what is the control flow of django rest framework
Asked Answered
E

2

13

I am developing an api for a webapp. I was initially using tastypie and switched to django-rest-framework (drf). Drf seems very easy to me. What I intend to do is to create nested user profile object. My models are as below

from django.db import models
from django.contrib.auth.models import User

class nestedmodel(models.Model):
    info = models.CharField(null=True, blank=True, max_length=100)


class UserProfile(models.Model):
    add_info = models.CharField(null=True, blank=True, max_length=100)
    user = models.OneToOneField(User)
    nst = models.ForeignKey(nestedmodel)

I have other models that have Foreignkey Relation. My Serializers are as below

from django.contrib.auth.models import User, Group
from rest_framework import serializers
from quickstart.models import UserProfile, nestedmodel


class NestedSerializer(serializers.HyperlinkedModelSerializer):

    class Meta:
        model = nestedmodel
        fields = ('info', )

class UserSerializer(serializers.HyperlinkedModelSerializer):

    class Meta:
        model = User
        fields = ('url', 'username', 'email', 'groups')


class GroupSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Group
        fields = ('url', 'name')

class UserProfileSerializer(serializers.HyperlinkedModelSerializer):
    user = UserSerializer()
    nst = NestedSerializer()
    class Meta:
        model = UserProfile
        user = UserSerializer(many=True)
        nested = NestedSerializer(many=True)
        fields = ('nst', 'user')

I can override methods like create(self, validated_data): without any issues. But What I want to know is to which method should the response returned by create() goes, or in other words Which method calls create(). In tastypie Resources.py is the file to override to implement custom methods. And Resources.py contains the order in which methods are being called. Which is the file in drf that serves the same purpose and illustrates the control flow like Resources.py in tastypie?.

Ellie answered 5/8, 2015 at 6:12 Comment(2)
Not sure if I understand your question, but isn't the result of create a Response object which contains the newly created object and is usually returned to the viewer?Zandrazandt
oh..yes. I will edit question.Ellie
F
43

So the flow goes something like:

  1. Viewset's create() method which is implemented in CreateModelMixin
  2. That creates serializer and validates it. Once valid, it uses viewset's perform_create()
  3. That calls serializer's save() method
  4. That then in turn calls serializer's either create() or update() depending if instance was passed to serializer (which it was not in step 1)
  5. create() or update() then create/update instance which is then saved on serializer.instance
  6. Viewset then returns response with data coming from serializer.data
  7. serializer.data is actually a property on serializer which is responsible for serializing the instance to a dict
  8. To serialize data, to_representation() is used.
  9. Then response data (Python dict) is rendered to a output format via renderers which could be json, xml, etc

And Resources.py contains the order in which methods are being called. Which is the file in drf that serves the same purpose and illustrates the control flow like Resources.py in tastypie?.

Guess that would be a combination of files. Its probably better to think in terms of classes/concepts you are touching since in DRF you can inherit from multiple things for create your classes. So the thing which glues everything together are viewsets. Then there are various viewset mixins which actually glue the viewset to the serializer and different CRUD operations.

Finder answered 5/8, 2015 at 12:59 Comment(5)
Thanks for the reply. After save(), what method is called to return json response? Or is it written in save() itself?Ellie
Sorry for the delay. Control flow greatly depend on the class that is being inherited. Anyway I could not find out a way to get an object if it exists else create a new one. I tried overriding save() and create() methods of HyperLinkedModelSerializer as well as Modelserializer. Anyway, control is not passed to both methods. I think this field must be unique if an object exists and that object serves as a non-nullable field, is generated at validation stage. But its still unclear how is it made at validation since django generates that error at the time of object creation.Ellie
update_or_create is not really applicable to RESTful APIs. User either creates object via POST on *-list URL (e.g. /api/resource/) or uses PUT to update object on *-detail URL (e.g. /api/resource/<pk>/). Combining the two is not a very good idea. If you absolutely need that, then you should create a custom route for that...Finder
I've found Classy DRF an invaluable resource for understanding these lifecycle questionsHotchkiss
Can't believe this isn't included in the DRF doc site, this piece of info is so important and fundamental. Was very confused when I want to start changing something, but ended up bouncing between viewsets & serializer without clue. This answer helped a ton!Reasoning
E
1

I figured out second part of question myself. get/create object can be done by using custom code in overriden def create(self, request, *args, **kwargs): in views.py. Code is as pasted below. Once Again, for clarity this is views.py not serializers.py. Also json with posted values can be accessed from request.DATA

class NestedViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows Nested objects to be viewed or edited.
    """
    queryset = nestedmodel.objects.all()
    serializer_class = NestedSerializer
    def create(self, request, *args, **kwargs):
        info = request.DATA['info']
        user = User.objects.get(username=request.DATA['user']['username'])
        profile = UserProfile.objects.get(user=user)
        nst = nestedmodel.objects.create(info=info, user=user, profile=profile)
        serialized_obj = serializers.serialize('json', [ nst, ])
        json_serialized = json.loads(serialized_obj)
        data = json.dumps(json_serialized[0])
        return Response(data)

Thanks for the help @miki275 :)

Ellie answered 6/8, 2015 at 15:32 Comment(1)
fyi. your solutions does not really use any of the DRF tools like a serializerFinder

© 2022 - 2024 — McMap. All rights reserved.