如何通过用户在Django模板上显示与反向引用的关系?

时间:2019-07-02 08:38:57

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

我有这样的模型

class Employee(models.Model):
    """Employee information."""
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='employee', unique=True)
    position = models.CharField("current position in a company", max_length=64, blank=True)
    birth_date = models.DateField("date of birth", null=True)
    skills = models.ManyToManyField(
        Technology, through="Skill", verbose_name="skills", blank=True)


class Technology(models.Model):
    """Technologies."""
    name = models.CharField('technology name', max_length=32, unique=True)

class Skill(models.Model):
    """Information about an employee's skills."""
    LEVELS = (
        ('basic', 'Basic'),
        ('intermediate', 'Intermediate'),
        ('advanced', 'Advanced'),
        ('expert', 'Expert'),
    )
    employee = models.ForeignKey(
        Employee, on_delete=models.CASCADE, related_name="employee_skills")
    technology = models.ForeignKey(Technology, on_delete=models.CASCADE)
    start_date = models.DateField(
        verbose_name='Works with since:')
    level = models.CharField("level", max_length=64, choices=LEVELS)

我不明白为什么我的模板代码不起作用

template.html

{{ user.employee.position }}
{{ user.employee.birth_date }}
{{ user.employee.summary }}

{% for i in  user.employee.skills.all %}
{{ i.technology.name }}
{{ i.level }}
{% endfor %}

我绝对看不到。所有型号都可以在adminpanel上看到。然后我使用诸如

的TemplateView
class AccountView(TemplateView):

    template_name = "profile.html"

    def get_context_data(self, **kwargs):
        context = super(AccountView, self).get_context_data(**kwargs)      
        context['skills'] = 
        Skill.objects.filter(employee__user=self.request.user)

        return context

然后一切正常。

2 个答案:

答案 0 :(得分:2)

您的员工模型当前与用户具有一对多关系

class Employee(models.Model):
    """Employee information."""
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='employee', unique=True)

根据您的评论,您需要一对一的关系,因此您需要将其更改为使用OneToOneField而不是ForeignKey

  

从概念上讲,这类似于具有unique = True的ForeignKey,但是关系的“反向”侧将直接返回单个对象。

答案 1 :(得分:2)

建模存在问题。您应该在OneToOneFieldEmployee之间使用User。本质上,OneToOneField唯一 ForeignKey。但是,它将更改某些逻辑,例如user.employee将访问相关的Employee对象,而不是QuerySet个对象中的Employee

class Employee(models.Model):
    # ...
    user = models.OneToOneField(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name='employee'
    )
    # ...

在您的AccountView中,您将'skills'与该员工的技能统一在一起,实际上是:

class AccountView(TemplateView):

    template_name = "profile.html"

    def get_context_data(self, **kwargs):
        context = super(AccountView, self).get_context_data(**kwargs)      
        context.update(
            skills=Skill.objects.filter(employee__user=self.request.user).select_related('technology')
        )
        return context

您可能想在这里使用.select_related(..)来防止所谓的“ N + 1问题”,其中对于每一项 技能,您都会多查询。

因此您可以通过以下方式呈现技能:

{% for skill in skills %}
    {{ skill.technology.name }}
    {{ skill.level }}
{% endfor %}

或者您可以通过以下方式访问:

{% for skill in request.user.employee.employee_skills.all %}
    {{ skill.technology.name }}
    {{ skill.level }}
{% endfor %}

尽管上述方法不太安全,因为User可能没有相关的Employee对象。