Нужна помощь в использовании данных из набора запросов Select_related()

Я работаю с базой данных деталей, где каждый номер детали также может быть сборкой, то есть он состоит из любого количества других деталей (и цикл может продолжаться, подчасти состоят из еще большего количества деталей и т. Д.). Таким образом, есть две таблицы базы данных, одна для информации о деталях, а другая для информации о взаимоотношениях - номер детали, связанный с номером "ее части". Имейте в виду, что "сборки", "детали" и "узлы" в конечном итоге являются просто "деталями" (что довольно запутанно, но допускает создание более СУХОЙ и универсальной базы данных).

В настоящее время я использую вызов select_related для отслеживания ForeignKeys, используемых в моей модели. Однако, поскольку мой запрос может возвращать больше, чем просто один результат (если несколько частей), я не могу использовать поиск "get", и вместо этого я использую "filter". Поэтому я не могу следовать приведенным в документации примерам, основанным на запросе get.

Похоже, что запрос select_related захватывает то, что я намереваюсь сделать (на основе необработанных запросов SQL, показанных DjangoDebugToolbar). Но я не знаю, как это назвать! Каков правильный синтаксис или метод для отображения значений из связанных таблиц? Как я могу перебрать каждый экземпляр в возвращенном наборе запросов? Приведенный ниже фрагмент шаблона должен наиболее эффективно показать, что я пытаюсь получить в результате. Благодарю.

#----------------
#MODEL SNIPPET
#----------------
class Part(models.Model):
    ISC_CHOICES = ( #intentionaly removed for this question 
    )
    part_no = models.CharField(max_length=15, primary_key=True)
    description = models.CharField(max_length=40, blank=True, null=True)
    isc = models.CharField(max_length=2, choices=ISC_CHOICES)
    rev = models.CharField(max_length=2, blank=True, null=True)

#this table relates subparts to the part model above- basically is a manual many-to-many field
class PartAssembly(models.Model):
    id = models.AutoField(primary_key=True)
    part_no = models.ForeignKey(Part, related_name="partno_set")
    subpart = models.ForeignKey(Part, related_name="subpart_set")
    qty = models.IntegerField(max_length=3)
    item_no = models.IntegerField(max_length=3)


#----------------
#VIEW SNIPPET
#----------------
def assembly_details(request, assembly_no): #assembly_no passed through URL
    context_instance=RequestContext(request)
    subpart_list = PartAssembly.objects.filter(part_no=assembly_no).select_related()
    return render_to_response('assembly_details.html', locals(), context_instance,)


#-------------------
# TEMPLATE SNIPPET
#-------------------
{% for partassembly in subpart_list %} 
# obviously, this  loop doesnt return anything for my part.foo variables below
# it does work for the partassembly.bar
        <tr>
            <td>{{ partassembly.item_no }}</td> #EDIT: comments are correct
            <td>{{ partassembly.subpart }}</td> #partassembly.subpart.part_no
            <td>{{ part.description }}</td> #partassembly.subpart.description
            <td>{{ part.rev }}</td>     #partassembly.subpart.rev   
            <td>{{ partassembly.qty }}</td>
            <td>{{ part.isc }}</td>         #partassembly.subpart.isc
        </tr>

Спасибо за любую помощь

2 ответа

Решение

Я не уверен, где именно твоя проблема. Помни что select_related() никоим образом не изменяет доступ к объектам для связанных экземпляров - все, что он делает, это предварительно их кэширует. Итак, вы ссылаетесь на partassembly.part_no.rev и так далее, точно так же, как если бы вы не использовали select_related,

Все select_related делает, охотно выбирает поля, объявленные как ForeignKey в вашей модели. Он пытается избежать лишних вызовов базы данных, он волшебным образом не дает вам доступ к дополнительным полям.

В вашем примере это означает, что доступ partassembly.subpart не приведет к дополнительному выбору базы данных, так как он был с нетерпением извлечен с PartAssembly.objects.filter() вызов.

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

{% for partassembly in subpart_list %} 
        <tr>
            <td>{{ partassembly.item_no }}</td>
            {% for subpart in partassembly.subpart.subpart_set %} # database hit
                 <td>{{ subpart.subpart }}</td>
                 <td>{{ subpart.subpart.description }}</td> # database hit
                 <td>{{ subpart.subpart.rev }}</td>         
                 <td>{{ subpart.qty }}</td>
                 <td>{{ subpart.subpart.isc }}</td>
            {% endfor %}
        </tr>

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

Теперь перейдем к вашей модели данных.

Скажем, у вас есть деталь под названием "3-миллиметровый винт". Звучит так, как будто его можно использовать для ряда различных сборок (я намеренно не использую форму множественного числа 's'). Итак, у вас есть Ассамблея, которая называется Desk, и Ассамблея, которая называется Председатель. Каждый использует много из этих 3-миллиметровых винтов. Вы хотите описать, как построить стол.

 desk = PartAssembly.objects.filter(id=assemblyid)
 part = desk.subpart # lets pretend this returns a 3mm screw
 subassemblies = part.subpart_set.all()
 for a in subassemblies:
     a.subpart.description # could be a Chair, or a Desk, or anything really!

Это происходит потому, что один экземпляр 3-миллиметрового винта (или ЛЮБОЙ детали) используется совместно для всех сборок. Вы действительно не реплицируете таблицу ManyToMany вообще. Ваша модель данных говорит, что одна деталь может использоваться во многих сборках.

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

class Assembly(models.Model):
    parent = models.ForeignKey('self', null=True, blank=True, related_name='children')
    parts = models.ManyToManyField(Part)
    name = models.CharField(max_length=..)

Теперь, когда вы хотите построить стул, вы можете сделать что-то вроде:

assembly = Assembly.objects.get(name='Chair')
children = assembly.children.all()
print assembly
for part in assembly.parts:
    print part
# now you iterate over the tree of children, printing their parts as you go

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

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

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

Удачи.

Другие вопросы по тегам