【问题标题】:Django: want to loop through _set for pk values onlyDjango:只想循环 _set 获取 pk 值
【发布时间】:2020-02-04 06:16:37
【问题描述】:

我一直在试图弄清楚如何使用详细视图 PK 过滤我的模板值。我有我的员工的详细视图。我希望显示我的员工的主题,然后我希望使用针对该主题进行的评估来过滤这些主题。

到目前为止,我已经可以显示我的主题名称,并显示每个主题的所有评估。但是,我不想显示所有这些我只想显示当前员工存在的那些(detailView PK)。正如您在我的模板中看到的那样,我使用 _set 来建立关系,但我不知道如何将 PK 过滤到该等式中。

例如,我想要什么:

主题一:

Evaluationname - 员工 Johnny

Evaluationname - 员工 Johnny

例如,我目前拥有的:

主题一:

Evaluationname - 员工 Johnny

Evaluationname - 员工 Chris

我不想要 Chris 的评价,我只想过滤主键,所以在这种情况下是 Johnny 的评价。

模板

{% for subject in subject_list %}
    <a href="">{{ subject.subejctname }}</a>
    {% for evaluation in subject.evaluation_set.all %}
        <div>
        <p>{{ evaluering.ma }} | {{ evaluering.ma.firstname }} | {{ evaluering.ma.lastname }}</p>
        </div>
    {% empty %}
        <p>No evaluations founds.</p>
    {% endfor %}
{% endfor %}

查看

class EmployeeDetailView(DetailView):
    template_name = 'evalsys/employee/alle_employees_eval.html'
    model = Employee

    # Uses employee PK to make a detail view
    def view_employee_with_pk(self, pk=None):
        if pk:
            employee = Employee.objects.get(pk=pk)
        else:
            employee = self.employee
        args = {'employee': employee, }
        return render(self, 'evalsys/employee/alle_employees_eval.html', args)

    def get_context_data(self, **kwargs):
        context = super(EmployeeDetailViewDetailView, self).get_context_data(**kwargs)
        context['subject_list'] = Subject.objects.all()
        return context

主题模型

class Subject(models.Model):
   id = models.AutoField(primary_key=True)
   subjectname = models.CharField(max_length=255, help_text="Indtast navnet på faget.")
   slug = models.SlugField(max_length=200, unique=True)

评估模型

class Evaluation(models.Model):
   id = models.AutoField(primary_key=True)
   employee_num = models.ForeignKey('Employee', on_delete=models.CASCADE, null=True)
   subjectname = models.ForeignKey('Subject', on_delete=models.CASCADE, null=True)

员工模型

class Employee(models.Model):
   id = models.AutoField(primary_key=True)
   slug = models.SlugField(max_length=200)
   employee_num = models.IntegerField(help_text="Indtast medarbejderens MA-nummer. (F.eks 123456)")
   firstname = models.CharField(max_length=30, help_text="Indtast medarbejderens fornavn.")
   lastname = models.CharField(max_length=30, help_text="Indtast medarbejderens efternavn.")
   subjectname = models.ForeignKey('Subject', on_delete=models.CASCADE, null=True)

【问题讨论】:

    标签: django django-models django-templates django-views django-queryset


    【解决方案1】:

    反向关系 (subject.evaluation_set) 可以是 prefetched,这是一种在访问查询集中许多对象的反向关系时减少数据库查询次数的技术。使用以下查询集时,当您访问 subject.evaluation_set.all 时,它不会执行额外的数据库访问,因为结果已经缓存在每个实例上

    Subject.objects.all().prefetch_related('evaluation_set')
    

    可以使用Prefetch 对象修改此缓存结果。使用这些您可以将subject.evaluation_set.all 的内容限制为仅包含您想要的结果

    Subject.objects.all().prefetch_related(
        Prefetch(
            'evaluation_set',
            queryset=Evaluation.objects.filter(employee=self.employee)
        )
    )
    

    【讨论】:

    • 谢谢,有道理,我知道我需要一些额外的过滤,但不知道预取。我不太明白这个逻辑应该放在我的代码中的什么位置?我假设在视图中?
    • 我想通了,将它添加到上下文中,它与我的模板当前的外观一起工作。非常感谢。
    【解决方案2】:

    您的模型结构令人困惑。你能详细说明员工、主题和评估之间的关系吗?您提到您希望显示员工的主题,但通过您的模型结构,员工只能有一个主题,因为员工通过外键与主题相关。

    下面我建议对您的模型名称和模型结构进行一些更改,以便在模板中检索您的评估可能更有意义。随意询问有关您的模型设计的问题,因为这对于设计您的视图、模板等至关重要。

    有关模型命名约定,请参阅此处
    Django Foreign Key Reference
    Django Model Coding Style (PEP8)

    主题模型

    class Subject(models.Model):
       id = models.AutoField(primary_key=True)
       subject_name = models.CharField(max_length=255, help_text="Indtast navnet på 
        faget.")
       slug = models.SlugField(max_length=200, unique=True)
    

    员工模型

    class Employee(models.Model):
        id = models.AutoField(primary_key=True)
        slug = models.SlugField(max_length=200)
        employee_num = models.IntegerField(help_text="Indtast medarbejderens MA-nummer. (F.eks 123456)")
        first_name = models.CharField(max_length=30, help_text="Indtast medarbejderens fornavn.")
        last_name = models.CharField(max_length=30, help_text="Indtast medarbejderens efternavn.")
        subjects = models.ManyToManyField(Subject, related_name='employee', through='Evaluation')
    

    评估模型

    class Evaluation(models.Model):
       name = models.CharField(blank=True,max_length=50)
       employee = models.ForeignKey('Employee', on_delete=models.CASCADE)
       subject = models.ForeignKey('Subject', on_delete=models.CASCADE)
    

    因此假设一个员工可以有不同的主题,并且映射是通过使用多对多的直通模型定义的。

    然后你的 DetaiView 就可以了

    class EmployeeDetailView(DetailView):
        template_name = 'evalsys/employee/alle_employees_eval.html'
        model = Employee
    
        def get_context_data(self, **kwargs):
            context = super(EmployeeDetailViewDetailView, 
              self).get_context_data(**kwargs)
            context['evaluations'] = Evaluation.objects.filter(employee=self.object)
            return context
    

    模板

    {% for evaluation in evaluations %}
        <a href="">{{ evaluation.subject.subject_name }}</a>
        <p>{{ evaluation.name }} | {{ evaluation.employee.first_name }} |
           {{evaluation.employee.last_name }}</p>
    {% empty %}
        <p>No evaluations founds.</p>
    {% endfor %}
    

    【讨论】:

    • 感谢您的深入回复。这很有道理。我已经按照您的建议做了,现在我有了 self.object 用于员工评估,但我没有清楚地知道它们。每个评估都“标记”有一个主题名称,但是我将如何只显示一次主题名称以及该主题下的所有评估?
    • 您需要确定员工、科目和评价之间的关系。如果您想要一个主题的所有评估,您需要过滤掉带有主题 ID 的评估,然后您将获得您的结果集。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-08-06
    • 2019-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-05
    • 1970-01-01
    相关资源
    最近更新 更多