DRF retriveapi view.

I have been working on a project, where the project has a Model called Competition and under each completion I have a model called Artwork ( in foreign key relationship). I am using DRF and the problem I am facing is each artwork has a field called approved ( boolean ) and I want to retrieve all the approved artwork under a competition detail view.

How can I filter that data on Competition retrieve API view. I could not find any good examples. Please help

Also, I have been thinking about making another API that will filter the artwork only based on the given competition id.

Please help me to find out the solution.

GET /api/v1/ongoing-competitions/
[
    {
        "id": "e1c0c058-1d8b-4e90-b2a6-6789cf897f08",
        "name": "Competition one",
        "description": "Competition one descriptions",
        "thumnail": "https://static.wixstatic.com/media/c84c64_e6218cad44794b949661b0d88097182e~mv2.jpg/v1/fill/w_383,h_283,al_c,q_80,usm_0.66_1.00_0.01/IAS%20Gallery_Original.webp",
        "created_at": "2020-07-22T12:46:53.938819Z",
        "ended": false,
        "artworks": [
            {
                "id": "b7916507-109d-41e2-b5b4-50c9fdc105c3",
                "title": "Hello",
                "medium": "Acrolic",
                "dimension": "32x33",
                "paid": false,
                "approved": true,
                "user": null,
                "position": 0,
                "created_at": "2020-07-22T14:23:24.047062Z",
                "artist": {
                    "id": "54efb6a3-a746-4c3c-bdd2-77e09bdd5bb7",
                    "full_name": "Manas Paul",
                    "email": "imanaspaul@gmail.com",
                    "artist_website": "https://manascode.com",
                    "artist_biography": "He is the best artist",
                    "artist_statement": "Manas paul is great..",
                    "created_at": "2020-07-22T14:21:48.134035Z"
                },
                "competition": {
                    "id": "e1c0c058-1d8b-4e90-b2a6-6789cf897f08",
                    "name": "Competition one",
                    "description": "Competition one descriptions",
                    "thumnail": "https://static.wixstatic.com/media/c84c64_e6218cad44794b949661b0d88097182e~mv2.jpg/v1/fill/w_383,h_283,al_c,q_80,usm_0.66_1.00_0.01/IAS%20Gallery_Original.webp",
                    "ended": false,
                    "created_at": "2020-07-22T12:46:53.938819Z"
                }
            },
            {
                "id": "f758d846-f446-4f1a-bd4c-ae9271e3a9ce",
                "title": "gdfg",
                "medium": "gfdg",
                "dimension": "gdfg",
                "paid": false,
                "approved": false,
                "user": null,
                "position": 1,
                "created_at": "2020-07-22T14:24:37.008208Z",
                "artist": {
                    "id": "54efb6a3-a746-4c3c-bdd2-77e09bdd5bb7",
                    "full_name": "Manas Paul",
                    "email": "imanaspaul@gmail.com",
                    "artist_website": "https://manascode.com",
                    "artist_biography": "He is the best artist",
                    "artist_statement": "Manas paul is great..",
                    "created_at": "2020-07-22T14:21:48.134035Z"
                },
                "competition": {
                    "id": "e1c0c058-1d8b-4e90-b2a6-6789cf897f08",
                    "name": "Competition one",
                    "description": "Competition one descriptions",
                    "thumnail": "https://static.wixstatic.com/media/c84c64_e6218cad44794b949661b0d88097182e~mv2.jpg/v1/fill/w_383,h_283,al_c,q_80,usm_0.66_1.00_0.01/IAS%20Gallery_Original.webp",
                    "ended": false,
                    "created_at": "2020-07-22T12:46:53.938819Z"
                }
            }
        ]
    }
]

Second way ( I thought )

GET /api/v1/get-artsworks/:competition-id

And filter the artwork and return the response. But in this case, I have to call two endpoint at the same time from the frontend. So I am getting confused about which one is the best way to implement.

It’s going to be a whole lot easier to give you specific advice if you post the view you want to modify for these functions.

1 Like

Here is the view

from rest_framework.generics import ListAPIView
from . serializers import AllCompetitionSerializer
from . models import Competition


class OngoingCompetitions(ListAPIView):
    serializer_class = AllCompetitionSerializer
    queryset = Competition.objects.filter(ended=False)

I just wanted to show only artworks which are approved under the competitions

Please post all the models you want included in your results, along with the AllCompetitonSerializer, and any other code involved with this specific process.

Here is the repo link I hope that will help you https://github.com/imanaspaul/art-studio

1 Like

Ok, so wanting to get this straight, please verify that my understanding is correct:

  • You want a list of all Competition
  • Within each Competition, you want all the Artwork objects with approved = True.

Then, you have a different question, where you want to:

  • Get a list of all Artwork for a specified Competition.

Is my understanding correct?

I’m by no means a DRF expert, but what I’ve found is that a Serializer class takes a queryset as the first parameter.

That implies to me that you could do something like this in AllCompetitionSerializer:

active_art = Artwork.objects.filter(approved=True)
artworks = ArtworkSerializer(active_art, many=True)
1 Like

But the response data structure will be something like this

"artworks": [
            {
                "id": "b7916507-109d-41e2-b5b4-50c9fdc105c3",
                "title": "Hello",
                "medium": "Acrolic",
                "dimension": "32x33",
                "paid": false,
                "approved": true,
                "user": null,
                "position": 0,
                "created_at": "2020-07-22T14:23:24.047062Z",
                "artist": {
                    "id": "54efb6a3-a746-4c3c-bdd2-77e09bdd5bb7",
                    "full_name": "Manas Paul",
                    "email": "imanaspaul@gmail.com",
                    "artist_website": "https://manascode.com",
                    "artist_biography": "He is the best artist",
                    "artist_statement": "Manas paul is great..",
                    "created_at": "2020-07-22T14:21:48.134035Z"
                },
                "competition": {
                    "id": "e1c0c058-1d8b-4e90-b2a6-6789cf897f08",
                    "name": "Competition one",
                    "description": "Competition one descriptions",
                    "thumnail": "https://static.wixstatic.com/media/c84c64_e6218cad44794b949661b0d88097182e~mv2.jpg/v1/fill/w_383,h_283,al_c,q_80,usm_0.66_1.00_0.01/IAS%20Gallery_Original.webp",
                    "ended": false,
                    "created_at": "2020-07-22T12:46:53.938819Z"
                }
            },
            {
                "id": "f758d846-f446-4f1a-bd4c-ae9271e3a9ce",
                "title": "gdfg",
                "medium": "gfdg",
                "dimension": "gdfg",
                "paid": false,
                "approved": false,
                "user": null,
                "position": 1,
                "created_at": "2020-07-22T14:24:37.008208Z",
                "artist": {
                    "id": "54efb6a3-a746-4c3c-bdd2-77e09bdd5bb7",
                    "full_name": "Manas Paul",
                    "email": "imanaspaul@gmail.com",
                    "artist_website": "https://manascode.com",
                    "artist_biography": "He is the best artist",
                    "artist_statement": "Manas paul is great..",
                    "created_at": "2020-07-22T14:21:48.134035Z"
                },
                "competition": {
                    "id": "e1c0c058-1d8b-4e90-b2a6-6789cf897f08",
                    "name": "Competition one",
                    "description": "Competition one descriptions",
                    "thumnail": "https://static.wixstatic.com/media/c84c64_e6218cad44794b949661b0d88097182e~mv2.jpg/v1/fill/w_383,h_283,al_c,q_80,usm_0.66_1.00_0.01/IAS%20Gallery_Original.webp",
                    "ended": false,
                    "created_at": "2020-07-22T12:46:53.938819Z"
                }
            }
        ]

I mean the in the frontend if I want to show all the ongoing competition then I have to parse them from the JSON first, restructure it then I can show them.

I just want to show all of the ongoing competitions and once a user clicks on that it will show the details of the competition and all of the artworks ( which are approved ) shows underneath

Yes as I said before I could make two endpoints for the Competition detail view, one will be only for competition details ( without any artworks ) another will be only for artworks with the code you recommended.

But in that case, I have to call two API endpoints at the same time, and I am not sure of is that a good API design or not.

Exactly that’s what I want to have.

The data I want to send will look something like this

[
   {
        "competition": "one",
        "com_otherdetails": "blah blah",
        "artworks": [
            {
             "name": "artwork one",
              "artwork_otherdetails": "blah blah",
             "approved": true
            },
            {
              "name": "artwork two",
              "artwork_otherdetails": "blah blah",
              "approved": true
            }
        ]
   }
]

Thank you for posting such an interesting problem! This is one of those topics that I wouldn’t ordinarily encounter, and it gave me a great opportunity to learn a lot more about the DRF that I haven’t learned before.

Anyway, I found an answer through a combination of a couple of Stack Overflow answers along with the explanations in a couple of tickets. This ticket was most helpful: https://github.com/encode/django-rest-framework/issues/6938

Anyway, there are two different solutions that I’ve tried in my “experiments” repository that seem to work.

The first, and the one that seems most straight forward to me is a change to the ModelViewSet / ListAPIView

class ParentClassViewSet(ListAPIView):
    queryset = ParentClass.objects.prefetch_related(
        Prefetch('child_class_related_name',
                 queryset=ChildClass.objects.filter(expr=value)
        )
    )
    serializer_class = ParentSerializerClass

The other choice involves creating a custom ListSerializer on the child class with overriding the to_representation method:

class FilteredChildClassList(ListSerializer):
    def to_representation(self, data):
        data = data.filter(query_expression=value)
        return super().to_representation(data)

class ChildClassSerializer(ModelSerializer):
    class Meta:
        list_serializer_class = FilteredChildClassList
        model = ChildClass
        fields = ['list', 'all', 'fields']

class ParentClassSerializer(ModelSerializer):
    related_name = ChildClassSerializer(many=True)
    class Meta:
        model = ParentClass
        fields = ['list', 'of', 'parent', 'class', 'fields', 'including', 'related_name']

I’ve tried both and they both work.

Ken

1 Like

Thanks, @KenWhitesell, the first solution seems pretty straight forward. Thanks for doing the hard work for me.