2012-02-08 17 views
12

tengo un modelo que tiene una única genérica relación de clave externa:Revertir una clave externa genérica única (y devolver un objeto en lugar de un gerente relacionados)

class Contact(models.Model): 
    ... 
    content_type = models.ForeignKey(ContentType) 
    object_id = models.PositiveIntegerField() 
    content_object = generic.GenericForeignKey() 

    class Meta: 
     unique_together = ('content_type', 'object_id',) 

lo que significa que un Contact tan sólo puede pertenecer a un objeto Por lo general, cuando quiero revertir la relación que pueda hacer

class Person(models.Model): 
    ... 
    contacts = generic.GenericRelation(Contact) 

y llamando person.contacts.all() me dará todos los objetos. Debido a que solo se devolverá una sola Contact en mi situación, ¿hay una forma mejor de acceder a este objeto al revés?

p.s. Podría escribir person.contact.all()[0] pero tiene que haber un enfoque más limpio

+0

duplicados Posible de http: // stackoverflow .com/questions/4893823/how-can-i-make-and-enforce-a-generic-onetoone-relation-in-django –

+0

Sé que la respuesta a mi pregunta es (o parece ser) en los comentarios, pero la pregunta en sí es diferente (gracias por el enlace, echaré un vistazo ahora) –

+0

Por lo tanto "posible";) –

Respuesta

12

Bueno, mirando a la cuestión en el comentario de Chris ayudó, y me escribió un mixin para devolver el objeto utilizando una búsqueda rápida (que debe ser almacenado en caché):

class ContactMixin(object): 
    @property 
    def contactcard(self): 
     ctype = ContentType.objects.get_for_model(self.__class__) 
     try: 
      contact = Contact.objects.get(content_type__pk = ctype.id, object_id=self.id) 
     except Contact.DoesNotExist: 
      return None 
     return contact 

y la Persona:

class Person(ContactMixin, models.Model): 
    ... 

ahora puedo simplemente llamar

myperson.contactcard.phone_number 

no voy a aceptar por el momento, ya que puede haber otras sugerencias

+2

En general, es una buena práctica especificar las excepciones que espera (en este caso doesnotexists y multipleobjectsreturned). De esta forma no terminas ocultando otras excepciones que probablemente quieras burbujear – second

+0

. Tengo el mismo problema y al mirar esta solución, no creo que 'select_related' ni' prefetch_related' trabajen en esto :(Se obtendría costoso muy rápido para obtener la propiedad 'contactcard' para un queryset grande. – user193130

5

si un conjunto de consultas contiene exactamente un elemento que puede hacer qs.get(), o en su caso

person.contact.get() 

(es posible que tenga que detectar la excepción DoesNotExists)

+1

Interesante, no lo sabía. Unfortunatley 'person.contact' devuelve un objeto Manager/GenericRelation por lo que aún necesitaría usar' person.contacts.all.get', que es igualmente engorroso –

Cuestiones relacionadas