I am trying to create a backend with Django Rest Framework and am trying to determine where to place the business logic. Would it go in the views.py? I would like to create more complex services than just getting a list of objects or grabbing one specific object. Any guidance would be appreciated, thanks. I realize there is a discussion about the business logic in a generic Django project but I am asking specifically about the django rest framework.
-
1There is already a big discussion about this: http://stackoverflow.com/questions/12578908/separation-of-business-logic-and-data-access-in-django – Spencer May 12 '15 at 17:30
-
2Yeah I looked at that one but was hoping to ask specifically about the location within django rest framework – perp May 12 '15 at 17:49
-
Did you find a good Design Pattern for this one? Thanks – jhagege Aug 19 '15 at 06:51
3 Answers
It is more about design patterns rather than Django Rest Framework.
Here are some tips:
- Providing interfaces using REST should not involve any specific code related to data manipulation or business logic.
- Using an MVC approach does not mean that you shouldn't layer your application.
- You should be able to test your business logic without touching the UI at all.
- Some people may suggest putting business logic in models. But I do not agree with them, since Django models are different from domain models and business related tasks such as tax calculation.
- Before getting stuck in MVC, You could read more about The MVC implemented in MVC three-tier architecture
- I suggest having a business layer and related apps putting your business logic there.
Suppose that you have an online coffee shop & you'd like to provide a REST API for ordering coffees.
Here are my suggested code samples:
myapp/views.py:
def order(request, quantity=1):
# Process the order by calling the mapped method
order_id = CoffeeShopService.place_order(quantity)
return HttpResponse({'order_id': order_id, mimetype='application/json')
myapp/services.py:
class CoffeeShopService(object):
@staticmethod
def place_order(quantity):
# do the business logic here
return order_id

- 661
- 6
- 12
-
Thank you for the insight. But I have another issue by implementing your idea. I'm difficult to standardize my exception handling. As you know in DRF we have `ValidationError`. In viewsets has another exception also in lower lever such us in models has a lot of exception class. The problem is those error handling has different format in API response. – Adiyat Mubarak Jul 14 '18 at 12:16
-
2Exception handling in DRF is a different question which is possible by Custom exception handling. if you search you can find how to or you may ask a separate question – Saeed Jul 15 '18 at 18:33
-
I've started to code in `Python` with `Django` recently, before I've coded in `Java`/`Spring Boot`. I very agree with your point that declines putting logic inside the `models.py` making it even fatter. And the `services` module is the best place to make some business processes in my opinion. I just get it from `Spring Boot` experience – catscoolzhyk Dec 16 '20 at 15:50
It is a design patterns Questing in Rest Framework, I guess. Here is a Detailed Overview of how i use Layered Approach in my API build on Rest Framework!
It is a little more layered for the sake of Easy Maintenance and utilizes Design Patterns and GRASP Principal most importantly!
Layered Approach Package Level View
Further Classification:
Now an Example of How I go through Layers:
A Request is made to example.com/Customer/profile @project/urls.py
The Request is forwarded to the Respective URL's Layer (@app/urls/Customer_Url)
URL's Pass it to the Respective Viewset (@app/Viewsets/Customer_Viewsets/Customer_Signup.py)
It being a Post Request, (I assume for this Example) is Forwarded to Business Logic Layer (@app/BusinessLogicLayer/BLL.py)
The Business Logic Layer has an Abstract Implementation(Act as Interface of IBLL) and it forwards the request to respective method to check for all my Business Rules! (@app/BusinessLogicLayer/SUB_BLL/Customer/*)
The Request is then Forwarded to the Data Access Layer which stores the Data of User in Database. and So forth! (@app/DataAccessLayer/DAL.py)

- 958
- 9
- 19
-
2`Customer_Name is ""` -- this is plain wrong. And generally the code smells. You should use validation frameworks (for example Marshmallow). – warvariuc Aug 03 '18 at 07:55
-
1I am basically Setting an Empty String for Handling some of my Custom Things, This API is interacted by a Dozens of Devices! Also this Code is the Work of my Team Member so he better Justify it, My Main goal is to give the overview of Layered Archietecture. i would myself use if not Customer_Name than that :) – Syed Faizan Aug 03 '18 at 08:02
-
1@warvariuc I would really appreciate if you can pick Mistakes in the Archietecture Side as I myself is more focused on using this for a long term, so I would really love to fix my Errors in Archietecture. Most of All, Thanks Alot :) – Syed Faizan Aug 03 '18 at 08:03
-
1It's difficult to judge about architecture when camel case names are used, repetitive code, wrong low level idioms. Also there is too much info and screenshots instead of text. IMO. Also I see just code and explanations but no description of the design principles used in the code. – warvariuc Aug 03 '18 at 08:14
-
1@warvariuc Currently, I am studying Student with just 1 year completed in Software Engineering and have 3 more years to go through :). I support myself till this level :) and would like to learn and Grow more from your knowledge if we can communicate via Email or Skype? – Syed Faizan Aug 03 '18 at 08:17
-
-
This is Great Archietecture, It organizes Stuff. Love the Tier but do you have any idea on Onion Archietecture? – Ibtihaj Uddin Oct 17 '18 at 08:58
maybe this is a slightly eccentric way, but I think it's quite helpful to wrap the logic into the serializer by adding methods in it.
For example
serializer:
class OrderSerializer(serializers.ModelSerializer):
class Meta:
model = Order
fields = (
'id',
'total',
'discount',
)
def calculate_discount(self, whatever_params):
# calculate discount if you need... and return it
def calculate_tax(self, whatever_params):
# calculate tax amount if you need...and return it
def calculate_grand_total(self, whatever_params):
# calculate grand total if you need and return it
def create(self, validated_data):
# You can make an order by applying
# some logic in the calculation method.
# Maybe by adding a bit of the context
# you sent as parameters from view.

- 751
- 7
- 10
-
2Even if it possible to do it, I think putting logic into `serializer`s is not obvious and wrong. Since the main idea of serializers is simply to serialize and deserialize data and make some validation staff. It is incorrect in terms of `django` project architecture. – catscoolzhyk Dec 16 '20 at 15:44