Модель Django, объединяющая отношение один ко многим для отображения в шаблоне - PullRequest
3 голосов
/ 25 февраля 2011

Не уверен, что лучший способ описать проблему. У меня есть 2 таблицы контакт и атрибут. Таблица контактов содержит 1 запись на человека, а таблица атрибутов - 0, 1 или несколько записей на человека. В настоящее время к ним присоединяется «поддельный» внешний ключ, который на самом деле не является внешним ключом. Если мне нужно будет добавить внешний ключ, то я не буду иметь большого значения, просто имея дело со старыми данными, и изначально не было никакого внешнего ключа. Таким образом, таблицы расположены следующим образом:

контакт:

class contact(models.Model):
    contactId = models.AutoField(primary_key=True, db_column='contactId')
    firstName = models.CharField(max_length=255, null=True, db_column='firstName')
    middleName = models.CharField(max_length=255, null=True, db_column='middleName')
    lastName = models.CharField(max_length=255, null=True, db_column='lastName')

атрибут:

class attribute(models.Model):
    attributeId = models.AutoField(primary_key=True, db_column='attributeId')
    contactId = models.IntegerField(db_index=True, null=True, db_column='contactId')
    attributeValue = models.TextField(null=True, db_column='attributeValue')

Итак, я правильно настроил модели Django для представления этих таблиц. Теперь мне нужно выполнить представление и шаблон для циклического перебора этих таблиц, чтобы он генерировал документ XML в следующем формате:

<contacts>
    <contact>
        <contactId></contactId>
        <firstName></firstName>
        <lastName></lastName>
        <attributes>
            <attribute>
                <attributeId></attributeId>
                <attributeValue></attributeValue>
            </attribute>
        </attributes>
    </contact>
</contacts>

Таким образом, будет список всех контактов и всех атрибутов, связанных с каждым контактом.

Я уверен, что есть простой способ сделать это. На других языках я бы просто написал два зацикленных запроса, чтобы зациклить контакт, а затем зациклить атрибуты для каждого контакта. Однако компания, в которой я работаю, мигрирует на новую платформу и хочет новое приложение, написанное на django / python, которое я все еще пытаюсь изучить.

Любая помощь, которую может оказать каждый, приветствуется.

Ответы [ 3 ]

8 голосов
/ 25 февраля 2011

Если вы настроили свои модели django для использования текущих настроек базы данных, я бы сделал следующее, если бы у меня не был настроен внешний ключ.запросы;

attributes_map = dict( 
    [(attribute.contactId, attribute) for attribute in \
        Attribute.objects.filter(contactId__in=[contact.pk for contact in contacts])]
    )

for contact in contacts:
    contact.attributes = attributes_map.get(contact.pk)

return render_to_response("mytemplate.html", {'contacts': contacts })

Шаблон

<contacts>
{% for contact in contacts %}
    <contact>
        <contactId>{{ contact.pk }}</contactId>
        <firstName>{{ contact.firstName }}</firstName>
        <lastName>{{ contact.lastName }}</lastName>

        {% if contact.attributes %}
            <attributes>
            {% for attribute in contact.attributes %}
                <attribute>
                    <attributeId>{{ attribute.pk }}</attributeId>
                    <attributeValue>{{ attribute.attributeValue }}</attributeValue>
                </attribute>
            {% endfor %}
            </attributes>
        {% endif %}

    </contact>
{% endfor %}
</contacts>
1 голос
/ 27 февраля 2011

Звучит так, как будто ты в наследственном аду.

Таким образом, вам, вероятно, будет трудно использовать стандартные модели django, такие как ForeignKey, но вы все равно должны стараться не допускать такого кода в код представления.Лучше определить некоторые методы в вашем классе контактов, что-то вроде ...

def attributes(self):
    return Attribute.objects.filter(contactId=self.contactId)

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

0 голосов
/ 11 марта 2011

Ответ Юджи очень похож на prefetch_refprops Ника Джонсона для App Engine: http://blog.notdot.net/2010/01/ReferenceProperty-prefetching-in-App-Engine

Я нашел способ оптимизировать этот код:

attributes_map = dict( 
    [(attribute.contactId, attribute) for attribute in \
        Attribute.objects.filter(contactId__in=[contact.pk for contact in contacts])]
    )

Заменить его на:

attributes_map = dict(Attribute.objects
    .filter(contactId__in=set([contact.pk for contact in contacts]))
    .values_list('contactId', 'attribute'))

Эта замена экономит время в запросе путем:

  • сжатия списка ключей в set () и
  • , получая только два поля, используемыеdict ().

Также используется тот факт, что .values_list () возвращает список кортежей, ожидаемых dict (), но это работает только в том случае, если первое поле (то есть, 'contactId')) является уникальным.

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

for contact in contacts:
    contact.attributes = attributes_map.get(contact.pk)

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

attributes_map = dict(Attribute.objects
    .filter(contactId__in=set([contact.pk for contact in contacts]))
    .values_list('contactId', 'attribute'))
names_map = dict(Name.objects
    .filter(nameId__in=set([contact.nameId for contact in contacts]))
    .values_list('nameId', 'name'))

for contact in contacts:
    contact.attributes = attributes_map.get(contact.pk)
    contact.name = names_map.get(contact.nameId)

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...