2011-03-02 9 views
8

Tengo una aplicación Django con el siguiente modelo:Captación de objetos del modelo heredado de Django

objeto Un es un objeto simple que se extiende desde Modelo con algunos campos, y digamos, una en particular es un campo Char llamado "NOMBRE" y un campo Entero llamado "PEDIR". Un es abstracto, es decir, no hay A objetos en la base de datos, pero en su lugar ...

Objetos B y C son especializaciones de Un, lo que significa que heredan de Un y ellos agregan algunos otros campos.

Ahora supongamos que necesito todos los objetos cuyo campo NOMBRE comenzar con la letra "Z", ordenada por el campo ORDEN, pero quiero que todos los B y C campos específicos de demasiado para esos objetos. Ahora veo 2 enfoques:

a) Hacer las consultas de forma individual para B y C objetos a buscar dos listas, fusionarlas, orden manualmente y trabajar con eso.

b) Consulta A objetos para los nombres que comienzan con "Z" ordenado por "ORDEN" y con la consulta resultado la B y C objetos para llevar a todos los datos restantes.

Ambos enfoques suenan muy ineficientes, en el primero tengo que encargarlos yo mismo, en el segundo tengo que consultar la base de datos varias veces.

¿Hay una manera mágica que me falta para recuperar todos los B y C objetos, ordenados en un solo método? ¿O al menos una forma más eficiente de hacer esto que las dos mencionadas?

¡Gracias de antemano!

Bruno

+1

Bienvenido a la herencia del modelo Django. Disfruta tu estancia. –

Respuesta

5

Si A puede ser concreto, puede hacerlo todo en una consulta usando select_related.

from django.db import connection 
q = A.objects.filter(NAME__istartswith='z').order_by('ORDER').select_related('b', 'c') 
for obj in q: 
    obj = obj.b or obj.c or obj 
    print repr(obj), obj.__dict__ # (to prove the subclass-specific attributes exist) 
print "query count:", len(connection.queries) 
+0

Inteligente. Horrible, pero inteligente. ¿No funcionará cuando A sea abstracto? – Wogan

+0

Correcto, solo herencia de tablas múltiples. – DrMeers

+0

Ah, me las arreglé para omitir la frase "A es abstracto" en mi lectura inicial ... – DrMeers

0

Consulta mediante su método de "b", le permitirá a usted a "traer" todos los datos restantes sin consultar a su B y C modelos por separado. Puede usar la relación "nombre de modelo en minúscula".

http://docs.djangoproject.com/en/dev/topics/db/models/#multi-table-inheritance

for object in A.objects.filter(NAME__istartswith='z').order_by('ORDER'): 
    if object.b: 
     // do something 
     pass 
    elif object.c: 
     // do something 
     pass 

Es posible que tenga que probar y salvo excepciones DoesNotExist. Estoy un poco oxidado con mi django. Buena suerte.

+0

Sí, necesitaría atrapar 'DoesNotExist', y cada intento de acceder a un objeto relacionado (exitoso o no) le costará una consulta adicional, terriblemente ineficiente. – DrMeers

0

Así que mientras usted pida ambas consultas sobre B y C, es bastante fácil de fusionarlos sin tener que hacer un complejo caro:

# first define a couple of helper functions 

def next_or(iterable, other): 
    try: 
     return iterable.next(), None 
    except StopIteration: 
     return None, other 

def merge(x,y,func=lambda a,b: a<=b): 
    ''' merges a pair of sorted iterables ''' 
    xs = iter(x) 
    ys = iter(y) 
    a,r = next_or(xs,ys) 
    b,r = next_or(ys,xs) 
    while r is None: 
     if func(a,b): 
      yield a 
      a,r = next_or(xs,ys) 
     else: 
      yield b 
      b,r = next_or(ys,xs) 
    else: 
     if a is not None: 
      yield a 
     else: 
      yield b 
    for o in r: 
     yield o 

# now get your objects & then merge them 

b_qs = B.objects.filter(NAME__startswith='Z').order_by('ORDER') 
c_qs = C.objects.filter(NAME__startswith='Z').order_by('ORDER') 

for obj in merge(b_qs,c_qs,lambda a,b: a.ORDER <= b.ORDER): 
    print repr(obj), obj.__dict__ 

La ventaja de esta técnica es que funciona con una clase base abstracta.

Cuestiones relacionadas