1

抱歉,如果标题不符合要求,我不知道如何表达我的问题。请随时编辑一个更好的。这是我正在尝试做的事情:

我正在尝试使用几种不同的模型创建一个关系数据库。这个想法是:

  • 合同是唯一的
  • 任何合同都可以拥有(并共享)任意数量的项目
  • 需要为特定合同存储有关每个特定项目的唯一信息

到目前为止,我按预期工作的前两个要点。第三点似乎奏效了,至少在管理面板中是这样。我可以将一条信息分配给特定合同的特定项目。

首先,我这样做是否正确?

其次,作为视图的一部分,我如何一次列出以上所有信息?像这样:

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

1 回答 1

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 中,您可以使用 newprefetch_related在一个查询中获取所有合同的所有信息实例,这大大减少了查询,但您仍然可以为每个项目查询。

contracts = Contract.objects.prefetch_related('info')

使用前面的示例,您的查询计数将是 1+1+3,或总共 5 个,因此您可以将其减半。值得庆幸的是,Django 甚至通过支持 join 语法让你走得更远prefetch_related

contracts = Contract.objects.prefetch_related('info_project')

这将获取所有合同,然后获取这些合同的所有信息实例,最后获取这些信息实例的所有项目。同样,使用前面的示例,您的查询计数减少到 1+1+1,总共 3。

如果您没有运行 Django 1.4,您可以从名为django-batch-select的包中获得几乎相同的功能。

于 2012-06-18T15:19:26.487 回答