2017-07-04 19 views
3

如何使下面的代碼更有效率(例如,如何用查詢替換循環)?如何消除循環中django查詢的低效率?

def get_question(datetime_now, questions_queryset, user): 
    best_schedule = None 
    best_question = None 
    # HOW TO ELIMINATE THE FOLLOWING LOOP AND REPLACE WITH A QUERY? 
    for question in questions_queryset: 
     try: 
      schedule = (Schedule.objects 
         .filter(question=question, user=user) 
         .latest(field_name='datetime_added') 
     except ObjectDoesNotExist: 
      schedule = None 
     if (schedule and (schedule.date_show_next >= datetime_now) and 
       ((not best_schedule) or 
       (schedule.datetime_added >= best_schedule.datetime_added))): 
      best_schedule = schedule 
      best_question = question 

    return best_question 



models.py

from django.contrib.auth.models import User 
from django.db.models import DateTimeField, ForeignKey, Model, TextField 

class Question(Model): 
    question = TextField() 

class Schedule(Model): 
    datetime_added = DateTimeField(auto_now_add=True) 
    datetime_show_next = DateTimeField(null=True, default=None) 
    question = ForeignKey(Question) 
    user = ForeignKey(User, null=True) 

回答

4

你可以在這個答案https://stackoverflow.com/a/43883397/3627387或使用Prefetchhttps://stackoverflow.com/a/31237026/3627387

這裏使用Subquery就像是Prefetch實現這一目標的一種方法:

schedules_prefetch = Prefetch(
     'schedule_set', 
     queryset=Schedule.objects.filter(user=user)) 
for question in questions_queryset.prefetch_related(schedules_prefetch): 
    try: 
     # using max here so it wouldn't do another DB hit 
     schedule = max(question.schedule_set.all(), 
         key=lambda x: x.datetime_added) 
    except ValueError: 
     schedule = None 

下面是使用Subquery(它可能不實際工作,但會給你的總體思路)爲例:

from django.db.models import OuterRef, Subquery 
schedules = (Schedule.objects 
      .filter(user=user, question=OuterRef('pk')) 
      .order_by('datetime_added')) 
questions_queryset = (questions_queryset 
        .annotate(latest_schedule=Subquery(schedules[:1]))) 
for question in questions_queryset: 
    schedule = question.latest_schedule 
2
# Get the question ids  
    question_ids = questions_queryset.values_list('id', flat=True) 

    # get the beloved shedule 
    schedule = Schedule.objects.filter(question__in=question_ids, user=user).latest(field_name='datetime_added') 

    # You may opt for Schedule.objects.get() so as not to run into 
    # the problem of multiple objects returned if all you need is strictly one schedule 
+0

這並不能解決獲得最新的日程安排對每個問題的問題 –