道歉,如果标题没有达到标题,我不知道如何说出我的问题。请随意编辑一个更好的。这是我想要做的:
我正在尝试使用几个不同的模型创建关系数据库。这个想法是:
到目前为止,我已按预期工作的前两个要点。第三点似乎有效,至少在管理面板中是这样。我可以将一条信息分配给特定合同的特定项目。
首先,我是否采取正确的方式?
其次,作为视图的一部分,如何一次列出上述所有信息?像这样:
-ContractName
-ProjectName
-ProjectName
-SpecificInfo/Comments
-ProjectName
以下是我目前的型号代码:
from django.db import models
class Project(models.Model):
identifier = models.CharField(max_length=30)
description = models.CharField(max_length=100)
def __unicode__(self):
return self.identifier
class Contract(models.Model):
number = models.CharField(max_length=30)
name = models.CharField(max_length=75)
projects = models.ManyToManyField(Project)
def __unicode__(self):
return self.number
class Info(models.Model):
contract = models.ForeignKey(Contract)
project = models.ForeignKey(Project)
title = models.CharField(max_length=75)
info_text = models.TextField()
def __unicode__(self):
return self.title
以下是视图,目前仅显示合同和任何相关项目:
<ul>
{% for contract in contracts %}
<b><li>{{ contract.number }} - {{ contract.name }}</li></b>
{% for project in contract.projects.all %}
<ul>
<li>{{ project.identifier }} - {{ project.description }}</li>
</ul>
{% endfor %}
{% endfor %}
</ul>
答案 0 :(得分:2)
子弹的子弹:
合同是唯一的
独一无二的?你可以使它对于名称的唯一或唯一,或者甚至是特定客户的唯一(虽然这没有多大意义,因为你可能希望客户有多个合同。重复业务FTW!)。要使特定字段唯一,您只需添加unique=True
即可。
任何合约都可以拥有(并分享)任意数量的项目
合同有许多项目,项目有很多合同,所以这是一个明显的M2M,你已经涵盖了。
需要为特定合同的每个特定项目存储唯一信息
所以这就是你侧身的地方。如果需要将唯一信息存储在关系上,即它特别适用于合同和项目的组合,那么您需要一个“通过”模型。你基本上用Info
模型创建了它,但你需要告诉Django实际使用这个模型而不是它的默认隐式模型,例如:
projects = models.ManyToManyField(Project, through='Info')
(我建议将Info
重命名为更具描述性的内容,例如ContractProject
,以表明它是这两个模型的连接表。)
有了这个,您的模板看起来大致相似(基于您当前的代码,而不是我建议的名称更改):
{% for contract in contracts %}
{{ contract.name }}
{% for info in contract.info_set.all %}
{{ info.project.name }}
{{ info.title }}
{{ info.info_text }}
{% endfor %}
{% enfor %}
因此,这里的想法是,不是直接从合同中获取项目,而是需要获取连接表实例(以便您可以访问该信息),然后通过它拉动项目。请记住,虽然这是相对昂贵的,但是每个合约都有一个查询来获取Info
个实例,然后为每个查询获得另一个项目查询。因此,如果您有每个合同的3个合同和3个项目,那么您已经在谈论1 + 3 * 3个查询或10个总计。这个数字当然会随着你拥有的合同/项目的数量呈指数级增长。
在Django 1.4中,您可以使用新的prefetch_related
来获取一个查询中所有合同的所有信息实例,从而大大减少查询,但您仍然可以查询每个项目。
contracts = Contract.objects.prefetch_related('info')
使用前面的示例,您的查询计数将为1 + 1 + 3或总计5,因此您可以将其减半。值得庆幸的是,Django甚至允许您通过prefetch_related
支持连接语法来进一步使用。
contracts = Contract.objects.prefetch_related('info_project')
这将获取所有合同,然后获取这些合同的所有信息实例,最后获取这些信息实例的所有项目。再次,使用前面的示例,将查询计数降至1 + 1 + 1,总计3。
如果您没有运行Django 1.4,您可以从名为django-batch-select的软件包中获得相同的功能。