2

我正在研究一个零件数据库,其中每个零件号也可以是一个组件,这意味着它由任意数量的其他零件组成(并且循环可以继续,子零件由更多零件组成,等等)。所以有两个数据库表,一个用于零件信息,另一个用于关系信息——一个零件号链接到它的“子零件”号。请记住,“组件”、“零件”和“子零件”最终都只是“零件”(有点令人困惑,但它允许更干燥和通用的数据库)。

我目前正在使用 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>

谢谢你的帮助

4

2 回答 2

4

我不确定你的问题到底出在哪里。请记住,select_related()这不会以任何方式更改相关实例的对象访问权限——它所做的只是预先缓存它们。所以你引用partassembly.part_no.rev等等,就好像你没有使用select_related.

于 2011-03-07T22:58:07.003 回答
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 中的零件,并且可以从该 Part 访问 PartAssembly 集,但是没有简单的方法可以访问第一个 PartAssembly 中所有 Parts 的 PartAssembly 集。哇,那是一口!

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

假设您有一个称为“3mm 螺钉”的零件。听起来它可以用于许多不同的程序集(我故意不使用“ies”复数形式)。因此,您有一个称为 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 的存在是为了帮助您表示树结构。它为您提供了遍历整个树并在模板中描述每棵树的方法。

我知道我可能已经帮助你完成了比你想象的更多的工作,但我认为这将真正帮助你。

祝你好运。

于 2011-03-07T23:16:41.847 回答