0

I have a model

    class Event(models.Model):
        random_fields...

    class Registrations(models.Model):
        user = models.ForeignKey(User...)
        event = models.ForeignKey(Event...)
        ts = models.DateTimeField(...)

Now I want to fetch the list of all the events along with whether the user who made the request is registered in that event or not (is_registered field in the ModelSerializer of Event maybe).

This should ideally happen in a single request and not too many database queries.

What is the efficient way to do this?

1 Answer 1

1

I think you can use prefetch related for reducing DB query. When fetching registrations from event, you can use prefetch_related to fetch all registrations at once(so multiple db query is not necessary).

So, for this first you can define the model like this:

class Registrations(models.Model):
    user = models.ForeignKey(User...)
    event = models.ForeignKey(Event, related_name="registrations",..)

Then, you can define the EventSerializer like this:

class EventSerializer(serializer.ModelSerializer):
    registrations = RegistrationSerializer(many=True, read_only=True)  # <-- getting all registraions via RegistrationSerializer
    is_invited = serializer.SerializerMethodField()

    class Meta:
       model = Event
       fields = "__all__"

    def get_is_invited(self, obj):
        return obj.registrations.filter(user=self.context.get("request").user).exists()  # does not make any DB query

SerializerMethodField has been used here to fetch if user is being invited or not.

Now in the view, when calling the Event queryset, use prefetch_related.

# A minimal example

class SomeView(APIView):
    def get(self, request, **kwargs):
        qset = Event.objects.prefetch_related('registrations').all()
        serializer = EventSerializer(qset, many=True)
        return Response(serializer.data)
Sign up to request clarification or add additional context in comments.

4 Comments

Hi, there is a typo in the custom field method, instead of 'get_in_invited' it is 'get_is_invited'.
This sounds good. As far as I understand, this method will load all the registrations for each event in memory. Am I right? If it does then is there a way to do this without loading all the registrations in memory?
Also for newer versions of django, I think select_related will not work for reverse relations. Use prefetch_related instead.
select_related worked for me in django 1.11. But it does not work in 2.1. There is 2 ways to do it to fetch data, one is either query database for each event or load these data in memory.

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.