【问题标题】:django: how do I query based on GenericForeignKey's fields?django:如何根据 GenericForeignKey 的字段进行查询?
【发布时间】:2012-08-11 05:22:40
【问题描述】:

我是使用 GenericForeignKey 的新手,我无法让它在查询语句中工作。表格大致如下:

class Ticket(models.Model):
    issue_ct = models.ForeignKey(ContentType, related_name='issue_content_type')
    issue_id = models.PositiveIntegerField(null=True, blank=True)
    issue = generic.GenericForeignKey('issue_ct', 'issue_id')

class Issue(models.Model):
    scan = models.ForeignKey(Scan)

扫描创建一个问题,一个问题生成一些票,我将问题作为 Ticket 表的外键。现在我有一个 Scan 对象,我想查询与此扫描相关的所有票证。我首先尝试了这个:

tickets = Tickets.objects.filter(issue__scan=scan_obj)

这是行不通的。然后我尝试了这个:

issue = Issue.objects.get(scan=scan_obj)
content_type = ContentType.objects.get_for_model(Issue)
tickets = Tickets.objects.filter(content_type=content_type, issue=issue)

还是不行。我需要知道如何在 django 中进行此类查询?谢谢。

【问题讨论】:

    标签: django generic-foreign-key


    【解决方案1】:

    可以通过创建与Ticket 共享db_table 的第二个模型来过滤GenericForeignKey。首先将 Ticket 拆分为抽象模型和具体模型。

    class TicketBase(models.Model):
        issue_ct = models.ForeignKey(ContentType, related_name='issue_content_type')
        issue_id = models.PositiveIntegerField(null=True, blank=True)
    
        class Meta:
            abstract = True
    
    class Ticket(TicketBase):
        issue = generic.GenericForeignKey('issue_ct', 'issue_id')
    

    然后创建一个也继承TicketBase 的模型。除了issue 被定义为ForeignKey 之外,这个子类将具有所有相同的字段。添加自定义 Manager 允许将其过滤为仅单个 ContentType

    由于这个子类不需要同步或迁移,它可以使用type()动态创建。

    def subclass_for_content_type(content_type):
        class Meta:
            db_table = Ticket._meta.db_table
    
        class Manager(models.Manager):
            """ constrain queries to a single content type """
            def get_query_set(self):
                return super(Manager, self).get_query_set().filter(issue_ct=content_type)
    
        attrs = {
            'related_to': models.ForeignKey(content_type.model_class()),
            '__module__': 'myapp.models',
            'Meta': Meta,
            'objects': Manager()
        }
       return type("Ticket_%s" % content_type.name, (TicketBase,), attrs)
    

    【讨论】:

      【解决方案2】:

      您定义的Ticket.issue 字段将帮助您从Ticket 实例转到它所附加的Issue,但它不会让您倒退。您已接近第二个示例,但您需要使用 issue_id 字段 - 您无法在 GenericForeignKey 上查询(它只是帮助您在拥有 Ticket 实例时检索对象)。试试这个:

      from django.contrib.contenttypes.models import ContentType
      
      issue = Issue.objects.get(scan=scan_obj)
      tickets = Ticket.objects.filter(
          issue_id=issue.id,
          issue_ct=ContentType.objects.get_for_model(issue).id
          )
      

      【讨论】:

      • @girasquid issue_id 非常混乱,因为它可以引用问题中的字段 issue_id 或问题中问题字段的 id 属性,我们可以区分它们吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-09
      • 2015-10-09
      相关资源
      最近更新 更多