【问题标题】:Need help using data from a Select_related() queryset需要帮助使用来自 Select_related() 查询集的数据
【发布时间】:2011-07-10 16:55:01
【问题描述】:

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

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

select_related 查询似乎正在获取我想要的内容(基于 DjangoDebugToolbar 显示的原始 SQL 查询)。但是,我不知道怎么称呼它!显示相关表中的值的正确语法或方法是什么?如何遍历返回的查询集中的每个实例?模板下面的 sn-p 应该最有效地显示我想要获得的结果。谢谢。

#----------------
#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>

感谢您的帮助

【问题讨论】:

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


    【解决方案1】:

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

    【讨论】:

    • 我试图在最小化查询的同时将数据调用到我的模板中,而 select_related 似乎是解决方案。我的主要问题实际上只是不知道将相关数据表调用到模板中的语法。我的大部分 django 经验只是简单的数据库交互,所以我在使用更高级的 django 数据库查询方面有点新手。
    • 这正是我需要做的。所以基本上你只需要调用 queriedmodelname.foriegnkeyname.propertyofthatkey 。为什么我不能从我不确定的文档中得到这个。我一直在尝试双下划线 __ 相关字段查找。谢谢!
    【解决方案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 的存在是为了帮助您表示树结构。它为您提供了遍历整个树并在模板中描述每棵树的方法。

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

    祝你好运。

    【讨论】:

    • 这就是答案!不幸的是,我倾向于在一天结束时在这里发帖,当我自己无法弄清楚时,但我所有的文件仍在工作中,我不能在家里试用它们!哈哈。感谢您的帮助,我会检查一下,可能会在早上接受它。
    • 我有意避免将顶级组件与子组件与零件等区分开来。此应用程序的使用方式要求在任何给定时间都可以调用特定的子组件,并且零件将不一致对于各种程序集处于同一层。我将查看 mptt 库。可能当我的模型不可避免地不起作用时,我会回到这篇文章。这是(目前)一个研发类型的项目,所以我不太害怕摔倒在脸上,不得不尝试新的东西(阅读:没有截止日期!)谢谢 josh
    猜你喜欢
    • 2021-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-18
    • 2011-08-05
    • 1970-01-01
    • 2016-02-05
    • 2016-09-13
    相关资源
    最近更新 更多