Django rest framework where to write complex logic in serializer.py or views.py?
Asked Answered
C

4

15

I am new to Django Rest Framework. Using serializer and views a simple CRUD is easy. When the logics increase, it is quite confusing where to write logics in serializer or views.
Some developers do prefer "Thick serializer and thin views" and some developers "Thick views and thin serializer".
Maybe this is not a big issue and I think it is up to the developer whether to write more on views or serializer, but as a newbie what will be your suggestion to follow? Should I write more on views or serializer?
There are many answers on Django View Template but can not find a satisfying answer for Django Rest Framework.
Thoughts of experienced developers will be highly appreciated. Thank you.

Cockade answered 7/8, 2019 at 5:49 Comment(1)
I would rather choose serializer instead of view to put my business logic.Pharyngoscope
A
23

Personally I prefer to have the business logic separated from both view and serializer. I usually create a new class with the business logic which can be used in both serializer and view based on necessity. Basically I treat it as a service. Reason for that is:

  1. Makes the code cleaner(no thick and thin stuff).
  2. Writing tests for those business logic is easier.
  3. You can use that this business logic service in both view and serializer, depending on your need.
  4. while testing APIs, you can mock those buiness logic if needed.
  5. Reuse any logic in multiple places.

An example would be like this:

class BusinessLogicService(object):

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

    def do_some_logical_ops(self, data_required_one, data_required_two):
        # do processing
        return processed_data

Example usage in serializer:

class SomeSerializer(serializer.Serialize):
     ...
     def create(self, validated_data):
         business_logic_data = BusinessLogicService(self.request).do_some_logical_ops(**validated_data)
         return Model.objects.create(**business_logic_data)
Alanealanine answered 7/8, 2019 at 6:11 Comment(6)
From now on I will try to follow your suggestion, pretty clearly explained. What kind of logics will be best for views and what kind of logics for serializerCockade
it depends on your application design. In general, you can put validation related business logics and data manipulations in serializer. flow restrictions, permissions , external api call etc in views :)Alanealanine
You are awesome dude, how cleanly explained. Thank you. :)Cockade
BusinessLogicService(self.request) here serializer object has no attribute'request' What am I missing?Bucaramanga
You are not using generic views or you need to send the request object from view to serializer manuallyAlanealanine
It can get dirty soon if BusinessLogicService has to deal with more and more serializersPharyngoscope
P
7

I've asked a similar question about this before. Actually, it depends on what logic you are going to adapt. After doing further research, I have come up with some approaches. Here are my suggestions:

  1. If you want to add some logic before doing serializer validation, it is better to include that in your view (eg. override your views create method). An example to this case would be; your POST body does not contain a value that is needed by the serializer hence is not valid yet, so add that in your view's create function.
  2. If you are doing some custom authentication logic, such as parsing a custom token in your http header, do it in your view as well, because serializer has nothing to do with it. Moreover, you can create your own authentication decorator for that.
  3. If you want to add logic which is directly related to the representation of your data, such as an adaptation of a timestamp from UTC to some other, you can add in your serializer as it is directly related to your object representation. You can use SerializerMethodField etc. to do that.
Pennywise answered 7/8, 2019 at 5:57 Comment(3)
okay, got it and what if the same logic is applicable in both view and serializer, which one of them will you choose?Cockade
You can place them under wherever you want. Actually as in @ruddra's answer you can do that in a separate utils or helper class. This will also work. But I prefer adding view-related, or serializer-related logic inside views or serializers. I create separate classes when I have logic such as calling some other web endpoints etc.Pennywise
got it, your help is appreciated. Thank you.Cockade
F
3

I try to segregate it on the basis of requirements of the context. Like:

  • If I'm supposed to deal with the request object(like current user), I try to implement that in view.
  • If I need to deal with querying models to create a view I would switch to serializer.

It may also depend upon how I'm planning to maintain the code (If I have huge number of views in a single file, I will try to avoid implementing logical stuffs as much as possible).

Fincher answered 7/8, 2019 at 6:4 Comment(0)
S
0

This problem is an indictment of the entire framework.

  • We must use serializers to sanitize our inputs at the beginning of processing.
  • We must use serializers to enact persistence concerns at the end of processing.
  • We are supposed to be able to use views and view sets to perform non-serialization concerns, like business logic.
  • We are supposed to be able to benefit from ViewSets supplying conventional mappings between url routes and queryset CRUD operations, eliminating loads of redundant boilerplate code

But as it turns out, we can only do a couple of the above things at any one time, because it comes at the expense of the other things.

If you want to build business logic outside of basic serialization CRUD concerns, it has to be called FROM your serializer in an override. This is a complete misfire of separation of concerns, and I've seen the unfortunate sprawl that results in a codebase because of this very problem.

It seems the ideal choice is for business logic that is not related to serialization, to be in a third place, and invoked FROM the view/viewset. But we cannot do this unless we opt out of all the conventional, "for free" wiring between serializers and viewsets.

In other words, to separate concerns into coherent groupings, we have to rewrite all the inherited logic in GenericViewSet, to call serializer.is_valid(), THEN invoke our business logic, THEN call serializer.save().

What is the point of this framework if we have to warp our mentality so far as to believe that it's appropriate design to stuff business logic inside of serializers?

Spotty answered 28/6, 2024 at 18:55 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.