2009-11-07 2 views
1

Рассмотрим модели:Джанго: Заказ объектов по их детских атрибутов

class Author(models.Model): 
    name = models.CharField(max_length=200, unique=True) 

class Book(models.Model): 
    pub_date = models.DateTimeField() 
    author = models.ForeignKey(Author) 

Теперь предположим, что я хочу заказать все книги, скажем, их pub_date. Я бы использовал order_by('pub_date'). Но что, если я хочу, чтобы список всех авторов был заказан в соответствии с тем, кто недавно опубликовал книги?

Это действительно очень просто, когда вы думаете об этом. Это по существу:

  • Автор на вершине тот, кто совсем недавно опубликованную книгу
  • Следующий один является тот, кто опубликовал книгу не как новую, как первые,
  • Так на пре

Возможно, я мог бы что-то взломать, но так как это может стать большим, мне нужно знать, что я делаю это правильно.

Помогите оценить!

Редактировать: Наконец, будет ли возможность добавлять новое поле к каждому, чтобы показать дату последней книги и просто обновить, что все время будет лучше?

ответ

1

Наконец, будет опцией просто добавив. новое поле для каждого, чтобы показать дату последней книги и просто обновить, что все время будет лучше?

На самом деле это было бы! Это нормальная денормализация практика и может быть сделано так:

class Author(models.Model): 
    name = models.CharField(max_length=200, unique=True) 
    latest_pub_date = models.DateTimeField(null=True, blank=True) 

    def update_pub_date(self): 
     try: 
      self.latest_pub_date = self.book_set.order_by('-pub_date')[0] 
      self.save() 
     except IndexError: 
      pass # no books yet! 

class Book(models.Model): 
    pub_date = models.DateTimeField() 
    author = models.ForeignKey(Author) 

    def save(self, **kwargs): 
     super(Book, self).save(**kwargs) 
     self.author.update_pub_date() 

    def delete(self): 
     super(Book, self).delete() 
     self.author.update_pub_date() 

Это третий распространенный вариант у вас есть, кроме двух уже предложил:

  • делать это в SQL с объединением и группировка
  • получать все книги на сторону Python и удалить дубликаты

Оба варианта выбор для вычисления pub_dates из нормализованных данных в то время, когда вы читаете т рубчик. Денормализация делает это вычисление для каждого автора в то время, когда вы пишете новые данные. Идея заключается в том, что большинство веб-приложений читает чаще всего, чем пишет, поэтому этот подход предпочтительнее.

Одним из возможных недостатков этого является то, что в основном у вас одни и те же данные в разных местах, и это требует от вас синхронизации. Обычно это ужасает людей базы данных :-). Но это обычно не проблема, пока вы не используете свою модель ORM для работы с dat (что вы, вероятно, так или иначе). В Django это приложение, которое управляет базой данных, а не наоборот.

Другой (более реалистичный) недостаток заключается в том, что с наивным кодом, который показал массовое обновление книг, может быть медленнее, так как они пинговые авторы обновляют свои данные при каждом обновлении независимо от того, что. Обычно это решается с помощью флага для временного отключения вызова update_pub_date и последующего вызова его вручную. В принципе, денормализованные данные требуют большего обслуживания, чем нормализованные.

0
def remove_duplicates(seq): 
    seen = {} 
    result = [] 
    for item in seq: 
     if item in seen: continue 
     seen[item] = 1 
     result.append(item) 
    return result 


# Get the authors of the most recent books 
query_result = Books.objects.order_by('pub_date').values('author') 
# Strip the keys from the result set and remove duplicate authors 
recent_authors = remove_duplicates(query_result.values()) 
+0

Эй, похоже, что мне нужно. Просто, если я могу спросить: 1. Как это работает и 2. Как это работает? – cwj

+0

Хм, на самом деле, извините, я не верю, что это сработает, вызов .distinct() будет взаимодействовать со списком, зависать, я исправляю его для вас. – DevDevDev

+0

Может быть, лучший способ, я мог бы сделать это в SQL, поэтому я знаю, что вы можете это сделать с помощью моделей Django, но я не могу думать, как с головы. – DevDevDev

1

Или вы могли бы играть с чем-то вроде этого:

Author.objects.filter(book__pub_date__isnull=False).order_by('-book__pub_date')

+0

Не будет работать, может быть много книг с тем же автором. –

+0

Прошу прощения, но почему это не сработает, независимо от того, нет ли у автора книг, одной книги или более? – ayaz

1
from django.db.models import Max 
Author.objects.annotate(max_pub_date=Max('books__pub_date')).order_by('-max_pub_date') 

это требует, чтобы Вы использовали Джанго 1,1

и я предположил, что вы будете добавить «related_name 'в поле вашего автора в Книжной модели, поэтому он будет вызываться Author.books вместо Author.book_set. его гораздо читабельнее.

0

Опираясь на решение Аяз, в чем о: Author.objects.filter (book__pub_date__isnull = False) .distinct() order_by ('-') book__pub_date

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