2011-03-07 36 views
2

我正在处理零件数据库,其中每个零件号也可以是一个装配体,这意味着它由任意数量的其他零件组成(并且循环可以继续,子部分由更多部分组成等)。因此,有两个数据库表,一个用于零件信息,另一个用于关系信息 - 与其“子部分”编号链接的零件编号。请记住,“程序集”,“部件”和“子部件”最终都只是“部件(有点令人困惑,但它允许更干和多功能的数据库)需要帮助使用来自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> 

感谢所有帮助

回答

4

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

+0

我试图在最小化查询的同时将数据调用到我的模板中,select_related似乎是解决方案。我在这里的主要问题实际上只是不知道将相关数据表调入模板的语法。我的大部分django经验都是简单的数据库交互,所以我在使用更高级的django数据库查询方面有点新手。 – 2011-03-07 23:38:08

+0

这正是我需要做的。所以基本上你只需要调用queriedmodelname.foriegnkeyname.propertyofthatkey。为什么我无法从我不确定的文档中获取这些信息。我一直在尝试双下划线__相关的字段查找。谢谢! – 2011-03-08 14:04:34

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中的零件,并且可以从该零件到达PartAssembly的集合,但是没有简单的方法可以达到第一个PartAssembly内所有零件的PartAssembly集合。哇,那真是一口!

现在,到您的数据模型。

假设您有一个称为“3毫米螺钉”的零件。这听起来像它可以用于一些不同的大会(我故意不使用'ies'复数形式)。所以你有一个名为书桌的大会和一个名为主席的大会。每个使用许多这些3mm螺丝。你想描述如何建立一个桌面。

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 

所以,你的装配模型现在已经转变成其他大会的一个树形结构,每个都包含自己的一套零件。现在您可以认识到这是一个Tree结构,您可以研究如何在Django中的数据库中表示此结构。

幸运的是,有一个图书馆正是这样做的。 django-mptt存在以帮助您表示树结构。它为您提供遍历整个树的方法,并描述模板中的每个树。

我知道我可能帮助你让更多的工作比你想象的要多,但我认为这对你真的会有帮助。

祝你好运。

+0

这是相当的答案!不幸的是,我倾向于在一天结束的时候在这里发帖,当时我无法自己弄清楚,但是我的所有文件仍然在工作,我无法在家中试用它们!哈哈。感谢您的帮助,我会检查出来,并可能在早上接受它。 – 2011-03-07 23:33:25

+0

我故意避开区分顶级组件与子组件等零件等。使用此应用程序的方式要求在任何给定时间可调用特定的子组件,并且部件不会始终处于同一层组件。我会检查出mptt库。可能当我的模型无法正常工作时,我会回到这篇文章。这是(目前)一个研发类型的项目,所以我不会害怕掉到我的脸上,也不必尝试新的东西(阅读:没有截止日期!)谢谢乔希 – 2011-03-08 14:44:10