Django:如何迭代两个一对二的表关系?

时间:2018-04-30 08:35:22

标签: python django

我正在尝试构建一个查询三个表的简单网页。有Company表与Position表具有一对多关系,以及与Project表的一对多关系。

目标是让页面显示一次给定的公司,以及与该公司相关的所有职位和项目。然后,继续展示下一家公司,在那里举行的任何职位和完成的项目。

以下是我最接近这个问题的方法。但是,显而易见的问题是,如果有一个以上的项目与某个公司相关联,您会看到该公司不止一次上市。

我是Django的新手,所以为了学习,我想在寻求帮助之前足够努力地击败自己的脑袋;但此时我真的可以使用一些新鲜的想法。

另外:我可以看到嵌套for循环在这里是如何工作的,但是我不清楚它的机制如何与查询一起工作,然后在模板中。

型号:

from django.db import models


class Company(models.Model):
    company_id = models.AutoField(primary_key=True)
    company_name = models.CharField(max_length=20)
    company_logo = models.ImageField(upload_to='images/')    

    def __str__(self):
        return self.company_name   

class Position(models.Model):
    position_id = models.AutoField(primary_key=True)
    position_title = models.CharField(max_length=55)
    company_id = models.ForeignKey('professional.Company',
                               on_delete=models.CASCADE,
                               blank=True,
                               null=True)
    begin_date = models.DateField()
    end_date = models.DateField()   

    def __str__(self):
        return self.position_title   

class Project(models.Model):
    project_id = models.AutoField(primary_key=True)
    project_name = models.CharField(max_length=55)
    company_id = models.ForeignKey('professional.Company',
                               on_delete=models.CASCADE,
                               blank=True,
                               null=True)
    project_description = models.CharField(max_length=500)
    project_image = models.ImageField(upload_to='images/')

    def __str__(self):
        return self.project_name

查看:

from django.views.generic import TemplateView, ListView

from professional.models import Company



class ProfessionalHome(TemplateView):
    template_name = 'professional/professional_home.html'


class TechnologyListView(ListView):
    template_name = 'professional/__technology.html'
    context_object_name = 'technology_list'

    def get_queryset(self):        
        return Company.objects.values('company_name','position__position_title', 'project__project_name')

HTML和模板:

{% for job in technology_list %}

    <h1>{{job.company_name}}</h1>
    <h1>Position: {{job.position__position_title}}</h1>
    <h1>project: {{job.project__project_name}}</h1>

{% endfor %}

2 个答案:

答案 0 :(得分:1)

如果要迭代公司,那么您应该使用公司模型作为视图的基础,而不是技术。此外,除非您知道自己有充分的理由,否则应该避免使用valuesvalues_list。您可以使用prefetch_related()来减少反向查询的数量。所以:

class TechnologyListView(ListView):
    def get_queryset(self):        
        return Company.objects.all.prefetch_related('project','position')

...

{% for company in company_list %}

    <h1>{{company.company_name}}</h1>
    {% for position in company.position_set.all %}
      <h1>Position: {{ position.position_title }}</h1>
    {% endfor %}
    {% for project in company.project_set.all %}
      <h1>project: {{ project.project_name }}</h1>
    {% endfor %}

{% endfor %}

(注意,你应该避免让你的ForeignKey字段名称以&#34; _id&#34;结尾.Django字段指的是整个公司,而不是ID;字段应该只调用company。无论如何,底层数据库将以_id为后缀。此外,您不需要在所有字段上使用model_name前缀;从访问它们的对象中可以明显看出它。)

答案 1 :(得分:1)

而不是get_queryset方法中的值,您可以返回实际的查询集,然后迭代它以构建视图。

def get_queryset(self):        
        return Company.objects.all()

然后在你的模板中:

{% for job in technology_list %}

    <h1>{{job.company_name}}</h1>
    {% for position in job.position_set.all() %}
        <h1>Position: {{position.position_title}}</h1>
    {% endfor %}
    {% for project in job.position_set.all() %}
        <h1>project: {{project.project_name}}</h1>
    {% endfor %}

{% endfor %}