Обработка связанных моделей в Django для использования в Django-Piston - PullRequest
2 голосов
/ 16 сентября 2010

У меня настроено так (изменено для простоты)

class Author(models.Model)
    name = models.CharField(max_length=100)
    ...

class Document(models.Model):
    title = models.CharField(max_length=200)
    content - models.TextField()
    author = models.ForeignKey("Author", related_name="documents")
    date_published = models.DateTimeField()
    categories = models.ManyToManyField("Category")

class Category(models.Model):
    name = models.CharField(max_length=100)

Я загружаю записи об авторах, но я хочу получить только связанные записи документов для каждого автора, которые соответствуют определенным критериям - скажем,, date_published и category.

Я знаю, что простой способ сделать это - извлечь записи в виде списка словарей, используя Author.objects.values(), просматривая каждую запись и выполняя:

author['documents']=Document.objects.filter(categories__in=[category_list], date_published__year=year)`

Однако, это генерируется для django-поршня, и кажется, что оно будет наиболее удачным (особенно если вы определяете свои собственные поля!), Если вы возвращаете объект QuerySet.

Частично это может быть связано с тем, чтоЯ внес изменения в базовый джанго-поршневой код.По сути, текущая версия кода здесь перезаписывает значение fields.Я изменил этот код, чтобы можно было изменить значение fields для обработчика на основе запроса (чтобы я мог предоставить более подробную информацию, если запрос был для определенного ресурса).

Так что, я думаю, мой вопростри раза:

  1. Есть ли способ отфильтровать или каким-то образом ограничить подзаписи записи (т. е. отфильтровать documents для каждого author.documents)
  2. Если нет, то чтофункциональный способ сделать это, который также работает с Django-поршнем?
  3. Есть ли какой-то более простой и лучший способ сделать то, что я пытаюсь сделать (показать всех авторов без их документов, если идентификатор не указан, но отображение вложенных записей при фильтрации только по одному автору)?

Уточнение

Ладно, просто чтобы прояснить, вот нужный мне псевдокод:

def perhaps_impossible_view(request, categories=None, year=None):
    authors = Author.objects.all()
    authors.something_magical_happens_to_documents(category__in=[categories], date_published__year=year)
    return render_to_response('blar.html', locals(), RequestContext(request))

Так что, если бы я был , чтобы поместить его в шаблон, это работало бы без каких-либо изменений:

{% for a in authors %}
    {% for d in authors.documents.all %}
        {{ d.title }} is almost certainly in one of these categories: {{ categories }} and was absolutely published in {{ year }}. If not, .something_magical_happens_to_documents didn't work.
    {% endfor %}
{% endfor %}

something_magical_happens_to_documents должно работать и фактически изменять содержимоеdocuments для каждой записи автора.Кажется, это должно быть возможно, но, возможно, это не так?

1 Ответ

0 голосов
/ 18 сентября 2010

Отредактировано ... или лучше ... заменено! :)

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

Вы получаете полное количество документов авторов, потому что вы не используете набор запросов для получения количества документов:

qryset = Author.objects.all()
qryset = qryset.filter(documents__categories__name__in = category_list).distinct()
qryset = qryset.filter(documents__date_published__year=year)

print(qryset) дает [<Author: Author object>] (если только один автор соответствует всем категориям), а qryset[0].documents.count() вернет только количество найденных документов (не все документы от автора - 2 в случае I проверено, и у автора было 4, но только 2 соответствовали всем условиям).

Если вы используете dict (.values ​​()) вместо наборов запросов в описанных выше шагах, вы не сможете сделать это (я думаю), потому что dict не будет иметь поля документов, так:

qryset_dict = Author.objects.values()
qryset_dict = qryset_dict.filter(documents__categories__name__in = category_list).distinct().values()
qryset_dict = qryset_dict.filter(documents__date_published__year=year).values()

при выдаче qryset_dict[0].documents.count() появляется сообщение об ошибке:

AttributeError: 'dict' object has no attribute 'documents'


Теперь, чтобы добавить отфильтрованных авторов обратно, вы можете сделать:

res = []
for a in Author.objects.all():
    if a in qryset:
        res.append([a,a.documents.count()])
    else:
        res.append([a,0])

и res будет список с <authors> в 1-м столбце и количеством документов, совпадающих во 2-м столбце.

Я знаю, что это далеко от совершенства ... но если вас интересует только count() соответствующих документов на автора, я думаю, вы могли бы найти лучший способ, используя агрегацию и аннотацию django или возможно сделать это с помощью raw sql, используя left join от авторов к документам.




РЕДАКТИРОВАТЬ после уточнения в вопросе:
def possible_view(request, categories=None, year=None):
    # you will pass these as parmeters of course
    category_list = ['c2', 'c3']
    year = 2010

    qryset = Document.objects.filter(categories__name__in = category_list).distinct()
    qryset = qryset.filter(date_published__year=year)
    authors = Author.objects.all()
    return render_to_response('blar.html', { 'result': qryset, 'authors': authors, 'categories': category_list, 'year': year }, RequestContext(request))

Шаблон blar.html:

{% for a in authors %}
    <b>{{a.name}}</b><br />
    {% for d in result %}
        {% if d.author.name == a.name %}
            {{ d.title }} is almost certainly in one of these categories: {{ categories }} and was absolutely published in {{ year }}. If not, .something_magical_happens_to_documents didn't work.<br />
        {% endif %}
    {% endfor %}<br />
{% endfor %}

Это даст вам что-то не очень красивое, но со всеми авторами и ниже каждого из них, список их документов, попадающих в одно из category_list (условие ИЛИ для AND, вам нужно отфильтровать запрос для каждой категории вместо использования __in).

Если у автора нет документа в category_list, он будет указан без документов под ним.


Что-то вроде:

aut1
tit2 is almost certainly in one of these categories: ['c2', 'c3'] and was absolutely   published in 2010. If not, .something_magical_happens_to_documents didn't work.
tit1 is almost certainly in one of these categories: ['c2', 'c3'] and was absolutely published in 2010. If not, .something_magical_happens_to_documents didn't work.

aut2
tit3 is almost certainly in one of these categories: ['c2', 'c3'] and was absolutely published in 2010. If not, .something_magical_happens_to_documents didn't work.

aut3
...