2012-08-14 8 views
39

Sono nuovo nell'utilizzo di GenericForeignKey e non sono riuscito a farlo funzionare in una dichiarazione di query. I tavoli sono più o meno simile al seguente:django: come faccio a interrogare in base ai campi di 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) 

Una scansione crea un problema, un problema genera alcuni biglietti, e ho fatto questione come una chiave esterna a tavola biglietteria. Ora ho un oggetto Scan e voglio interrogare tutti i ticket relativi a questa scansione. Ho provato prima questo:

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

che non funziona. Poi ho provato questo:

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) 

Ancora non funziona. Devo sapere come fare questo tipo di domande in django? Grazie.

risposta

57

Il Ticket.issue campo avete definito vi aiuterà a passare da un'istanza Ticket al Issue è attaccato, ma non vi lascerà andare all'indietro. Sei vicino al tuo secondo esempio, ma devi usare il campo issue_id - non puoi eseguire una query su GenericForeignKey (ti aiuta semplicemente a recuperare l'oggetto quando hai un'istanza Ticket). Prova questo:

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)) 
+3

Salvato il mio giorno, amico mio, sono praticamente senza peli dopo aver provato a capirlo. Grazie :) . –

+0

@girasquid issue_id è molto confuso in quanto può riferirsi al campo issue_id in questione o all'attributo id del campo di emissione nella domanda, possiamo renderli distinguibili? – rohanagarwal

14

filtraggio attraverso un GenericForeignKey lattina con la creazione di un secondo modello che condivide il db_table con Ticket. Prima dividi il biglietto in un modello astratto e in un modello concreto.

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') 

quindi creare un modello che le sottoclassi anche TicketBase. Questa sottoclasse avrà tutti gli stessi campi tranne issue che è invece definita come ForeignKey. L'aggiunta di una personalizzata Manager consente di filtrarla su un singolo ContentType.

Poiché questa sottoclasse non ha bisogno di essere sincronizzata o migrata, può essere creata dinamicamente usando 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) 
+0

Questo è molto, molto intelligente .. –

Problemi correlati