如何在django rest框架中将绝对url字段放在序列化器模型中?

时间:2014-02-20 04:19:38

标签: django django-rest-framework

我有一个这样的模型:

class GiveAbsolute(serializers.Field):
    def to_native(self,value): 
         # this where it give an error (self doesn't have request)
         # what i want it to give full url 
         # like: http://www.blabla.com/othermodel/1
         return reverse('link_to_othermodel',
                         args=[value],
                         request=self.request)

class SomethingSerializer(serializers.ModelSerializer):
    # field with foreign key
    othermodel = GiveAbsolute(source="othermodel.id")
    class Meta:
        model=Something
        fields("fields1","othermodel")

有没有办法实现这个目标? 感谢

3 个答案:

答案 0 :(得分:8)

来自source

请求对象是上下文字典的条目。即

request = self.context.get('request')

在你的情况下,只需:

self.request = self.context.get('request')

然后构建网址

self.request.build_absolute_uri(reverse('some_url_name'))

答案 1 :(得分:3)

DRF中唯一可以访问请求对象的是视图,因此您需要弄清楚如何将请求从视图传递到序列化程序,例如在通用ListView中,您可以使用get_serializer

然后,当您已经在序列化程序中使用它时,可以使用self.parent(父序列化程序)从字段本身捕获它:

class GiveAbsolute(serializers.Field):
    def to_native(self,value):
        return reverse('link_to_othermodel',
                     args=[value],
                     request=self.parent.request)


class SomethingSerializer(serializers.ModelSerializer):
    # field with foreign key
    othermodel = GiveAbsolute(source="othermodel.id")
    class Meta:
        model=Something
        fields=("fields1","othermodel")

    def __init__(self, *args, **kwargs):
        self.request = kwargs.pop('request', None)
        super(SomethingSerializer, self).__init__(*args, **kwargs)


class SomethingView(generics.ListAPIView):
    model = Something
    serializer_class = SomethingSerializer

    def get_serializer(self, instance=None, data=None,
                   files=None, many=False, partial=False):

        serializer_class = self.get_serializer_class()
        context = self.get_serializer_context()
        return serializer_class(instance, data=data, files=files, many=many,
                                partial=partial, context=context, request=self.request)

答案 2 :(得分:3)

基于mariodev的答案,这里是模型的可重用解决方案;我使用它来提供django模型上的服务URL(请参阅它们作为修改)。

可重复使用的组件

serializers.py

class RequestAwareSerializer(serializers.ModelSerializer):
    """
    A serializer which fields can access the request object.
    """
    def __init__(self, *args, **kwargs):
        self.request = kwargs.pop('request', None)
        super(RequestAwareSerializer, self).__init__(*args, **kwargs)

class APIMethodField(serializers.Field):
    """ To get the absolute URL of a method accessible via the API
    """
    def __init__(self, url_action_name, *args, **kwargs):
        self._url_name = url_action_name
        super(APIMethodField, self).__init__(source='*', *args, **kwargs)

    def to_native(self, obj):
        """
        @param objid the ID of the object
        @param method_url_name, the name of the url, as in urls.py
        """
        return reverse_lazy(self._url_name, args=[obj.id],


                   request=self.parent.request)

views.py

class ChattyModelViewSet(ModelViewSet):
    """ ModelViewSet which informs the serializer about the request

    (abstract)
    """
    def get_serializer(self, instance=None, data=None,
                   files=None, many=False, partial=False):

        serializer_class = self.get_serializer_class()
        context = self.get_serializer_context()
        return serializer_class(instance, data=data, files=files, many=many,
                                partial=partial, context=context,
                                request=self.request)

使用示例

urls.py

url(r'^v1/maildomain/(?P<maildomain_id>\d+)/check/$',
    views.MailDomainDetail.as_view(), name='maildomain_dns_check')

serializers.py

class MailDomainSerializer(RequestAwareSerializer):
    checkdns_url = APIMethodField(url_action_name='maildomain_dns_check')

    class Meta:
        model = MailDomain()
        fields = ('name', 'checkdns_url')

views.py

class MailDomainView(ChattyModelViewSet):
    model = MailDomain
    serializer_class = MailDomainSerializer