1

I am developing a small application that lists the customers of a store. I'm trying to retrieve the additional fields of the intermediate model because a contact can belong to several stores but depending on the store it is premium or not and if he is happy or not.

Here's the JSON response I'd like to get for a Store like /contacts/?store=my_store

[
    {
        "id": "UX",
        "first_name": "UX",
        "last_name": "UX",
        "email": null,
        "mobile": null,
        "happy": True,
        "premium": True
    },
    {
        "id": "AX",
        "first_name": "AX",
        "last_name": "AX",
        "email": null,
        "mobile": null,
        "happy": False,
        "premium": True
    }
]

here are my models:

class Store(BaseModel):
    id = models.CharField(primary_key=True, max_length=200)
    name = models.CharField(max_length=100)


class Contact(BaseModel):
    id = models.CharField(primary_key=True, max_length=200)
    first_name = models.CharField(max_length=100, null=True, blank=True)
    last_name = models.CharField(max_length=100, null=True, blank=True)
    email = models.CharField(max_length=100, null=True, blank=True)
    mobile = models.CharField(max_length=100, null=True, blank=True)
    stores = models.ManyToManyField(
        Store, through="MemberShip", through_fields=("contact", "store")
    )


class MemberShip(BaseModel):
    contact = models.ForeignKey(
        Contact, on_delete=models.CASCADE, related_name="contact_to_store"
    )
    store = models.ForeignKey(
        Store, on_delete=models.CASCADE, related_name="store_to_contact"
    )
    happy = models.BooleanField(default=True)
    premium = models.BooleanField(default=False)

and my serializers:

class MemberShipSerializer(serializers.ModelSerializer):
    class Meta:
        model = MemberShip
        fields = ("contact", "store", "happy", "premium")


class StoreSerializer(serializers.ModelSerializer):
    class Meta:
        model = Store
        fields = ("id", "name")


class ContactSerializer(serializers.ModelSerializer):
    infos = MemberShipSerializer(
        source="contact_to_store" many=True, read_only=True
    )

    class Meta:
        model = Contact
        fields = (
            "id", "first_name", "last_name", "email", "mobile", "infos"
        )

As you can see, I first tried to gather all the information of the intermediate model in a field before displaying happy and premium but, strangely enough, the infos field is returned with an empty array value. Python v 3.7 Django v 2.1 DRF v 3.9

2 Answers 2

1

You must provide data to MemberShipSerializer . You can use SerializerMethodField. Like that:

class ContactSerializer(serializers.ModelSerializer):
    infos = serializers.SerializerMethodField(read_only=True)

    class Meta:
        model = Contact
        fields = (
        "id", "first_name", "last_name", "email", "mobile", "infos"
        )

    def get_infos(self,obj:Contact):
        return MemberShipSerializer(obj.contact_to_store.all(),many=True).data
Sign up to request clarification or add additional context in comments.

3 Comments

Doesn't work the field infos is still an empty list "infos": []
Could you check whether any MemberShip records related with contact object is exist in your db?
It works the problem is that it returns ALL the stores to which the contact is affiliated while I'm trying to display only the additional fields of the store that is passed in parameter like contact/?store=my-store
0

I tried kamilyrb's solution here's what I changed:

class MemberShipSerializer(serializers.ModelSerializer):
    class Meta:
        model = MemberShip
        fields = ("contact", "store", "happy", "premium")


class StoreSerializer(serializers.ModelSerializer):
    class Meta:
        model = Store
        fields = ("id", "name")


class ContactSerializer(serializers.ModelSerializer):
    happy = serializers.SerializerMethodField(read_only=True)
    premium = serializers.SerializerMethodField(read_only=True)

    class Meta:
        model = Contact
        fields = (
            "id", "first_name", "last_name", "email", "mobile", "happy", "premium"
        )

    def get_premium(self, obj):
        return MemberShipSerializer(obj.contact_to_store.all(), many=True).data

    def get_happy(self, obj):
        return MemberShipSerializer(obj.contact_to_store.all(), many=True).data

This is what i have now:

[
    {
        "id": "UX",
        "first_name": "UX",
        "last_name": "UX",
        "email": "0",
        "mobile": null,
        "happy": [
            {
                "store": "my-store",
                "contact": "UX",
                "happy": true,
                "premium": false,
            },
            {
                "store": "my-store2",
                "contact": "UX",
                "happy": false,
                "premium": false,
            }
        ],
        "premium": [
            {
                "store": "my-store",
                "contact": "UX",
                "optin_sms": true,
                "happy": false,
                "premium": false
            }
        ]
    }
]

how can i get that ?

[
    {
        "id": "UX",
        "first_name": "UX",
        "last_name": "UX",
        "email": null,
        "mobile": null,
        "happy": True,
        "premium": True
    },
    {
        "id": "AX",
        "first_name": "AX",
        "last_name": "AX",
        "email": null,
        "mobile": null,
        "happy": False,
        "premium": True
    }
]

I also noticed that all the stores to which a contact is affiliated are shown but as I said before the url is called as follows contact/?store=my-store

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.