django:我如何根据GenericForeignKey的字段进行查询?

Sha*_*ang 45 django generic-foreign-key

我是使用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)
Run Code Online (Sandbox Code Playgroud)

扫描会产生一个问题,一个问题会产生一些故障单,我将问题作为Ticket表的外键.现在我有一个Scan对象,我想查询与此扫描相关的所有故障单.我先试了一下:

tickets = Tickets.objects.filter(issue__scan=scan_obj)
Run Code Online (Sandbox Code Playgroud)

这不起作用.然后我尝试了这个:

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)
Run Code Online (Sandbox Code Playgroud)

仍然无法正常工作.我需要知道如何在django中进行这些查询?谢谢.

gir*_*uid 66

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))
Run Code Online (Sandbox Code Playgroud)

  • 保存了我的一天,我的朋友,在我试图解决这个问题之后,我基本没毛了.谢谢 :) . (4认同)

小智 15

GenericForeignKey通过创建共享db_tablewith 的第二个模型来过滤罐Ticket.首先将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(models.Model):
    issue = generic.GenericForeignKey('issue_ct', 'issue_id')
Run Code Online (Sandbox Code Playgroud)

然后创建一个也是子类的模型TicketBase.此子类将具有所有相同的字段,除了将issue其定义为a 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)
Run Code Online (Sandbox Code Playgroud)