2009-07-10 22 views
5

He estado babeando sobre Django todo el día mientras codificaba un sitio web interno en un tiempo récord, pero ahora me doy cuenta de que algo es muy ineficiente con mis ForeignKeys en el modelo.Muchas consultas de los campos django foreignkey

Tengo un modelo que tiene 6 ForeignKeys, que son básicamente tablas de búsqueda. Cuando consulto todos los objetos y los visualizo en una plantilla, se ejecutan alrededor de 10 consultas por artículo. Aquí hay un código, que debería explicarlo mejor:

class Website(models.Model): 
    domain_name = models.CharField(max_length=100) 
    registrant = models.ForeignKey('Registrant') 
    account = models.ForeignKey('Account') 
    registrar = models.ForeignKey('Registrar') 
    server = models.ForeignKey('Server', related_name='server') 
    host = models.ForeignKey('Host') 
    target_server = models.ForeignKey('Server', related_name='target') 

class Registrant(models.Model): 
    name = models.CharField(max_length=100) 

... y 5 tablas más simples. Hay 155 registros del sitio web, y en la vista que estoy usando:

Website.objects.all() 

Termina ejecutando 1544 consultas. En la plantilla, estoy usando todos los campos extranjeros, como en:

<span class="value">Registrant:</span> <a href="/filter/registrant/{{ website.registrant.id }}">{{ website.registrant.name }}</a><br /> 

así que sé que va a ejecutar una gran cantidad de consultas ... pero parece que esto es excesivo. ¿Esto es normal? ¿No debería hacerlo de esta manera?

Soy bastante nuevo para Django, así que espero estar haciendo algo estúpido. Definitivamente es un marco bastante sorprendente.

Respuesta

5

Debe usar select_related function, p. Ej.

Website.objects.select_related() 

modo que lo hará automáticamente una combinación y sigue todas las claves externas cuando la consulta se realiza en lugar de cargarlos en la demanda, ya que se utilizan. Django carga datos desde la base de datos con pereza, así que por defecto se obtiene el siguiente comportamiento

# one database query 
website = Website.objects.get(id=123) 

# first time account is referenced, so another query 
print website.account.username 

# account has already been loaded, so no new query 
print website.account.email_address 

# first time registrar is referenced, so another query 
print website.registrar.name 

y así sucesivamente. Si usa los elementos relacionados seleccionados, se realiza una unión entre bastidores y todas estas claves externas se siguen y se cargan automáticamente en la primera consulta, por lo que solo se realiza una consulta en la base de datos. Por lo tanto, en el ejemplo anterior, obtendrá

# one database query with a join and all foreign keys followed 
website = Website.objects.select_related().get(id=123) 

# no additional query is needed because the data is already loaded 
print website.account.username 
print website.account.email_address 
print website.registrar.name 
+0

¡Gracias! Eso definitivamente tiene mucho sentido para tener esa función. Ahora está ejecutando 9 consultas. Como las tablas son pequeñas, no me importa que estén cargando todos los datos (y obviamente es mucho mejor). –