我是使用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中进行这些查询?感谢。
答案 0 :(得分:65)
您定义的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))
答案 1 :(得分:15)
通过创建与GenericForeignKey
共享db_table
的第二个模型,可以跨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')
然后创建一个也是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)