Consultas en Django


Unos pequeños apuntes cogidos al vuelo de consultas en django

Un queryset sería el equivalente a un SELECT
Un filter sería el equivalente a un WHERE
Comandos de Query:
Objeto.objects.all() -> Todo el conjunto
Objeto.objects.filter() -> Un filtro para incluir
Objeto.objects.exclude() -> Un filtro para excluir
Objeto.objects.get() -> Busca un solo objeto

Encadenado de filtros

Entry.objects.filter(
headline__startswith=’What’
).exclude(
pub_date__gte=datetime.now()
).filter(
pub_date__gte=datetime(2005,1,1)
)
Todos los que empiezan por What entre 1/1/2005 y ahora.

Cada filtro crea una consulta única

q1=Entry.objects.filter(headline__startswith=’What’)
q2=q1.exclude(pub_date__gte=datetime.now())
q3=q2.filter(pub_date__gte=datetime(2005,1,1))

Buscar un solo objeto con get()

one_entry=Entry.objects.get(pk=1)
Si no hay datos salta la excepción DoesNotExist
from django.core.exceptions import ObjectdoesNotExist
try:
one_entry=Entry.object.get(pk=numero)
except ObjectDoesNotExist, e:
mensaje=("La entrada %n no existe" % (numero))






En cambio filter()[0], no hace saltar ninguna excepción.

Limitar el número de registros devueltos

Entry.objects.all()[:5] # los cinco primeros
Entry.objects.all()[5:10] # del quinto al décimo

Buscar sobre campos

Básicos: Son de la forma campo__tipobusqueda=valor
Ejemplo: Entry.objects.filter(pub_date___lte=’2006-01-01’) se transforma en select from blog_entry where pub_date<=’2006-01-01’
-> exact : headline__exact=’algo’
-> iexact: case insentive exact
-> contains
-> startswith
-> endswith

Relacionales

Entry.objects.filter(blog__name__exact=’Pep’)
Blogs.objects.filter(entry__headline__contains=’Pep’, entry__pub_date__year=2006)
Todos los blogs que tengan alguna entrada cuyo titulo tenga Pep y se haya publicado en 2006
Blogs.objects.filter(entry__headline__contains=’Pep’).filter(entry__pub_date__year=2006)
Todos los que tengan Pep y todos los que se hayan publicado en 2006

Filtros que referencian a otros campos del mismo modelo

from django.db.models import F
Entry.objects.filter(n_coments__gt=F(‘n_pingbacks’))
gt: greather than
n_pingbacks: valor de otro campo del mismo modelo

Primary key

Blog.objects.get(pk=valor)
.get(pk__in=[1,4,7])
.get(pk__gt=14)

Caching

Esta consulta se realiza dos veces:
print [e.headline from p in queryset]
print [e.pub_date from p in queryset]
Esta, sólo una vez (cacheo de resultados):
queryset=Entry.objects.all()
print [p.headline form p in queryset] <- En esta se cachea
print [p.pub_date form p in queryset] <- en esta su usa la caché

Consultas complejas con Q

Las palabras clave en filter, etc... son ANDs, si queremos algo más complejo, necesitamos Qs
django.db.models.Q
Q(question__startswith=’Who’) | Q(question__startswith=’What’)
Q(question__startswith=’Who’) | ~Q(question__startswith=’What’)
Poll.objects.get( Q(question__startswith=’Who’),
Q(pub_date=date(2005,5,2)) | Q(pub_date=date(2005,5,6)) )

Comparando objetos

Para comparar dos objetos usamos el == estándar de python
una_entrada==otra_entrada
La comparación se realiza siempre usando la clave primaria

Borrando objetos

Entry.objects.filter(pub_date__year=2005).delete()
Borra todos los elementos y los foreign key que le apuntan en cascada
b=Blogs.objects.get(pk=1)
b.delete() -> borra la entrada y todos sus comentarios

Update de varios elementos

Entry.objects.filter().update(headline=’Cambiado’)

Objetos relacionados

Si un modelo tiene un foreign key, podemos acceder al objeto foráneo via simple atributo del modelo:
e=Blog.objects.get(id=1)
e.entry_set.all() --> todas las entradas del primer blog
e.entry_set.filter(headline__contains=’Pep’)
Si se ha usado el related_name en la definición del modelo, entonces ese es el nombre del atributo para acceder
blog=ForeignKey(Blog, related_name=’entries’)
b=Blog.objects.get(id=1)
b.entries.all()
b.entries.count()
Métodos del Foreign Manager:
relacionado.add(ob1, obj2, …) Añade al objeto relacionado
relacionado.create(**kwargs)
relacionado.remove(obj1, obj2, …)
relacionado.clear() -> borra todos los objetos relacionados
O también:
b=Blog.objects.get(id=1)
b.entry_set=[e1, e2, …] <- un objeto iterable
Hacer siempre el save del objeto principal para que permanente.