Ik ben nieuw in het gebruik van GenericForeignKey, en ik kon het niet laten werken in een query-instructie. De tabellen zien er ongeveer als volgt uit:
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)
Een scan creëert één probleem, een probleem genereert enkele tickets en ik heb een probleem gemaakt als een externe sleutel voor de tickettabel. Nu heb ik een Scan-object en ik wil alle tickets opvragen die betrekking hebben op deze scan. Ik heb dit eerst geprobeerd:
tickets = Tickets.objects.filter(issue__scan=scan_obj)
wat niet werkt. Toen probeerde ik dit:
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)
Werkt nog steeds niet. Ik moet weten hoe ik dit soort vragen in django moet doen? Bedankt.
Antwoord 1, autoriteit 100%
Het veld Ticket.issue
dat je hebt gedefinieerd, helpt je om van een Ticket
-instantie naar het issue
te gaan waaraan het is gekoppeld, maar het laat je niet achteruit gaan. U bent in de buurt met uw tweede voorbeeld, maar u moet het veld issue_id
gebruiken – u kunt geen query uitvoeren op de GenericForeignKey
(het helpt u alleen het object op te halen wanneer u een Ticket
instantie hebben). Probeer dit:
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
)
Antwoord 2, autoriteit 21%
Filteren op een GenericForeignKey
kan door een tweede model te maken dat de db_table
deelt met Ticket
. Splits Ticket eerst op in een abstract model en een concreet model.
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')
Maak vervolgens een model dat ook TicketBase
subklassen. Deze subklasse heeft allemaal dezelfde velden behalve issue
die in plaats daarvan is gedefinieerd als een ForeignKey
. Door een aangepaste Manager
toe te voegen, kan deze worden gefilterd op slechts één ContentType
.
Aangezien deze subklasse niet hoeft te worden gesynchroniseerd of gemigreerd, kan deze dynamisch worden gemaakt met 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)