我正在研究零件数据库,其中每个零件编号也可以是一个装配体,这意味着它由任意数量的其他零件组成(循环可以继续,子零件由更多零件组成,等等) 。因此,有两个数据库表,一个用于部件信息,另一个用于关系信息 - 与其“子部件”编号链接的部件号。请记住,“程序集”,“部件”和“子部件”最终都只是“部件(有点令人困惑,但它允许更干燥和多功能的数据库)。
我目前正在使用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>
感谢您的帮助
答案 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来帮助您表示树结构。它为您提供了迭代整个树的方法,并描述了模板中的每个树。
我知道我可能会帮助你做出比你认为更多的工作,但我认为这会对你有所帮助。
祝你好运。