Нужна помощь в использовании данных из набора запросов Select_related () - PullRequest
2 голосов
/ 08 марта 2011

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

В настоящее время я используювызов 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 ]

4 голосов
/ 08 марта 2011

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

2 голосов
/ 08 марта 2011

Все 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 существует, чтобы помочь вам представить древовидные структуры. Он дает вам методы для перебора всего дерева и описания каждого дерева в ваших шаблонах.

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

Удачи.

...