【问题标题】:Django-filter and Django-tables2 Using a foreign attributeDjango-filter 和 Django-tables2 使用外部属性
【发布时间】:2018-01-31 15:18:40
【问题描述】:

我已经阅读了以前的问题,并尝试在文档中阅读,但我对此并没有真正的运气。

我正在使用 Django-tables2 来显示学生的数据。

表中的一列(当前排名)使用学生模型中的模型管理器的访问器填充,如下所示:

models.py

class Student(models.Model): 
#a bunch of fields
def get_current_standing(self):
        current_standing = AcademicStanding.objects.get(year=self.enrol_term, student=self).standing
        return current_standing

tables.py

class StudentTable(tables.Table):
    current_standing = tables.Column(accessor='get_current_standing')
    class Meta:
        model = Student
        fields = ["last_name", "first_name", "campus_id", "current_standing"] 

表格可以正确填充和显示,但排序依据会产生错误。我可以按如下方式调整 Column:

current_standing = tables.Column(accessor='get_current_standing', order_by='academicstanding.standing')

但是因为关系是 1:N,所以我得到了多个结果,其中(如学生模型中的经理所示),我只想要该特定入学年份的学生的学术地位。此方法也不会根据排名对条目进行分组。

最后,这种使用模型管理器作为访问器填充表的方法是否正确?为了启用正确的预期功能,我缺少什么?

【问题讨论】:

  • 如果您有多个问题,您应该发布多个问题。 :( 对于问题 1,您应该能够使用 .annotate() 而不是访问器,这将解决您的排序问题,并摆脱固有的 N+1 选择问题......但我不太确定如何做那种注释来发布答案。
  • @AdamBarnes 谢谢你。我认为将它们组合在一起会更好,并且可以更全面地了解我想要实现的目标。
  • 嗯...可能吗?也许我太仓促了,因为看起来这甚至可能不是两个问题,因为注释可以解决这两种情况......我不认为您可以将您的问题和一些示例数据放在存储库中?那么,我将尝试实施我所描述的内容。
  • @AdamBarnes 如果我理解正确,我只需将 .annotate(currentstanding='academicstanding__standing') 添加到过滤器的查询集中。但是我现在得到“str”对象没有属性“resolve_expression”-我在这里做错了什么?
  • 我真的不确定;这是我需要让我的手指粘在代码中才能理解的事情之一。现在让我拼凑一个玩具项目,看看我能做什么。

标签: python django django-tables2


【解决方案1】:

好的,这很有趣。如果你给我一个存储库会更快,但你提供了很多信息,所以我可以毫无困难地制作自己的。 :D 已完成here,(在撰写本文时提交e7f70e)。

为了整洁,我在QuerySets 中做了所有重要的事情,所以看看students/managers.py

在这里,您会看到我在上面的 cmets 中遇到问题的注释。我在下面将它翻译成更独立的东西:

Student.objects.annotate(current_standing=models.Subquery(
    AcademicStanding.objects \
        .filter(student=models.OuterRef('id')) \
        .filter(year__year=2018) \
        .values('standing'),
    )
)

适用于以下型号:

class Student(models.Model):
    name = models.CharField(max_length=20, ...)

    ...


class AcademicStanding(models.Model):
    student = models.ForeignKey(
        'students.Student',
        related_name='academic_standings',
        on_delete=models.CASCADE,
    )
    standing = models.PositiveIntegerField()
    year = models.DateField()

    ...

查询使用models.Subquery 来执行子查询,使用OuterRef 来引用当前行的id,这意味着每个Student 将获得与它们相关联的自己的AcademicStanding,而不是到集合中的第一个 AcademicStanding,没有那个过滤器。

我们的表定义如下,一切都“正常工作”,因为我们感兴趣的值现在原生在查询集上。所有性能也保持不变,因为这实际上是在数据库中完成的计算,而不是在 Python 中进行多个查询。

class StudentTable(tables.Table):

    class Meta:
        model = Student
        fields = ['name', 'current_standing']

我在此过程中学到的一件很酷的事情是关于RequestConfig。这是django-tables2 中的东西,它接受当前请求,并自动对它提供的表执行所需的操作以匹配 GET 参数等。您可以在here 中看到这一点。这对我来说是全新的。


对于您的问题 2 - 我怀疑您会发现使用我上面详述的注释更容易推理和实施,但如果不是,请发布另一个问题。

(这样我可以得到更多的答案点)。 :P

【讨论】:

  • 这行得通!我必须调整一些东西才能让它在当前设置中工作。我似乎无法让过滤器工作,对此有什么建议吗?
  • 老实说,我会提出一个新问题。我在上面的答案中写了很多,而且 - 在我看来 - 它非常彻底。需要添加更多内容当然感觉像是第二个问题。如果我先得到它,我会尽力回答你的新问题;也是。
  • 这很公平,我会这样做的。当我发布这个问题时,决定的权力只是在学生模型中创建一个额外的字段并运行一个脚本来导入最新的排名(不幸的是)。所以这个问题不再那么紧迫。我将编辑我上面的问题,以便您的回答完全回答问题。感谢您的帮助!
  • 也感谢您的耐心等待。
猜你喜欢
  • 2021-04-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-06
  • 1970-01-01
  • 2021-03-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多