需要使用Select_related()查询集中的数据的帮助

时间:2011-03-07 22:20:33

标签: django django-models django-select-related

我正在研究零件数据库,其中每个零件编号也可以是一个装配体,这意味着它由任意数量的其他零件组成(循环可以继续,子零件由更多零件组成,等等) 。因此,有两个数据库表,一个用于部件信息,另一个用于关系信息 - 与其“子部件”编号链接的部件号。请记住,“程序集”,“部件”和“子部件”最终都只是“部件(有点令人困惑,但它允许更干燥和多功能的数据库)。

我目前正在使用select_related调用来跟踪我的模型中使用的ForeignKeys。但是,因为我的查询可能返回的不仅仅是单个结果(如果有多个子部分),我不能使用“get”查找而我正在使用“filter”。所以 - 我不能按照文档中显示的全部基于get查询的示例。

select_related查询似乎抓住了我想要的东西(基于DjangoDebugToolbar显示的原始SQL查询)。但是,我不知道怎么称呼它!从相关表中显示值的正确语法或方法是什么?如何循环返回的查询集中的每个实例?模板下面的片段应该最有效地显示我想要获得的结果。感谢。

#----------------
#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 个答案:

答案 0 :(得分:4)

我不确定你的问题究竟在哪里。请记住,select_related()不会以任何方式更改相关实例的对象访问权限 - 它所做的就是预先缓存它们。因此,您可以参考partassembly.part_no.rev等,就像您没有使用select_related一样。

答案 1 :(得分:2)

所有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集。哇,真是满口!

现在,进入您的数据模型。

假设您有一个名为“3mm螺丝”的零件。听起来它可以用于许多不同的组件(我故意不使用'ies'复数形式)。所以你有一个名为Desk的程序集,以及一个名为Chair的程序集。每个都使用许多这些3毫米螺丝。您想描述如何构建Desk。

 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!

这是因为在所有组件之间共享3mm螺钉(或任何部件)的单个实例。您根本不是真正复制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

因此,您的Assembly模型现在已转换为其他Assembly的Tree结构,每个Assembly都包含自己的Parts部件。现在你可以认识到这是一个Tree结构,你可以研究如何在Django中的数据库中表示这个结构。

幸运的是,有一个库正是这样做的。存在django-mptt来帮助您表示树结构。它为您提供了迭代整个树的方法,并描述了模板中的每个树。

我知道我可能会帮助你做出比你认为更多的工作,但我认为这会对你有所帮助。

祝你好运。