Home > Enterprise >  How to check if a object has ManyToMany reference in a queryset django?
How to check if a object has ManyToMany reference in a queryset django?

Time:07-16

I have these models in my django project

class Question(models.Model):
    heading = models.CharField(max_length=300)
    description = models.TextField()

class Profile(models.Model):
    name = models.CharField(max_length=100,null=False,blank=False)
    completed = models.ManyToManyField(Question)

I'm trying to find a optimized way for fetching a list of questions for user it should with whether they have completed it or not. I think it can be done with these quersets:-

all_questions = Question.objects.all()
completed_questions = Question.objects.filter(profile = profile_instance)

where profile_instance is a profile object. Then we can loop through the all_questions and check whether they also exist in completed_questions, but i am not sure whether this is optimized for pagination. I'm using Django-Rest Framework pagination.

Edit 1:- It looks like i'm not clear with the result i'm looking for, i will elaborate on it. I need a queryset which satisfies two requirements:-

  1. List of all questions.
  2. In this list, if let's say question 1 is completed by the user, then, it should have a boolean field turned to true. Note, that the question will only be completed for the current logged-in user not all the users.

CodePudding user response:

If you are just trying to get the questions connected to the profile then something like this would work:

completed_questions = profile.completed.all()

This will return a queryset of Question objects connected to that profile. There isn't then the need to loop through all of the questions to see if they exist in completed questions.

If you want to filter Questions to get all of those that are (or aren't) answered at all then you can filter for profiles with completed questions and then filter the questions against it:

profile_with_completed = Profile.objects.exclude(completed=None)
completed_questions = Question.objects.filter(profile__in=profile_with_completed)

Edit

To get a list of all questions annotated with whether the question has been completed by the user or not, use the following annotation. It will check whether the primary key of each question is in the list of completed question primary keys connected to the selected profile (which you can separately linked to the logged-in user).

from django.db.models import Case, When, Value, BooleanField

all_questions = Question.objects.annotate(is_complete=Case(
    When(
        pk__in=profile.completed.values('pk'), 
        then=Value(True)
    ),
    default=Value(False), 
    output_field=BooleanField())
)

In your view or your template you can then access question.is_complete which returns true or false.

  • Related