Building a Reusable Core Package for Your Django REST Framework Expense Tracker — Part 4

denisa_dev
Django Unleashed
Published in
2 min readJul 24, 2024
Expense Tracker — Core Package

If you enjoyed this, buy me a coffee! ☕💖

Core Package Structure

Let’s start by setting up the core structure for our Expense Tracker package. This package will include essential components such as paginators, API views, constants, exceptions, and serializers, setting the foundation for a robust and scalable application.

core/
├── filters/
│ ├── category_filter.py
│ └── expense_filter.py
├── serializers/
│ ├── balance_serializer.py
│ ├── category_serializer.py
│ ├── expense_serializer.py
│ └── user_serializer.py
├── views/
│ ├── balance_views.py
│ ├── category_views.py
│ ├── expense_views.py
│ ├── export_expense_views.py
│ ├── raw_query_views.py
│ └── user_views.py
├── apis_views.py
├── cons.py
├── exception.py
├── paginators.py
└── urls.py

Constants (cons.py)

# cons.py
DATA = 'data'
ERRORS = 'errors'
MESSAGE = 'message'

Exceptions (exception.py)

# exception.py
class InvalidData(Exception):

def __init__(self, message):
self.message = message

def get_message(self):
return self.message

Paginators (paginators.py)

# paginators.py
from collections import OrderedDict
from rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response

class ExpenseTrackerPaginator(PageNumberPagination):
template = None
page_query_param = 'page'
page_size_query_param = 'page_size'

def get_paginated_response(self, data):
return Response(OrderedDict({
'data': data,
'pagination': {
'count': self.page.paginator.count,
'next': self.get_next_link(),
'previous': self.get_previous_link()
}
}))

API Views (apis_views.py)

import json

from django.core.exceptions import ObjectDoesNotExist
from django.db import IntegrityError
from django.db.transaction import atomic
from django.http import Http404
from rest_framework import status
from rest_framework.exceptions import ValidationError
from rest_framework.generics import CreateAPIView, ListAPIView, RetrieveUpdateDestroyAPIView
from rest_framework.response import Response

from core.cons import DATA, ERRORS, MESSAGE
from core.exception import InvalidData


class BaseExpenseTrackerAPIView:
queryset = None
serializer_class = None
read_serializer_class = None
write_serializer_class = None
filter_serializer_class = None
filter_map = {}

def get_serializer_class(self):
if self.request.method in ['GET', 'HEAD']:
return self.read_serializer_class or self.serializer_class
elif self.request.method in ['POST', 'PUT', 'PATCH']:
return self.write_serializer_class or self.serializer_class
return self.serializer_class

@staticmethod
def handle_exception(exception):
response_data = {
ERRORS: str(exception),
MESSAGE: 'Server Error'
}
if isinstance(exception, ValidationError):
response_data.update({
ERRORS: exception.get_full_details()
})
response_status = status.HTTP_400_BAD_REQUEST
elif isinstance(exception, ObjectDoesNotExist):
response_data.update({
MESSAGE: 'Object does not exist',
})
response_status = status.HTTP_404_NOT_FOUND
elif isinstance(exception, IntegrityError):
response_data.update({
MESSAGE: 'Error in database',
})
response_status = status.HTTP_500_INTERNAL_SERVER_ERROR
elif isinstance(exception, InvalidData):
response_data.update({
MESSAGE: exception.get_message(),
})
response_status = status.HTTP_400_BAD_REQUEST
else:
response_status = status.HTTP_500_INTERNAL_SERVER_ERROR

return response_data, response_status

class ExpenseTrackerListAPIView(BaseExpenseTrackerAPIView, ListAPIView):
pass

class ExpenseTrackerCreateAPIView(BaseExpenseTrackerAPIView, CreateAPIView):
pass


class ExpenseTrackerListCreateAPIView(ExpenseTrackerListAPIView, ExpenseTrackerCreateAPIView):
pass

class ExpenseTrackerRetrieveUpdateDestroyAPIView(BaseExpenseTrackerAPIView, RetrieveUpdateDestroyAPIView):
pass

Conclusion

By building a reusable core package, we have laid the groundwork for a scalable and secure Expense Tracker application. This modular approach ensures that we can easily extend and maintain the application as it grows. Stay tuned for the next part of this series, where we will dive deeper into the Expense Tracker features and functionalities.

If you found this article helpful, don’t forget to share it with your friends and colleagues! 📤 Feel free to leave a comment below with your thoughts or questions 💬, and give it a like if you enjoyed it! 👍😊

If you enjoyed this, consider buying me a Coffee! ☕💖

--

--

denisa_dev
Django Unleashed

🎯 Experienced and Passionate Software Engineer | Python | Django REST | Angular | https://ko-fi.com/codewiz_dev