Запрос данных из определенного связанного объекта в шаблоне Django - PullRequest
0 голосов
/ 06 февраля 2011

Я пытаюсь использовать Django для отображения таблицы информации по нескольким моделям, и я не уверен, каковы наилучшие методы для этого.Вот урезанная версия моего models.py:

from django.contrib.auth.models import User

class Widget(models.Model):
    name = models.CharField(max_length=50)
    pass

class Finished_Widget(models.Model):
    user = models.ForeignKey(User)
    thing = models.ForeignKey(Thing)
    created = models.DateTimeField(editable=False)

Это довольно простая установка с подключением пользователя и виджета через неизвестное число объектов Finished_Widget.В моем html я хотел бы показать список экземпляров имен виджетов и дату самого последнего готового виджета.Очевидно, что приведенный ниже код не работает, но, надеюсь, он проиллюстрирует, какие данные я хочу получить.

{% for widget in widget_list %}
<p>{{ widget.name }}</p>
<p>{{ widget__Finished_Widget.latest.created }}</p>
{% endfor %}

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

  • добавление желаемой даты в качестве дополнительного атрибута через представление
  • , создание словаря в представлении и вызов его в шаблоне
  • ManyToManyField с использованием 'through'аргумент
  • добавление мета в вызов виджета к дате создания последней версии Finished_Widget

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

Примечание: я уже нашел довольно много вариантов этой проблемы на SO, что делает ее довольно близкой к обману, но они не кажутсячтобы мне очень помогло из-за необходимости сузить список Finished_Widget до тех, которые соответствуют идентификатору пользователя, совпадают с идентификатором виджета, и только самый последний.

Ответы [ 2 ]

2 голосов
/ 06 февраля 2011

Обновлен ответ на основе необходимости передачи user объекта.

С вашей точки зрения, проще всего разобраться с этим, но у него есть свои проблемы.

for widget in widget_list:
    widget.latest_finished_widget = widget.finished_widget_set.filter(user=request.user).latest('created')

{% for widget in widget_list %}
    <p>{{ widget.name }}</p>
    <p>{{ widget.latest_finished_widget }}</p>
{% endfor %}

Хотя этот код легко написать, он страдает от выполнения запроса БД для каждой итерации.

Одно быстрое решение называется разделением запросов. Используйте 2 запроса и python для максимально эффективного заполнения обратных отношений без перехода на SQL.

widgets = Widget.objects.filter(...)

finished_widget_map = dict( 
    [(x['thing__id'], x['created']) for x in 
        Finished_Widget.objects.filter(thing__in=widgets, user=request.user).values_list('thing__id', 'created').order_by('created')])
    # this ensures we only select what we need, thing__id and the created column
    # ordering by created will ensure only the last (latest) will appear in our dictionary

for widget in widgets:
    widget.latest_finished_widget_created = finished_widget_map.get(widget.id, 'No Widget')


{% for widget in widgets %}
    {{ widget.name }}
    {{ widget.latest_finished_widget_created }}
{% endfor %}

Хотя всегда есть компромиссы. Это может быть медленным, если есть много Finished_Widgets, которые Python бессмысленно пытается заполнить диктом.

0 голосов
/ 06 февраля 2011

Ну, я не думаю, что здесь достаточно информации, чтобы полностью ответить на ваш вопрос, но одним простым решением проблемы возврата только самого последнего Finished_Widget было бы добавить метод с именем «latest_widget» в модель User:

class User(models.Model):
    #...
    def latest_widget(self):
        return self.widgets.all().order_by('-created')[0]

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

Как только вы получите этот метод, вызвать его из шаблона просто.Если у вас есть список пользователей, например, с именем user_list, вы можете отобразить каждого пользователя и его / ее последний виджет следующим образом:

{% for uu in user_list %}
<p>
    {{uu.username}}: {{uu.latest_widget.name}}
</p>
{% endfor %}
...