1

Here's are examples I have:

models.py:

class Example(models.Model):
    title = models.CharField(...)
    description = models.CharField(...)

class Foo(models.Model):
    example = models.ManyToManyField(Example)

serializers.py:

class FooSerializer(serializers.ModelSerializer):
    class Meta:
        model = Foo
        fields = '__all__'
        depth = 1

views.py:

...
serialized_data = [FooSerializer(foo).data for foo in Foo.objects.all().get]

In output, I receive only Example's IDs, but is there any way I could get title and description fields also (details of m2mfield)? As I understand, Foo.objects.all().get simply doesn't contain this data, but maybe I could somehow get it and use it? I could also rebuild models if needed, but currently I use m2mf because of needs to contain multiple objects as related to this model data.

update

models.py:

class Event(models.Model):
    ts = models.BigIntegerField(editable=False)

class Foo(Event):
    user = models.ForeignKey(User, ...)
    example = *...(remains to be the same)*
    foos = models.ForeignKey('self', **somemore** null=True)

serializers.py:

class EventSerializer(serializers.ModelSerializer):

    class Meta:
        model = Event
        fields = '__all__'

    def to_representation(self, instance):
        result = {'ts': instance.ts}
        if isinstance(instance, Foo):
            result['foo'] = FooSerializer(instance).data
        return result

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('id', 'username')

class FooSerializer(serializers.ModelSerializer):
   # user = UserSerializer(read_only=True) # with this I have an error: Got AttributeError when attempting to get a value for field 'username' on #serializer 'UserSerializer'

    class Meta:
        model = Foo
        fields = '__all__'
        depth = 1
Chickenfresh
  • 365
  • 5
  • 15

2 Answers2

2

You could use depth attribute to achieve desired output.

The default ModelSerializer uses primary keys for relationships, but you can also easily generate nested representations using the depth option.The depth option should be set to an integer value that indicates the depth of relationships that should be traversed before reverting to a flat representation.

class FooSerializer(serializers.ModelSerializer):
    class Meta:
        model = Foo
        fields = '__all__'
        depth = 1



Apart from the answer, I would like to change your views.py code, cause it seems like very bad :(. Do it on DRF Way as

serialized_data = FooSerializer(Foo.objects.all(), many=True).data<br>

Example View

from rest_framework.viewsets import ModelViewSet


class FooViewset(ModelViewSet):
    serializer_class = FooSerializer
    queryset = Foo.objects.all()


UPDATE-1

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        exclude = ('password',) # add fields that are need to be excluded 


class FooSerializer(serializers.ModelSerializer):
    user = UserSerializer()

    class Meta:
        model = Foo
        fields = '__all__'
        depth = 1

depth = 1 will serializer all fields in the model, (It's same as setting the fields=='__all__' in Meta class of serializer)


UPDATE-2

class FooSerializer(serializers.ModelSerializer):
    user = UserSerializer()

    class Meta:
        model = Foo
        fields = '__all__'
        depth = 1

    def to_representation(self, instance):
        real_data = super().to_representation(instance).copy()
        # DO YOUR EXTRA CHECKS
        child = UserSerializer(instance.child_foo).data
        if child:
            real_data.update({"child_data": child})
        # After your checks, add it to "real_data"
        return real_data

and I assumed I have a Foo model as

class Foo(models.Model):
    example = models.ManyToManyField(Example)
    user = models.ForeignKey(User)
    child_foo = models.ForeignKey('self', null=True, blank=True)
JPG
  • 82,442
  • 19
  • 127
  • 206
  • I have User's model ForeignKey in Foo and by adding depth it shows me password and other fields. And at some point I can't serialize users model because it says `AttributeError: Got AttributeError when attempting to get a value for field 'username' on serializer 'UserSerializer'` Same happens for manytomanyfields in model :( – Chickenfresh Jul 13 '18 at 12:12
  • 1
    If you wish to **exclude** some fields, you have to define a separate serializer, That is a **nested serializer** – JPG Jul 13 '18 at 12:17
  • 1
    If you update your question with **Actual Code** and **relevant relationship**, I could help you more, That is, user model/abstract user model, userserailzer l etc – JPG Jul 13 '18 at 12:21
  • My user is inherited from abstract user model, theres nothing special. It contains pwd, username and id. And it would be enough if I had shown only id and username. **Updated topic, hope it helps** – Chickenfresh Jul 13 '18 at 12:53
  • In fact, I just do not understand why, by adding depth, I see much more data than those with which a serializer can work – Chickenfresh Jul 13 '18 at 12:55
  • Can you also help with using https://stackoverflow.com/a/29651543/9048369 solution in `to_representation` at `EventSerializer`? I have recursive field but `RecursiveField().to_representation(instance.recursive)` says `TypeError: NoneType takes no arguments` at line `serializer = serializer_class(value, many=self._recurse_many, context=self.context)` – Chickenfresh Jul 13 '18 at 14:09
  • 1
    I don't understand your requirement. Which field did you make as `self-referencing FK`, (in which model)? – JPG Jul 13 '18 at 14:28
  • in `Foo` I've added `foos = models.ForeignKey('self', **somemore** null=True)` – Chickenfresh Jul 13 '18 at 14:31
  • 1
    You don't want to override `to_representaon()` or anything. Just use `depth=2` instead of `depth=1` ;) – JPG Jul 13 '18 at 15:04
  • Yes but by overriding to_representation() I can filter null fields and use other logic – Chickenfresh Jul 13 '18 at 22:30
1

In your serializer add depth = 1. Example where 'users' is the related field:

FooSerializer(serializers.ModelSerializer):
    class Meta:
        model = Foo
        fields = ('id', 'account_name', 'users', 'created')
        depth = 1
Taylor
  • 1,223
  • 1
  • 15
  • 30