2013-12-11 2 views
2

Я следующие модели:Джанго QuerySets: Получите уникальный/первый элемент из ForeignKey поля

class SchoolClass(models.Model): 
    title = models.CharField() 
    max_students = models.IntegerField(default=10) 
    is_published = models.BooleanField(default=False) 

class Session(models.Model): 
    school_class = models.ForeignKey(SchoolClass, related_name="sessions") 
    start_date = models.DateField() 
    enrolled_students = models.IntegerField() 

SchoolClass может иметь несколько сеансов (например, «Математика для чайников» в понедельник, вторник и пятницу = 3 Sessions) ,

На моей странице с индексом (ListView) я хотел бы показать все предстоящие классы (которые имеют хотя бы один сеанс) только один раз, поскольку классы, которые имеют много сеансов, сделают обзор грязным.

Как я могу создать список Session-объектов (я могу получить соответствующую информацию курса через session.school_class), которые отвечают следующим требованиям:

  • start_date__gte=datetime.now().date()
  • school_class.is_published=True
  • это первый элемент SchoolClass (oder_by('start_date')[0])

Спасибо!

PS: Я бегу MySQL в качестве БД, так различны ('поле') не будет работать ..


Edit:

Ниже мое текущее решение, которое работает , но это не очень чистый (избыточные хиты на БД)

def get_sessions_mixin(filter_args): 
    session_qs = [] 
    qs = SchoolClass.objects.filter(**filter_args) 
    for schoolclass in qs: 
     session_qs.append(schoolclass.get_first_session()) 

    #session_qs = Session.objects.filter(course_meta__is_deleted=False, date_from__gte=datetime.now().date()).\ 
    # annotate(Max('date_from')) 
    #session_qs = qs.order_by('get_first_session__date_from') 

    return session_qs 

и внутри models.py

class Sessions(models.Model): 
    # ... 
    def get_first_session(self): 
     if self.is_published: 
      tmp_sessions = self.sessions.filter(date_from__gte=datetime.now().date()) 
      if tmp_sessions: 
      return tmp_sessions.order_by('date_from')[0] 
    return None 
+0

Не могли бы вы объяснить, пожалуйста, более четкое определение третьей отметки. – mariodev

+0

Уверен. Если объект SchoolClass связан с, например,3 Объекты сеанса, я просто хочу первый (самый ранний) объект Session в QuerySet –

ответ

1

Я не могу придумать способ сделать то, что вы хотите, в одном запросе ORM Django. То, что я бы, вероятно, это, во-первых, получить все соответствующие Session объектов:

sessions = Session.objects.filter(school_class__is_published=True, 
            start_date__gte=datetime.now().date()) 
          .select_related('school_class') 
          .order_by('start_date') 

Теперь у вас есть все, что нужно, в том числе связанных SchoolClass данных из одного запроса. Вам просто нужно сделать некоторую работу на Python для фильтрации данных. Есть много способов, вы можете сделать это, вот простой:

first_sessions = collections.OrderedDict() 
for session in sessions: 
    if session.school_class.pk not in first_sessions: 
     first_sessions[session.school_class.pk] = session 

first_sessions.values() И теперь имеет то, что вы хотите. Вы можете обернуть это методом в обычном Manager.

Это трудно сделать предположение о производительности, когда базы данных участвуют (особенно, не зная, сколько Sessions есть для типичного SchoolClass), но я подозреваю, что этот подход одного запроса будет быстрее и проще, чем ваше текущее решение, которое поражает базы данных много раз.

+0

Спасибо за ответ. Я решил добавить поле (first_session) в модель SchoolClass и обновить его (через сигналы) каждый раз, когда смена сеанса. Иногда денормализация - это прекрасная вещь :) Я буду отмечать ваш ответ как принятый, так как это самый близкий правильный ответ здесь. –

0

Похоже, этот вид запроса может работать:

SchoolClass.objects.filter(sessions__start_date__gte=datetime.now().date(), is_published=True)\ 
    .annotate(session_count=Count('sessions'))\ 
    .filter(session_count__gte=1) 

Но я не уверен, о том, что означает, что третья точка пули.

+0

Спасибо за ответ. Это может сработать, но я пытаюсь получить объекты QuerySet объектов Session (первый или самый ранний из каждого объекта SchoolClass). –

+2

['.earliest ('sessions_start_date')'] (https: //docs.djangoproject. com/en/1.6/ref/models/querysets/# early) –

Смежные вопросы