Otskimanot Sqilal
Otskimanot Sqilal

Reputation: 2402

django how to check if a user is already exists on this app without making too much query?

Assume these as django models:

class Question():

    question = charfield()
    choice = charfield(choices = answer_choice)

class Answer():

    question = models.foreignkey(Question, related_name = 'answers')
    answerer = models.foreignkey('auth.User')
    answer = models.charfield()

I'm building a page where i display 100 questions, and each User can answer, but cannot change the answer for each question. For each question, i have to check whether the User already exists or not on Answerer. Then i make templatetags: @register.filter def this_user_exists(user,obj): obj = obj.answers.filter(answerer_id = user.id) return obj

Then on the template:

# obj is list of question
{% if not user|this_user_exists:obj %}
    # can answer
{% else %}
    # cannot answer
{% endif %}

The problem is, for every question, it generate 1 query, so for 100 question it'll generate 100 query. I tried this query to generate question Question.objects.all() and Question.objects.prefetch_related('answers'), still got the problem. Is there a better way to achieve this without making too many query?

Upvotes: 0

Views: 162

Answers (2)

Ted
Ted

Reputation: 12318

In your view:

answered_ids = [ans.question_id for ans in Answer.objects.filter(answerer=request.user)]

In your template:

{% if not obj.id in answered_ids %}
    # can answer
{% else %}
    # cannot answer
{% endif %}

Upvotes: 0

Qiang Jin
Qiang Jin

Reputation: 4467

To reduce queries, you can first query out your needed answers, and then fetch all related answerers,

answers = Answer.objects.select_related('answerer').filter(xxxx)

# fetch related user id's
userids_in_answer = [answer.answerer.id for answer in answers]

# fetch user ids
user_id_set = set(User.objects.filter(id__in=userids_in_answer).values('id', flat=True)

after that, you can easily know whether user exists by,

for answer in answers:
  if answer.answerer.id in user_id_set:
      xxx

The query num is reduced, you can check whether this helps.

Upvotes: 2

Related Questions