Django Rest framework, how to include '__all__' fields and a related field in ModelSerializer ?

前端 未结 7 2057
Happy的楠姐
Happy的楠姐 2020-12-01 05:09

I have two models, one with M2M relation and a related name. I want to include all fields in the serializer and the related field.

models.py:

<
相关标签:
7条回答
  • 2020-12-01 05:39

    If you are trying to basically just add extra piece of information into the serialized object, you don't need to change the fields part at all. To add a field you do:

    class MySerializer(serializers.ModelSerializer):
       ...
       new_field = serializers.SerializerMethodField('new_field_method')
    
       def new_field_method(self, modelPointer_):
          return "MY VALUE"
    

    Then you can still use

    class Meta:
       fields = '__all__'
    
    0 讨论(0)
  • 2020-12-01 05:46

    Hi I could achieve the expected result by using Django's _meta API , which seems to be available since Django 1.11. So in my serializer I did:

    model = MyModel
    fields = [field.name for field in model._meta.fields]
    fields.append('any_other_field')
    

    In programming there's always many ways to achieve the same result, but this one above, has really worked for me.

    Cheers!

    0 讨论(0)
  • 2020-12-01 05:47

    The fields="__all__" option can work by specifying an additional field manually as per the following examples. This is by far the cleanest solution around for this issue.

    Nested Relationships

    http://www.django-rest-framework.org/api-guide/relations/#nested-relationships

    class TrackSerializer(serializers.ModelSerializer):
        class Meta:
            model = Track
            fields = '__all__'
    
    class AlbumSerializer(serializers.ModelSerializer):
        tracks = TrackSerializer(many=True, read_only=True)
    
        class Meta:
            model = Album
            fields = '__all__'
    

    I would assume this would work for any of the other related field options listed on the same page: http://www.django-rest-framework.org/api-guide/relations/#serializer-relations

    Reverse relation example

    class TrackSerializer(serializers.ModelSerializer):
        album = AlbumSerializer(source='album_id')
    
        class Meta:
            model = Track
            fields = '__all__'
    

    Note: Created using Django Rest Framework version 3.6.2, subject to change. Please add a comment if any future changes break any examples posted above.

    0 讨论(0)
  • 2020-12-01 05:47

    to include all the fields and the other fields defined in your serializer you can just say exclude = ()

    class ToppingSerializer(serializers.HyperlinkedModelSerializer):
       pizzas = '<>' #the extra attribute value
        class Meta:
            model = Topping
            exclude = ()
    

    This will list all the field values with the extra argument pizzas

    0 讨论(0)
  • 2020-12-01 05:51

    I just checked the source code of Django Rest Framework. The behaviour you want seems not to be supported in the Framework.

    The fields option must be a list, a tuple or the text __all__.

    Here is a snippet of the relevant source code:

        ALL_FIELDS = '__all__'
        if fields and fields != ALL_FIELDS and not isinstance(fields, (list, tuple)):
            raise TypeError(
                'The `fields` option must be a list or tuple or "__all__". '
                'Got %s.' % type(fields).__name__
            )
    

    You cannot add 'all' additionally to the tuple or list with fields...

    0 讨论(0)
  • 2020-12-01 06:00

    Like @DanEEStart said, DjangoRestFramework don't have a simple way to extend the 'all' value for fields, because the get_field_names methods seems to be designed to work that way.

    But fortunately you can override this method to allow a simple way to include all fields and relations without enumerate a tons of fields.

    I override this method like this:

    class ToppingSerializer(serializers.ModelSerializer):
    
        class Meta:
            model = Topping
            fields = '__all__'
            extra_fields = ['pizzas']
    
        def get_field_names(self, declared_fields, info):
            expanded_fields = super(ToppingSerializer, self).get_field_names(declared_fields, info)
    
            if getattr(self.Meta, 'extra_fields', None):
                return expanded_fields + self.Meta.extra_fields
            else:
                return expanded_fields
    

    Note that this method only change the behaviour of this serializer, and the extra_fields attribute only works on this serializer class.

    If you have a tons of serializer like this, you can create a intermediate class to include this get_fields_names method in one place and reuse'em many times. Some like this:

    class CustomSerializer(serializers.HyperlinkedModelSerializer):
    
        def get_field_names(self, declared_fields, info):
            expanded_fields = super(CustomSerializer, self).get_field_names(declared_fields, info)
    
            if getattr(self.Meta, 'extra_fields', None):
                return expanded_fields + self.Meta.extra_fields
            else:
                return expanded_fields
    
    
    class ToppingSerializer(CustomSerializer):
    
        class Meta:
            model = Topping
            fields = '__all__'
            extra_fields = ['pizzas']
    
    class AnotherSerializer(CustomSerializer):
    
        class Meta:
            model = Post
            fields = '__all__'
            extra_fields = ['comments']
    
    0 讨论(0)
提交回复
热议问题