django: управление данными для отображения в шаблонах - PullRequest
1 голос
/ 14 марта 2012

Есть ли способ как-то предварительно выбрать данные в наборе запросов, прежде чем они перейдут в шаблоны? Это модели «проекта», которые подключаются к «project_phase», и есть записи «project_phase_history», которые отслеживают все изменения статуса.

Я строю отчеты на основе этих данных и показываю все их проекты на одной странице и хочу отображать только project_phase_history, которые были отправлены за последние несколько дней ИЛИ один из последних.

Я пытался сделать это в представлении как-то так:

projects_to_report_on = project.objects.filter(Q(current_phase__phase__id__in=[1,2,3,4]) & Q(role_sponsor__id = sponsor_id))
projects_to_report_on.current_phase.project_phase_history_set = projects_to_report_on.current_phase.project_phase_history.filter(...)

но на самом деле это не помогает - кажется, все данные попадают в шаблон.

В итоге я передал дату в шаблон и сгенерировал отчет примерно так:

{% for s in p.current_phase.project_phase_history_set.all %}
    {% if s.date_submitted >= status_start_date %}

    <tr>
    <td>{{ s.date_submitted }}</td>
    <td>{{ s.date_end_fact|default_if_none:"-" }}</td>
  </tr>
      {% endif %}
      {% endfor %}

но у него нет той гибкости, которую я ищу.

class project(models.Model):
    name = models.CharField(max_length=100, null=False, unique=True)
    description = models.CharField(max_length=1024,null=True,blank=True)
    current_phase = models.ForeignKey('project_phase', null=True, blank=True, related_name="current_phase")

class project_phase(models.Model):
    phase = models.ForeignKey('phases')
    project = models.ForeignKey('project')
    is_finished = models.BooleanField(default=False)

class project_phase_history(models.Model):
    project_phase = models.ForeignKey('project_phase')
    date_start_plan = models.DateField(null=True, blank=False)
    date_start_fact = models.DateField(null=True, blank=True)

1 Ответ

0 голосов
/ 15 марта 2012

Вот ваша проблема:

projects_to_report_on.current_phase.project_phase_history_set = projects_to_report_on.current_phase.project_phase_history.filter(...)

Вы устанавливаете Менеджер обратного конца отношения к QuerySet. Это не работает. Вот пример с блогом и моделями записей:

>>> print(Entry.objects.all())
[<Entry: Today>, <Entry: Hello>]
>>> today = datetime.date.today()
>>> print(Entry.objects.filter(pub_date__lt=today).all())
[<Entry: Hello>]
>>> blog.entry_set = Entry.objects.filter(pub_date__lt=today())
>>> print(blog.entry_set.all())
[<Entry: Today>, <Entry: Hello>]
>>> blog.entry_set = Entry.objects.none()
>>> print(blog.entry_set.all())
[<Entry: Today>, <Entry: Hello>]

Потому что:

>>> blog.entry_set = Entry.objects.all()
>>> type(blog.entry_set)
<class 'django.db.models.fields.related.RelatedManager'>

Это означает, что blog.entry_set по-прежнему является менеджером, и вызов all для менеджера просто вернет все записи. Так что не делай этого. Передайте QuerySet своему шаблону и используйте его:

history_set = projects_to_report_on.current_phase.project_phase_history_set.filter(...)
# add it to the context as 'history_set'

{% for s in history_set.all %}

Так как вам нужно перебрать оба проекта и историю этого проекта, я бы передал словарь в шаблон:

from django.utils.datastructures import SortedDict
# ...
project_map = SortedDict()
for project in projects_to_report_on:
    project_map[project] = history_query_set_goes_here
# ...
return render(request, template, {'project_map': project_map})

А потом в вашем шаблоне:

{% for project, history_set in project_map.items %}
    <h2>{{ project }}</h2>
    <ol>
    {% for history in history_set.all %}
        <li>{{ history }}</li>
    {% endfor %}
    </ol>
{% endfor %}

SortedDict документирован на вики Django . Он поддерживает порядок вставки, поэтому, если вы извлекаете проекты из базы данных в правильном порядке, они будут отображаться в том же порядке.

...