Django模型-如何过滤ForeignKey对象的数量

发布于 2021-01-29 15:07:27

我有一个模型AB,就像这样:

class A(models.Model):
  title = models.CharField(max_length=20)
  (...)

class B(models.Model):
  date = models.DateTimeField(auto_now_add=True)
  (...)
  a = models.ForeignKey(A)

现在我有了一些AB对象,我想得到一个查询,该查询选择所有指向A少于2的对象B

A就像一个池子,用户(B)加入池。如果仅加入1或0,则根本不应该显示该池。

这样的模型设计可能吗?还是我应该修改一下?

关注者
0
被浏览
102
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    听起来像是一份工作extra

    A.objects.extra(
        select={
            'b_count': 'SELECT COUNT(*) FROM yourapp_b WHERE yourapp_b.a_id = yourapp_a.id',
        },
        where=['b_count < 2']
    )
    

    如果B计数通常是您需要的过滤或排序标准,或者需要显示在列表视图中,则可以考虑通过将b_count字段添加到A模型并在添加B或添加B时使用信号对其进行更新来考虑非规范化已删除:

    from django.db import connection, transaction
    from django.db.models.signals import post_delete, post_save
    
    def update_b_count(instance, **kwargs):
        """
        Updates the B count for the A related to the given B.
        """
        if not kwargs.get('created', True) or kwargs.get('raw', False):
            return
        cursor = connection.cursor()
        cursor.execute(
            'UPDATE yourapp_a SET b_count = ('
                'SELECT COUNT(*) FROM yourapp_b '
                'WHERE yourapp_b.a_id = yourapp_a.id'
            ') '
            'WHERE id = %s', [instance.a_id])
        transaction.commit_unless_managed()
    
    post_save.connect(update_b_count, sender=B)
    post_delete.connect(update_b_count, sender=B)
    

    另一种解决方案是在添加或删除相关的B时管理A对象上的状态标志。

    B.objects.create(a=some_a)
    if some_a.hidden and some_a.b_set.count() > 1:
        A.objects.filter(id=some_a.id).update(hidden=False)
    
    ...
    
    some_a = b.a
    some_b.delete()
    if not some_a.hidden and some_a.b_set.count() < 2:
        A.objects.filter(id=some_a.id).update(hidden=True)
    


知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看