简体   繁体   中英

Django Rest Serializer get data related through Foreign Keys

I have the following model skeletons:

class A(models.Model):
    post_id = models.ForeignKey('D')
    user_id = models.ForeignKey('B')

class B(AbstractBaseUser):
    email = models.EmailField(unique=True)
    username = models.CharField(max_length=20, unique=True)    
    first_name = models.CharField(max_length=40)
    last_name = models.CharField(max_length=40)
    # `resource_id`
    profile_photo = models.ForeignKey('C', null=True)

class C(models.Model):
    user_id = models.ForeignKey('B')
    name = models.CharField(max_length=60)

I want to write a serializer for A which should return name from model C, which is related to B.

The relation here is like A->B->C Now using A's serializer I want data to be fetched from C

I want to access C via A ie get profile_photo from B and the get the name of profile_photo from C

I scrolled through RelatedFields as given here Django Rest relations but am not able to achieve what I want.

Is their any way I can achieve it.

Also there are a lot of fields other than mentioned in the model skeleton and I do not want to fetch those.

EDIT : The final result I need is the all the user_id for a particular post_id from A with the name from model C

You can do this with a ModelSerializer :

Note: I will asumme that 'posts.Post' is model C

class CsSerializer(serializers.ModelSerializer):

    class Meta:
        model = C
        fields = ('name')


class AsSerializer(serializers.ModelSerializer):

    post_id = CsSerializer()

    class Meta:
        model = A
        # exclude = ('field_you_dont_want_1', 'field_you_dont_want_2')
        # fields = ('field_you_want_1', 'field_you_want_2')

Note that in CsSerializer you can return any field you want from model C in this case I'm just returning a name .

If you just need a string, you could use StringRelatedField

class AsSerializer(serializers.ModelSerializer):
    post_id = serializers.StringRelatedField(many=True)

    class Meta:
        model = A

This StringRelatedField will return what C models return in __unicode__ method ( __str__ method if python 3.x).

EDIT

Now, from your comment, I know that 'posts.Post' is not C model. So you could use SerializerMethodField :

class AsSerializer(serializers.ModelSerializer):
    c_name = serializers.SerializerMethodField()

    def get_c_name(self, obj):
        return obj.user_id.c_set.values('name')  # this will return a list of dicts with B's related C objects.

    class Meta:
        model = A

EDIT

You can always define class methods in your models:

class B(AbstractBaseUser):
    email = models.EmailField(unique=True)
    username = models.CharField(max_length=20, unique=True)    
    first_name = models.CharField(max_length=40)
    last_name = models.CharField(max_length=40)
    # `resource_id`
    profile_photo = models.ForeignKey('C', null=True)

    def get_profile_photo(self):
        return self.profile_photo.name  # This will return 'C' related object's name

So when you have an A's objects:

a_object.user_id.get_profile_photo()

Or if you have an B's object:

b_object.get_profile_photo()

EDIT

You can define a new Serializer for C class:

class CsSerializer(serializers.Serializer):

    class Meta:
        model = C

Then in your AsSerializer

class AsSerializer(serializers.ModelSerializer):
    c_name = serializers.SerializerMethodField()

    def get_c_name(self, obj):
        qs = obj.user_id.c_set.all()
        qs_serialized = CsSerializer(qs, many=True)
        return qs_serialized.data

    class Meta:
        model = A

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM