Django Rest框架、HyperlinkedModelSerializer、ModelViewSet和可写的GenericForeignKeys:如何?

Django Rest框架、HyperlinkedModelSerializer、ModelViewSet和可写的GenericForeignKeys:如何?,django,django-rest-framework,Django,Django Rest Framework,我有一个模型FinancialTransaction,它具有典型的内容类型,对象id,和内容对象字段,用于设置与我的任何其他模型的通用关系 我已经找到了如何序列化此关系以便阅读: class FinancialTransactionSerializer(serializers.HyperlinkedModelSerializer): content_object = serializers.SerializerMethodField('get_content_obj_url')

我有一个模型
FinancialTransaction
,它具有典型的
内容类型
对象id
,和
内容对象
字段,用于设置与我的任何其他模型的通用关系

我已经找到了如何序列化此关系以便阅读:

class FinancialTransactionSerializer(serializers.HyperlinkedModelSerializer):
    content_object = serializers.SerializerMethodField('get_content_obj_url')

    def get_content_obj_url(self, obj):
        obj = obj.content_object

        view_name = obj._meta.object_name.lower() + "-detail"
        s = serializers.HyperlinkedIdentityField(source=obj, view_name=view_name)
        s.initialize(self, None)
        return s.field_to_native(obj, None)

    class Meta:
        model = FinancialTransaction
        fields = ('id', 'value', 'date', 'memo', 'banking_account', 'content_object')
视图集:

class FinancialTransactionViewSet(viewsets.ModelViewSet):
    model = FinancialTransaction
    serializer_class = FinancialTransactionSerializer
当我在视图上执行GET时,这将为序列化表示创建一个指向相关对象的超链接

然而,我有点纠结于如何制作它,这样我就可以发布一个新的金融交易和一个已经存在的相关对象

理想情况下,它会像普通的外键一样工作,在这里我可以发布如下内容:

{"value": "200.00",
 "date": "2014-10-10",
 "memo": "repairs",
 "banking_account": "http://domain.com/api/banking_account/134/",
 "content_object": "http://domain.com/api/property/432/"
}

您可以在此文档中阅读更多内容:,如果您需要为您的
POST
请求指定路由,请参阅他们的代码示例:

from django.contrib.auth.models import User
from rest_framework import status
from rest_framework import viewsets
# See these imports
from rest_framework.decorators import detail_route, list_route
from rest_framework.response import Response
from myapp.serializers import UserSerializer, PasswordSerializer

class UserViewSet(viewsets.ModelViewSet):
    """
    A viewset that provides the standard actions
    """
    queryset = User.objects.all()
    serializer_class = UserSerializer

    # just place your logical def with the existing decorator, like so:
    @detail_route(methods=['post'])
    def set_password(self, request, pk=None):
        user = self.get_object()
        serializer = PasswordSerializer(data=request.DATA)
        if serializer.is_valid():
            user.set_password(serializer.data['password'])
            user.save()
            return Response({'status': 'password set'})
        else:
            return Response(serializer.errors,
                            status=status.HTTP_400_BAD_REQUEST)

我希望这有帮助。

好的,回答我自己的问题

我在自己的序列化程序中重写了
restore\u字段
,如下所示:

class FinancialTransactionSerializer(serializers.HyperlinkedModelSerializer):
    content_object = serializers.SerializerMethodField('get_content_obj_url')

    def get_content_obj_url(self, obj):
        obj = obj.content_object

        view_name = get_view_name(obj)
        s = serializers.HyperlinkedIdentityField(source=obj, view_name=view_name)
        s.initialize(self, None)
        return s.field_to_native(obj, None)

    def restore_fields(self, data, files):
        content_object = None

        if 'content_object' in data:
            request = self.context.get('request')  
            content_object = get_object_from_url(request.DATA['content_object'])

        attrs = super(FinancialTransactionSerializer, self).restore_fields(data, files)
        if content_object:
            attrs['content_object'] = content_object
        return attrs

    class Meta:
        model = FinancialTransaction
        fields = ('id', 'value', 'date', 'memo', 'banking_account', 'content_object')

def get_model_from_url(url: str):
    return resolve(urlparse(url).path).func.cls.model

def get_object_from_url(url: str):
    model = get_model_from_url(url)
    pk = resolve(urlparse(url).path).kwargs.get('pk')
    if not pk:
        return None
    return model.objects.get(pk=pk)
此设置序列化对象,以便
content\u object
字段包含到相关对象的超链接,并且当使用此序列化程序发布到视图时,数据包括
content\u object
键,我们获取相关对象并传递它

restore\u字段
返回的属性用于
restore\u对象
方法,由于我们查找了内容对象并将其放入属性中,
restore\u对象
将FinancialTransaction对象上的
content\u对象
属性设置为检索到的对象,然后Django处理其余的内容


到目前为止,我能看到的唯一缺点是,这并没有将
content\u object
字段添加到可浏览的API中……但我不确定这将如何工作,因为相关对象通常在select中提供,我想我们不希望数据库中的每个对象都填充select,这让我更深入地研究文档。感觉这个功能更多地属于序列化程序,而不是视图,所以我。