Django Rest Framework 的控制流是什么?

13

我正在开发一个Web应用程序的API。一开始我使用了Tastypie,后来切换到Django Rest Framework (DRF)。对我来说,DRF似乎非常容易上手。我的意图是创建嵌套用户配置文件对象。我的模型如下:

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)

我有其他具有外键关系的模型。我的序列化程序如下:

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')

我可以轻松地覆盖像create(self, validated_data):这样的方法。但我想知道返回给create()的响应应该发送到哪个方法中,或者换句话说,哪个方法调用了create()。在tastypie中,Resources.py是要覆盖以实现自定义方法的文件。而且,Resources.py包含被调用方法的顺序。在drf中,有哪个文件可以实现与tastypie的Resources.py类似的功能并说明控制流程?


我不确定我是否理解了你的问题,但是create的结果不是包含新创建对象的Response对象吗?通常这个对象会返回给查看者。 - pingul
哦..是的。我会编辑问题。 - cutteeth
2个回答

42
所以流程大致如下:
  1. CreateModelMixin 中实现的 Viewset 的 create() 方法
  2. 该方法创建序列化器并验证它。一旦验证通过,它就会使用 Viewset 的 perform_create() 方法
  3. 该方法调用序列化器的 save() 方法
  4. 然后,根据是否将实例传递给序列化器(在第一步中没有传递),它将调用序列化器的 create()update() 方法来创建/更新实例
  5. create()update() 然后创建/更新实例,该实例随后保存在 serializer.instance
  6. Viewset 然后返回响应,数据来自于 serializer.data
  7. serializer.data 实际上是序列化器的一个属性,负责将实例序列化为字典
  8. 为了序列化数据,使用 to_representation() 方法
  9. 然后,响应数据(Python 字典)通过 renderers 渲染为输出格式,例如 json、xml 等
「Resources.py」包含方法被调用的顺序。在DRF中,与tastypie中的「Resources.py」具有相同目的且说明控制流程的文件是哪一个呢?
我猜那应该是多个文件的组合。最好考虑你所涉及的类/概念,因为在DRF中,你可以从多个地方继承来创建自己的类。所以把一切粘合在一起的是viewsets。然后有各种viewset mixin,它们实际上将viewset与serializer和不同的CRUD操作粘合在一起。

谢谢回复。在save()之后,调用哪个方法来返回json响应?还是它写在save()本身中? - cutteeth
抱歉耽搁了。控制流程非常依赖于被继承的类。无论如何,我找不到一种方法来获取对象(如果存在)否则创建一个新对象。我尝试重写HyperLinkedModelSerializerModelserializersave()create()方法,但是控制权都没有传递给这两个方法。我认为,如果对象已经存在并且该对象作为非空字段,则在验证阶段生成“此字段必须唯一”的错误。但是仍然不清楚它是如何在验证时生成的,因为Django在对象创建时生成该错误。 - cutteeth
update_or_create 对于RESTful API并不适用。用户可以通过在*-list URL上进行POST(例如, /api/resource/)来创建对象,或者使用PUT*-detail URL(例如, /api/resource/<pk>/)上更新对象。将两者结合起来并不是一个很好的主意。如果您绝对需要这样做,那么您应该为此创建一个自定义路由... - miki725
我发现 Classy DRF 是理解这些生命周期问题的宝贵资源。 - Ben
1
难以置信这个重要而基础的信息没有包含在DRF文档站点中。当我想要开始更改某些内容时,我非常困惑,最终在视图集和序列化器之间反复跳转却毫无头绪。这个答案帮了我很大的忙! - Shawn

1
我自己解决了问题的第二部分。可以通过在覆盖views.py中的def create(self, request, *args, **kwargs):中使用自定义代码来完成获取/创建对象。代码如下所示。再次强调,为了清晰起见,这是views.py而不是serializers.py。同时,可以从request.DATA中访问带有发布值的json。
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)

感谢 @miki275 的帮助 :)

你的解决方案并没有真正使用DRF工具,比如序列化器。 - miki725

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接