You are on page 1of 122

pdfcrowd.com open in browser PRO version Are you a developer?

Try out the HTML to PDF API


Escribiendo tu primer parche para Django
Interesado en dar a la comunidad un poco? Tal vez encontraste un fallo en Django que te gustara
corregir, o tal vez hay una pequea caracterstica que te gustara aadir.
Las contribuciones son en s mismo la mejor manera de abordar y ver nuestras propias
preocupaciones retribuidas a Django en s. Esto puede parecer un poco intimidante al principio, pero
en realidad es bastante simple. Esta gua te guiara te llevara a travs de todo el proceso, por lo que
puedes aprender con el ejemplo.
Para este tutorial, esperamos que tengas por lo menos un conocimiento bsico de la forma en que
funciona Django. Esto quiere decir que deves ir poco a poco aprendiendo de una forma cmoda sobre
los tutoriales existentes: Tu primera aplicacion en Django. Adems, tambien necesitas poseer una buena
comprensin de Python o al menos entender la forma en que funciona. Pero si no la tienes no te
preocupes puedes leerDive Into Python que es un fantstico (y gratis) libro en lnea para comenzar a
programar en Python.
Aquellos de ustedes que no estn familiarizados con los sistemas de control de versiones tipo Trac, git
30
DEC
Introduccin
Qu esperamos de este tutorial?
Plantilla Dynamic Views. Con la tecnologa de Blogger.
Django Portada Tutoriales Classic
Django, Todo lo que quieres saber y algo m
buscar
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
encontrarn que este tutorial y sus vnculos incluyen informacin suficiente para empezar. Sin
embargo, es probable que quieras leer un poco ms acerca de estas herramientas diferentes entre si,
si es que vas a contribuir a Django con regularidad.
En su mayor parte, este tutorial trata de explicar tanto como sea posible, de modo que pueda ser de
utilidad en audiencias ms amplias.
Dnde obtener ayuda:
Si ests teniendo problemas a travs de este tutorial, por favor envia un mensaje
a django-developers o a travs del chat #django-dev on irc.freenode.net para chatear con otros
usuarios de Django que podrn resolver tus dudas y ayudarte.
A lo largo de este tutorial cubriremos la forma de contribuir con un parche para Django por primera
vez. Al final de este tutorial, debes tener un conocimiento bsico tanto de la las herramientas y los
procesos involucrados en el proceso. En concreto, vamos a estar cubriendo los siguientes temas:
La instalacin de Git.
Cmo descargar una copia de desarrollo de Django.
Ejecutar un paquete de pruebas en Django.
Redactar una prueba para su revisin.
Escribir el cdigo para una revisin.
Testear un parche.
Generacin de un archivo de revisin de cambios.
Dnde buscar ms informacin?.
Una vez que hayas terminado con el tutorial, puedes buscar a travs del resto de la
documentacion:Django's documentation on contributing. Contiene gran cantidad de informacin y es
Qu cubre este tutorial?
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
una lectura obligada para cualquier persona que quiera convertirse en un colaborador habitual de
Django. Si tienes preguntas, es probablemente que alli estn las respuestas.
Para este tutorial, necesitamos instalar Git para descargar la versin actual de desarrollo de Django y
generar archivos de revisin para posteriormente hacer los cambios.
Para comprobar si tienes o no instalado Git, introduce el siguiente comando en la terminal asi: git. Si
recibes un mensajes diciendo que el comando no puede ser encontrado, tendrs primero que
descargarlo e instalarlo, consulta la seccin Gits download page para mas informacin.
Si no ests familiarizado con Git, siempre puedes encontrar ms informacin sobre su comandos (una
vez instalado) escribiendo git help en la lnea de comandos.
El primer paso para contribuir a Django es obtener una copia del cdigo fuente. Desde la lnea de
comandos, utiliza el comando cd para navegar hasta el directorio donde quieras almacenar una copia
local de Django.
Descarga el cdigo fuente desde el repositorio de Django con el siguiente comando:
git clone https://github.com/django/django.git
Note
Para los usuarios que deseen usar virtualenv, puede utilizar:
pip install -e /path/to/your/local/clone/django/
Para asi enlazar el directorio clonado con el entorno virtual. Esta es un gran opcin, aislar
Instalar Git
Obtener una copia de la versin de desarrollo de Django
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
la copia de desarrollo de Django del resto de su sistema y evitar posibles conflictos entre
paquetes.
Para este tutorial, vamos a utilizar el ticket #17549 como caso de estudio, por lo que vamos a retroceder
en la versin de git y en la historia de Django antes de de aplicar el ticket para el parche. Esto nos
permitir pasar por todos los pasos necesarios para escribir ese parche desde cero, incluyendo la
ejecucin de un conjunto de pruebas para Django.
Ten en cuenta que, vamos a estar utilizando una versin del tronco de Django antigua para los
efectos de este tutorial, siempre se debe utilizar la revisin de desarrollo actual de Django cuando
se trabaja en un parche de un ticket!
Note
El parche para esta entrada fue escrita por Ulrich Petri, y se aplic a Django como commit
ac2052ebc84c45709ab5f0f25e685bf656ce79bc. Por lo tanto, vamos a aprovechar la revisin de
Django justo antes de aplicar el commit 39f5bc7fc3a4bb43ed8a1358b17fe0521a1a63ac.
Navega a el directorio raz de Django (que es el que contiene django, docs, tests, AUTHORS, etc.). A
continuacin, puedes checar la mayor parte de las revisiones de Django que vamos a utilizar a
continuacin en el tutorial:
git checkout 39f5bc7fc3a4bb43ed8a1358b17fe0521a1a63ac
Al contribuir a Django es muy importante que los cambios en el cdigo no introduzcan mas errores en
otras reas de Django. Una forma de comprobar que Django trabaja despus de realizar los cambios
Retornar a una revisin previa de Django
Ejecutando un conjunto de pruebas Django por primera vez
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
es mediante la ejecucin de una suite de pruebas. Si todas las pruebas pasan, entonces se puede
estar razonablemente seguro de que los cambios no han roto completamente a Django. Si nunca has
ejecutado una suite de pruebas de Django antes, es una buena idea ejecutarla una vez antes slo
para familiarizarse con la forma en que se comporta y con la salida que aparece.
Podemos ejecutar el conjunto de pruebas, simplemente situndonos con el
comandocd `` en el directorio ``tests/, si ests usando GNU/Linux, Mac OS X o algn otro sabor
de Unix, puedes ejecutar:
PYTHONPATH=.. python runtests.py --settings=test_sqlite
Si ests en Windows, lo anterior debera funcionar siempre y cuando ests utilizando Git Bash que
es proporcionado por la instalacin Git por defecto. GitHub tiene un tutorial muy bueno en nice tutorial.
Note
Si utilizas virtualenv, puede omitir PYTHONPATH=.. cuando ejecutes las pruebas. Esto
indica a Python que busque a Django en el directorio padre de
pruebas tests. virtualenv pone su copia de Django en el PYTHONPATH automticamente.
Ahora sintate y reljate un poco. Todo el conjunto de pruebas de Django cuenta con ms de 4800
diferentes pruebas, por lo que puede tardar entre 5 y 15 minutos en ejecutarse, en funcin de la
velocidad de tu ordenador.
Mientras la suite de pruebas de Django se est ejecutando, vers una secuencia de caracteres que
representa el estado de cada prueba como es ejecutado. E indica que un error fue lanzado durante
una prueba y F indica que una de las afirmaciones de prueba ha fallado. Ambos se consideran fallos de
prueba. Mientras tanto, x y s indican fallas esperadas y las pruebas omitidas, respectivamente. Los
puntos indican que se pasaron las pruebas.
Las pruebas que suelen ser omitidos son debido a que faltan bibliotecas externas necesarias para
ejecutar la prueba, puedes ver running-unit-tests-dependencies para obtener una lista de las
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
dependencias y asegurarte de instalar cualquiera de las bibliotecas faltantes para las pruebas
relacionadas con los cambios que se est haciendo (que no necesitaremos ninguna para este tutorial).
Una vez que se completan las pruebas, recibiremos un mensaje informndonos si el conjunto de
pruebas aprob o no. Dado que an no se ha realizado ningn cambio a el cdigo de Django, la
prueba de toda la suite debera aprobar. Si obtienes fallas o errores asegurarte de que has seguido
todos los pasos anteriores correctamente. Puedes ver running-unit-tests para ms informacin.
Ten en cuenta que el tronco (trunk) de Django puede no ser estable siempre. Cuando desarrollamos
en el tronco, podemos comprobar en Djangos continuous integration builds y determinar si los errores son
especficos de la mquina en que estamos trabajando o si tambin estn presenten en las versiones
oficiales de Django. Si das clic en una vista en particular, se puede ver la Matriz de configuracin,
que muestra las fallas desglosados por el tipo de versin de Python y la base de datos back-end
usada.
Note
Para este tutorial y ticket en que estamos trabajando, las pruebas son usando como base
de datos SQLite, sin embargo, es posible (y, a veces es necesario) para run the tests
using a different database usar diferentes bases de datos.
En la mayora de los casos, para ser aceptado un parche en Django este tiene que incluir pruebas.
Para parches de correccin de errores, esto significa escribir una prueba de regresin para asegurar
que el bug no vuelva a ser reintroducido en Django mas adelante. Una prueba de regresin debera
ser escrita de tal manera que produzca un error, mientras que todava existe el error y pasar una vez
que el error se halla corregido. Para los parches con nuevas caractersticas, debern ser incluidas
pruebas que garanticen que las nuevas caractersticas funcionan correctamente. Ellos tambin
deberan fallar cuando la nueva caracterstica no est presente, y luego pase una vez que se halla
aplicado el parche.
Escribir algunas pruebas para el ticket
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
Una buena manera de hacer esto es escribir las nuevas pruebas en primer lugar, antes de hacer
cualquier cambio en el cdigo. Este estilo de desarrollo es llamado test-driven development y se puede
aplicar tanto en proyectos completos y parches individuales. Despus de escribir las pruebas, a
continuacin, las ejecutamos para asegurarnos que de no se han hecho cambios (ya que no se han
fijado ese error o aadido todava esa caracterstica). Si las nuevas pruebas no fallan, tendrs que
arreglarlas para que lo hagan. Despus de todo, un anlisis de regresin que pasa sin importar si un
error est presente no es muy til en la prevencin de estos errores si se repita en el futuro.
Ahora, para nuestro ejemplo prctico.
El Ticket #17549 describe la suma de la siguiente, pequea caracterstica:
Es til para un campo URLField para darle una forma de abrir la direccin URL, de lo contra
rio
puede ser que tambin se utilice un CharField.
Con el fin de resolver este ticket, vamos a aadir un mtodo render para el
widget AdminURLFieldWidgetcon el fin de mostrar un vnculo al hacer clic encima de la entrada del
widget. Antes de realizar estos cambios, sin embargo, vamos a escribir un par de ensayos para
comprobar que nuestras funciones de modificacin funcionan correctamente y que continuara
funcionando correctamente en el futuro.
Navega hasta el directorio de Django tests/regressiontests/admin_widgets/ y abre el
archivo test.py. Agrega el siguiente cdigo justo en la lnea 269 antes de la
clase AdminFileWidgetTest
class AdminURLWidgetTest(DjangoTestCase):
def test_render(self):
w = widgets.AdminURLFieldWidget()
self.assertHTMLEqual(
conditional_escape(w.render('test', '')),
'<input class="vURLField" name="test" type="text" />'
Escribiendo algunas pruebas para el ticket #17549
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
)
self.assertHTMLEqual(
conditional_escape(w.render('test', 'http://example.com')),
'<p class="url">Currently:<a href="http://example.com">http://example.com</a><b
r />Change:<input class="vURLField" name="test" type="text" value="http://example.com" /></
p>'
)
def test_render_idn(self):
w = widgets.AdminURLFieldWidget()
self.assertHTMLEqual(
conditional_escape(w.render('test', 'http://example-.com')),
'<p class="url">Currently:<a href="http://xn--example--7za4pnc.com">http://exam
ple-.com</a><br />Change:<input class="vURLField" name="test" type="text" value="http://
example-.com" /></p>'
)
def test_render_quoting(self):
w = widgets.AdminURLFieldWidget()
self.assertHTMLEqual(
conditional_escape(w.render('test', 'http://example.com/<sometag>some text</som
etag>')),
'<p class="url">Currently:<a href="http://example.com/%3Csometag%3Esome%20text%
3C/sometag%3E">http://example.com/&lt;sometag&gt;some text&lt;/sometag&gt;</a><br />Change:
<input class="vURLField" name="test" type="text" value="http://example.com/<sometag>some te
xt</sometag>" /></p>'
)
self.assertHTMLEqual(
conditional_escape(w.render('test', 'http://example-.com/<sometag>some text<
/sometag>')),
'<p class="url">Currently:<a href="http://xn--example--7za4pnc.com/%3Csometag%3
Esome%20text%3C/sometag%3E">http://example-.com/&lt;sometag&gt;some text&lt;/sometag&gt;
</a><br />Change:<input class="vURLField" name="test" type="text" value="http://example-
.com/<sometag>some text</sometag>" /></p>'
)
Las nuevas pruebas verifican que el mtodo render vaya agregando los nuevos trabajos
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
correctamente en algunas situaciones diferentes.
Pero esto parece una prueba un poco difcil...
Si nunca has tenido que lidiar con las pruebas antes, pueden parecer un poco duro
escribir una prueba o test a primera vista. Afortunadamente, la pruebas son un
tema muy recurrente en programacin de ordenadores, as que hay mucha informacin
por ah:
Para escribir pruebas para Django, como primer vistazo se puede encontrar en la
misma documentacin en Testing Django applications.
Inmersin en Python (un libro gratis en lnea para desarrolladores principiantes de
Python) incluye un gran introduccin a pruebas unitarias: introduction to Unit Testing.
Despus de leer esto, si quieres algo un poco ms sustancioso puedes hundirle
siempre el diente a la documentacion de Python, en la seccin de: Python unittest
documentation.
Recuerda que no se han realizado modificaciones en AdminURLFieldWidget todava, as que nuestras
pruebas van a fallar. Vamos a correr todo el conjunto de pruebas en la
carpeta model_forms_regress para asegurarnos de que es lo que realmente sucede. Desde la lnea de
comandos, nos cambiamos de directorio con cd ala carpeta tests/ y ejecutamos
PYTHONPATH=.. python runtests.py --settings=test_sqlite admin_widgets
Si las pruebas se han ejecutado correctamente, deberas ver tres fallos correspondientes a cada uno
de los mtodos de ensayo que hemos aadido. Si todas las pruebas pasaron, entonces tambin
querrs asegurarte de que se han agregado las nuevas pruebas que se muestran arriba en la clase y
carpeta correspondiente.
Ejecuando la nueva prueba
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
A continuacin vamos a aadir la funcionalidad descrita en ticket #17549 a Django.
Navegamos haste el directorio django/django/contrib/admin/ y abrimos el archivo widgets.py.
Buscamos la clase AdminURLFieldWidget en la lnea 302 y aadimos el siguiente
mtodo render despus de el existente mtodo __init__
def render(self, name, value, attrs=None):
html = super(AdminURLFieldWidget, self).render(name, value, attrs)
if value:
value = force_text(self._format_value(value))
final_attrs = {'href': mark_safe(smart_urlquote(value))}
html = format_html(
'<p class="url">{0} <a {1}>{2}</a><br />{3} {4}</p>',
_('Currently:'), flatatt(final_attrs), value,
_('Change:'), html
)
return html
Una vez que hayas terminado las modificacin de Django, es necesario asegurarse de que las pruebas
que escribimos antes pasen correctamente, para que podamos ver si el cdigo que escribimos arriba
est trabajando correctamente. Para ejecutar las pruebas nos cambiamos ala
carpeta admin_widgets con el comando cd nos situamos en el directorio tests/ y ejecutamos la prueba
PYTHONPATH=.. python runtests.py --settings=test_sqlite admin_widgets
Oops, menos mal que escribimos esta prueba! An tenemos 3 fallos con la excepcin siguiente
NameError: global name 'smart_urlquote' is not defined
Escribir el cdigo para su ticket
Escribir el cdigo para el ticket #17549
Verificando que la prueba pasa ahora
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
Nos hemos olvidado de importar el mtodo smart_urlquote. Seguimos adelante y aadimos el mtodo
de importacin smart_urlquote al final de la lnea 13 del archivo django/contrib/admin/widgets.py de
la siguiente forma:
from django.utils.html import escape, format_html, format_html_join, smart_urlquote
Volvemos a ejecutar las pruebas y debera pasarlas todas. Si no lo hace, devemos asegurarnos de
que hemos modificado correctamente la clase AdminURLFieldWidget como se muestra arriba y que
hemos copiado las nuevas pruebas correctamente.
Una vez que hayas verificado que el parche y la prueba est funcionando correctamente, es una
buena idea ejecutar toda la suite de pruebas Django slo para comprobar que el cambio no ha
introducido ningn otro bug en otras reas de Django. Aunque paso con xito todo el conjunto de
pruebas esto no garantiza que el cdigo esta libre de errores, lo que hace es ayudar a identificar
muchos errores y regresiones que de otro modo podran pasar desapercibidas.
Para ejecutar la totalidad del conjunto de pruebas de Django nos cambiamos al
directorio tests/ con cd y ejecutamos
PYTHONPATH=.. python runtests.py --settings=test_sqlite
Siempre y cuando no se vea ningn fallo, esto esta bien por el momento. Ten en cuenta que esta
revisin Tambin hizo un pequeo cambio al dar formato al widget small CSS change . Puedes hacer el
cambiar si lo deseas, pero lo vamos a omitir por el momento, en aras de la brevedad.
Esta es una nueva caracterstica, por lo que debe ser documentada. Agregamos lo siguiente en la
lnea 925 de django/docs/ref/models/fields.txt debajo de la actual documentacin para URLField:
Ejecutando el paquete de pruebas Django por segunda vez
Escribir Documentacin
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
.. versionadded:: 1.5
El valor actual del campo se mostrar como un enlace al dar clic encima de la
entrada del widget.
Para obtener ms informacin sobre escribir documentacin, incluyendo una explicacin acerca
deversionadded , puedes consultar /internals/contributing/writing-documentation. Esta pgina
incluye tambin una explicacin acerca de cmo construir una copia de la documentacin a nivel local,
para poder tener una vista previa del HTML que se generar.
Ahora es el momento para generar un archivo de revisin que se pueden cargar en Trac o pueda ser
aplicado a otra copia de Django. Para echar un vistazo a los contenidos de el parche, ejecutamos el el
siguiente comando
git diff
Este comando mostrar las diferencias entre la copia actual de Django (con los cambios) y la revisin
que checamos inicialmente a principios de este tutorial.
Una vez que hayas terminado de ver el parche, pulse la tecla q para salir de nuevo a la lnea de
comandos. Si el contenido del parche es correcto, puedes ejecutar el siguiente comando para guardar
el archivo de parche en el directorio de trabajo actual
git diff> 17549.diff
Ahora debes tener un archivo en el directorio raz de Django llamado 17549.diff. Este parche contiene
todos los cambios que haz hecho y debe verse asi:
diff --git a/django/contrib/admin/widgets.py b/django/contrib/admin/widgets.py
index 1e0bc2d..9e43a10 100644
--- a/django/contrib/admin/widgets.py
Generacin del parche para los cambios
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
+++ b/django/contrib/admin/widgets.py
@@ -10,7 +10,7 @@ from django.contrib.admin.templatetags.admin_static import static
from django.core.urlresolvers import reverse
from django.forms.widgets import RadioFieldRenderer
from django.forms.util import flatatt
-from django.utils.html import escape, format_html, format_html_join
+from django.utils.html import escape, format_html, format_html_join, smart_urlquote
from django.utils.text import Truncator
from django.utils.translation import ugettext as _
from django.utils.safestring import mark_safe
@@ -306,6 +306,18 @@ class AdminURLFieldWidget(forms.TextInput):
final_attrs.update(attrs)
super(AdminURLFieldWidget, self).__init__(attrs=final_attrs)
+ def render(self, name, value, attrs=None):
+ html = super(AdminURLFieldWidget, self).render(name, value, attrs)
+ if value:
+ value = force_text(self._format_value(value))
+ final_attrs = {'href': mark_safe(smart_urlquote(value))}
+ html = format_html(
+ '<p class="url">{0} <a {1}>{2}</a><br />{3} {4}</p>',
+ _('Currently:'), flatatt(final_attrs), value,
+ _('Change:'), html
+ )
+ return html
+
class AdminIntegerFieldWidget(forms.TextInput):
class_name = 'vIntegerField'
diff --git a/docs/ref/models/fields.txt b/docs/ref/models/fields.txt
index 809d56e..d44f85f 100644
--- a/docs/ref/models/fields.txt
+++ b/docs/ref/models/fields.txt
@@ -922,6 +922,10 @@ Like all :class:`CharField` subclasses, :class:`URLField` takes the op
tional
:attr:`~CharField.max_length`argument. If you don't specify
:attr:`~CharField.max_length`, a default of 200 is used.
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
+.. versionadded:: 1.5
+
+The current value of the field will be displayed as a clickable link above the
+input widget.
Relationship fields
===================
diff --git a/tests/regressiontests/admin_widgets/tests.py b/tests/regressiontests/admin_wid
gets/tests.py
index 4b11543..94acc6d 100644
--- a/tests/regressiontests/admin_widgets/tests.py
+++ b/tests/regressiontests/admin_widgets/tests.py
@@ -265,6 +265,35 @@ class AdminSplitDateTimeWidgetTest(DjangoTestCase):
'<p class="datetime">Datum: <input value="01.12.2007" type="text" clas
s="vDateField" name="test_0" size="10" /><br />Zeit: <input value="09:30:00" type="text" cl
ass="vTimeField" name="test_1" size="8" /></p>',
)
+class AdminURLWidgetTest(DjangoTestCase):
+ def test_render(self):
+ w = widgets.AdminURLFieldWidget()
+ self.assertHTMLEqual(
+ conditional_escape(w.render('test', '')),
+ '<input class="vURLField" name="test" type="text" />'
+ )
+ self.assertHTMLEqual(
+ conditional_escape(w.render('test', 'http://example.com')),
+ '<p class="url">Currently:<a href="http://example.com">http://example.com</a><
br />Change:<input class="vURLField" name="test" type="text" value="http://example.com" /><
/p>'
+ )
+
+ def test_render_idn(self):
+ w = widgets.AdminURLFieldWidget()
+ self.assertHTMLEqual(
+ conditional_escape(w.render('test', 'http://example-.com')),
+ '<p class="url">Currently:<a href="http://xn--example--7za4pnc.com">http://exa
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
mple-.com</a><br />Change:<input class="vURLField" name="test" type="text" value="http:/
/example-.com" /></p>'
+ )
+
+ def test_render_quoting(self):
+ w = widgets.AdminURLFieldWidget()
+ self.assertHTMLEqual(
+ conditional_escape(w.render('test', 'http://example.com/<sometag>some text</so
metag>')),
+ '<p class="url">Currently:<a href="http://example.com/%3Csometag%3Esome%20text
%3C/sometag%3E">http://example.com/&lt;sometag&gt;some text&lt;/sometag&gt;</a><br />Change
:<input class="vURLField" name="test" type="text" value="http://example.com/<sometag>some t
ext</sometag>" /></p>'
+ )
+ self.assertHTMLEqual(
+ conditional_escape(w.render('test', 'http://example-.com/<sometag>some text
</sometag>')),
+ '<p class="url">Currently:<a href="http://xn--example--7za4pnc.com/%3Csometag%
3Esome%20text%3C/sometag%3E">http://example-.com/&lt;sometag&gt;some text&lt;/sometag&gt
;</a><br />Change:<input class="vURLField" name="test" type="text" value="http://example-
.com/<sometag>some text</sometag>" /></p>'
+ )
class AdminFileWidgetTest(DjangoTestCase):
def test_render(self):
Felicidades, has generado tu primer parche Django! Ahora que haz aprendido com hacerlo, puedes
usar esas habilidades para ayudar a mejorar la base de cdigo de Django. La generacin de parches y
tickets para adjuntarlos a Trac es til, sin embargo, ya que estamos usando git - (Recientemente
adoptado como versin de control) git oriented workflow es recomendado.
Ya que nunca hemos subido (committed) nuestros cambios a nivel local, necesitamos hecer lo
siguiente para obtener una nueva rama de git como punto de partida
Entonces, qu debo hacer ahora?
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
git reset - cabeza dura
git checkout master
Antes de que puedas escribir parches para Django, hay un poco ms de informacin sobre las
contribuciones que probablemente deberas echar un vistazo:
Debes asegurarse de leer la documentacin de Django
enclaiming tickets and submitting patches. Cubre etiquetas en Trac, cmo reclamar tickets
para s mismo, como se espera el estilo de codificacin para parches, y muchos detalles
importantes.
Si eres por primera vez un contribuyente tambin puedes
leerdocumentation for first time contributors. Tiene un montn de buenos consejos para
aquellos de nosotros que son nuevos para ayudar con Django.
Despus de todo esto, si todava tienes ganas de obtener ms informacin acerca de la forma de
contribuir a Django, siempre puedes navegar por el resto
deDjango's documentation on contributing. Contiene un montn de informacin til y debera
ser tu primera fuente de informacin para responder a cualquier pregunta que te pueda surgir.
Una vez que hemos revisado alguna de esta informacin, podemos estar listos para salir y encontrar
un ticket por nuestra cuenta y para escribir un parche para este. Presta especial atencin a las
entradas marcadas con el criterio easy pickings. Estos tickets son a menudo mucho mas simples en
la naturaleza y son ideales para los contribuyentes primerizos. Una vez que ests familiarizado con la
forma de contribuir a Django, puedes pasar a escribir parches para entradas ms difciles y
complicadas.
Si lo que desea es empezar ya (y nadie te culpara de ello!), Prueba echar un vistazo a la lista de easy
tickets that need patches (tickets que necesitan parches) y a la de easy tickets that have patches which need
improvement. Si est familiarizado con la escritura de pruebas, tambin puede consultar la lista deeasy
Ms informacin para los nuevos contribuyentes
Encontrar el primer Ticket
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
tickets that need tests. Slo recuerda seguir las directrices sobre entradas que se mencionan en el enlace
a la documentacin de Django en claiming tickets and submitting patches.
Despus de que un ticket tiene un parche, tiene que ser revisado por un segundo par de de ojos.
Despus de cargar un parche o se presente una solicitud de extraccin, asegurarte de actualizar los
metadatos del ticket mediante el establecimiento de las banderas correspondientes a el ticket que
diga has patch, doesnt need tests, etc. (tiene parche, no necesita pruebas), para que otros
puedan encontrarlos para su revisin. Contribuyendo no necesariamente significa escribir un parche
desde cero. La revisin de parches existentes es tambin una contribucin muy til.
Ver/internals/contributing/triaging-tickets para mas detalles.
Publicado 30th December 2012 por Saul Garcia
Etiquetas: Django, intro, Tutorial

Qu sigue?

0
Aadir un comentario
Agregacin
La gua de temas sobre Djangos database-abstraction API describe las formas en que podemos usar las
29
NOV
Agregacin
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
consultas en Django para crear, recuperar, actualizar y eliminar objetos individualmente. Sin embargo,
a veces se tiene la necesidad de obtener valores derivados de una suma o una agregacion de una
coleccin de objetos. Esta gua temtica describe las maneras en que los valores agregados se
pueden generar y devolver usando consultas o querys en Django.
A lo largo de esta gua, nos referiremos a los siguientes modelos. Estos modelos son utilizados para
realizar el seguimiento del inventario de una serie de libreras en lnea:
class Author(models.Model):
name = models.CharField(max_length=100)
age = models.IntegerField()
friends = models.ManyToManyField('self', blank=True)
class Publisher(models.Model):
name = models.CharField(max_length=300)
num_awards = models.IntegerField()
class Book(models.Model):
isbn = models.CharField(max_length=9)
name = models.CharField(max_length=300)
pages = models.IntegerField()
price = models.DecimalField(max_digits=10, decimal_places=2)
rating = models.FloatField()
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
pubdate = models.DateField()
class Store(models.Model):
name = models.CharField(max_length=300)
books = models.ManyToManyField(Book)
En una apuracion? Esta es la forma mas comn de hacer consultas de agregados, asumiendo los
modelos arriba mencionados:
Cheat Sheet
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
# Numero total de libros.
>>> Book.objects.count()
2452
# El numero total de libros con un publisher=BaloneyPress
>>> Book.objects.filter(publisher__name='BaloneyPress').count()
73
# Precio medio de los libros.
>>> from django.db.models import Avg
>>> Book.objects.all().aggregate(Avg('price'))
{'price__avg': 34.35}
# Maximo precio de todos los libros.
>>> from django.db.models import Max
>>> Book.objects.all().aggregate(Max('price'))
{'price__max': Decimal('81.20')}
# Cada publisher, con un contador de libros con un atributo "num_books".
>>> from django.db.models import Count
>>> pubs = Publisher.objects.annotate(num_books=Count('book'))
>>> pubs
[<Publisher BaloneyPress>, <Publisher SalamiPress>, ...]
>>> pubs[0].num_books
73
# El top 5 de publishers, en orden de numero de libros.
>>> from django.db.models import Count
>>> pubs = Publisher.objects.annotate(num_books=Count('book')).order_by('-num_books')[:5]
>>> pubs[0].num_books
1323
Django proporciona dos maneras de generar agregados. La primera manera es generar los valores
Agregados que generan ms de un QuerySet
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
sumarios sobre un QuerySet entero. Por ejemplo, digamos que queremos calcular el precio medio de
todos los libros disponibles para la venta. Los querys en Django proporcionan una sintaxis para
describir el conjunto de todos los libros:
>>> Book.objects.all()
Lo que necesitamos es una manera de calcular la suma del valor de los objetos que pertenecen a
esteQuerySet. Esto lo hacemos aadiendo una clausula aggregate() a el QuerySet de esta forma:
>>> from django.db.models import Avg
>>> Book.objects.all().aggregate(Avg('price'))
{'price__avg': 34.35}
El metodo all() es redundante en este ejemplo, por lo se podra simplificar a:
>>> Book.objects.aggregate(Avg('price'))
{'price__avg': 34.35}
El argumento para la clusula aggregate() describe el valor agregado que queremos calcular - en este
caso, el promedio de los campos price en el modelo Book - . Una lista de las funciones agregadas est
disponibles en la QuerySet reference.
aggregate() es una clusula terminal para un QuerySet que, cuando se invoca, devuelve un diccionario
de pares de nombre-valor. El nombre es un identificador para el valor agregado, el valor es la suma
calculada. El nombre es generado automticamente a partir del nombre del campo y la funcin de
agregado. Si se desea especificar manualmente un nombre para el valor agregado, puede hacerce
proporcionando ese nombre cuando se especifica la clusula agregada:
>>> Book.objects.aggregate(average_price=Avg('price'))
{'average_price': 34.35}
Si se desea generar ms de un agregado, solo devemos agregar otro argumento ala
clusula aggregate(). Por lo tanto, si tambin queremos saber el precio mximo y mnimo de todos los
libros, podramos emitir la consulta asi:
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
>>> from django.db.models import Avg, Max, Min, Count
>>> Book.objects.aggregate(Avg('price'), Max('price'), Min('price'))
{'price__avg': 34.35, 'price__max': Decimal('81.20'), 'price__min': Decimal('12.99')}
La segunda manera de generar sumas de valores es el de generar sumas independientes de cada
objeto en un QuerySet. Por ejemplo, si vamos a recuperar una lista de libros, podriamos querer saber
cuntos autores contribuyeron a cada libro. Cada libro tiene una relacin de muchos a muchos con el
autor, si queremos resumir esta relacin para cada libro del QuerySet
La suma de pre-objetos se pueden generar utilizando la clusula annotate(). Cuando una
clusulaannotate() se especifica, cada objeto del QuerySet ser anotada con los valores especificados.
La sintaxis de estas anotaciones es idntica a la utilizada por la clusula aggregate() . Cada
argumento aannotate() describe un agregado que sera calculado. Por ejemplo, para anotar los libros
por el nmero de autores podemos usar:
# construye un queryset anotado
>>> q = Book.objects.annotate(Count('authors'))
# preguntamos por el primer objeto del queryset
>>> q[0]
<Book: The Definitive Guide to Django>
>>> q[0].authors__count
2
# preguntamos por el segundo objeto del queryset
>>> q[1]
<Book: Practical Django Projects>
>>> q[1].authors__count
1
Al igual que con aggregate(), el nombre de la anotacin se deriva automticamente a partir del
nombre de la funcin de agregado y el nombre del campo que se ha agregado. Se puede sustituir este
Generacin de agregados para cada elemento de un QuerySet
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
nombre por defecto al proporcionar un alias cuando se especifique la anotacin:
>>> q = Book.objects.annotate(num_authors=Count('authors'))
>>> q[0].num_authors
2
>>> q[1].num_authors
1
Tal como aggregate(), annotate() no es una clusula terminal. La salida de la clusula annotate() es
unQuerySet; este QuerySet puede ser modificado como cualquier otro QuerySet con operaciones,
incluyendofilter(), order_by, o incluso con llamadas adicionales a annotate().
Hasta ahora, nos hemos ocupado de los agregados sobre los campos que pertenecen a los modelos
que se est consultando. Sin embargo, a veces el valor que se desea agregar pertenecer a un
modelo que tiene que ver con el modelo que se est consultando.
Al especificar el campo para ser agregados en una funcin de agregado, Django nos permitir utilizar
la mismo double underscore notation (doble guion bajo) que utiliza para referirse a los campos
relacionados en filtros. Django manejara las uniones de las tablas que son requeridas y agregara el
valor reacionado.
Por ejemplo, para encontrar el rango de precios de los libros que se ofrecen en cada tienda, se puede
utilizar la anotacin:
>>> Store.objects.annotate(min_price=Min('books__price'), max_price=Max('books__price'))
Esto le indica a Django que recupere el modelo Store, junto (a travs de la relacion muchos-a-muchos)
con el modelo book, y agregue el precio de campo del modelo de libro para producir un valor mnimo y
mximo.
Las mismas reglas se aplican a clusula aggregate(). Si quisieramos saber el precio ms bajo y ms
Juntar y Agregar
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
alto de todos los libros que estn disponibles para la venta en la tienda(Store), podramos utilizar
elaggregate() siguiente:
>>> Store.objects.aggregate(min_price=Min('books__price'), max_price=Max('books__price'))
Juntar cadenas pueden ser tan profundo como sea necesario. Por ejemplo, para extraer la edad de la
autora ms joven de todos los libros disponibles para la venta, se podra emitir la consulta:
>>> Store.objects.aggregate(youngest_age=Min('books__authors__age'))
Los agregados tambin pueden participar en filtros. Cualquier filter() (o exclude()) aplicado a los
campos normales del modelo tendr el efecto de restringir los objetos que se consideran para la
agregacin.
Cuando se utilizan con un clusula annotate(), un filtro tiene el efecto de restringir los objetos para
los que se calcula una anotacin. Por ejemplo, se puede generar una lista anotada de todos los libros
que tienen un ttulo que empieza con Django utilizando la consulta:
>>> Book.objects.filter(name__startswith="Django").annotate(num_authors=Count('authors'))
Cuando se utiliza con una clusula aggregate(), un filtro tiene un efecto limitador de objetos sobre los
cuales se calcula el agregado. Por ejemplo, se puede generar el precio medio de todos los libros con
un ttulo que comience con Django utilizando la consulta:
>>> Book.objects.filter(name__startswith="Django").aggregate(Avg('price'))
Agregaciones y otras clusulas de un QuerySet
filter() y exclude()
Filtros o anotaciones
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
Los valores anotados tambin se puede filtrar. Los alias de la anotacin puede ser utilizados en
clausulasfilter() y exclude() de la misma manera que cualquier otro modelo de campo.
Por ejemplo, para generar una lista de libros que tienen ms de un autor, podemos ejecutar la
siguiente consulta:
>>> Book.objects.annotate(num_authors=Count('authors')).filter(num_authors__gt=1)
Esta consulta genera un conjunto de resultados anotados, a continuacin, genera un filtro basado en
que la anotacin.
Cuando se desarrolla una consulta compleja que involucra tanto una clusula annotate() si como
unafilter(), se debe prestar especial atencin al orden en el que se aplican las clusulas
del QuerySet.
Cuando un clusula annotate() es aplicada a una consulta, la anotacin es calculada sobre el estado
de la consulta hasta el punto en que la anotacin se solicita. La implicacin prctica de esto es
que filter() yannotate() no son operaciones conmutativas - es decir, hay una diferencia entre la
consulta -:
>>> Publisher.objects.annotate(num_books=Count('book')).filter(book__rating__gt=3.0)
y la consulta:
>>> Publisher.objects.filter(book__rating__gt=3.0).annotate(num_books=Count('book'))
Ambas consultas devolver una lista de editores que tienen por lo menos un buen libro (es decir, un
libro con una calificacin superior a 3.0). Sin embargo, la anotacin en la primera consulta
proporcionar el nmero total de todos los libros publicados por la editorial, la segunda consulta
incluir solamente los buenos libros en el contador de la anotacin. En la primera consulta, la
anotacin precede al filtro, por lo que el filtro no tiene efecto en la anotacin. En la segunda consulta,
Ordenar clausulas annotate() y filter()
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
el filtro precede a la anotacin, y como resultado, el filtro restringe los objetos considerados cuando se
hace la anotacin.
Las anotaciones se pueden utilizar basicamenente para ordenar. Cuando se define una
clausulaorder_by (), los agregados suministrados pueden hacer referencia a cualquier alias definido
como parte de una clusula annotate() en la consulta.
Por ejemplo, para ordenar un QuerySet de libros por el nmero de autores que han colaborado en el
libro, se puede utilizar la siguiente consulta:
>>> Book.objects.annotate(num_authors=Count('authors')).order_by('num_authors')
Por lo general, las anotaciones se generan en funcin de cada objeto - una
anotacion QuerySet devolver un resultado para cada objeto en el original QuerySet -. Sin embargo,
cuando una clusula values() es utilizada para restringir las columnas que se devuelven en el
conjunto de resultados, el mtodo de evaluacin de anotaciones es ligeramente diferente. En lugar de
devolver un resultado anotado para cada resultado en el QuerySet, los resultados originales son
agrupados de acuerdo con las combinaciones particulares de los campos especificados en la
clusula values(). Una anotacin se proporciona entonces para cada grupo nico; la anotacin se
calcula sobre todos los miembros del grupo.
Por ejemplo, consideremos una consulta de un autor que intenta averiguar el promedio de valoracin
de los libros escritos por cada autor:
>>> Author.objects.annotate(average_rating=Avg('book__rating'))
Esto devolver un resultado por cada autor en la base de datos, con la anotacin, y su clasificacin
promedio contable.
order_by()
values()
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
Sin embargo, el resultado ser un poco diferente si se utiliza un clusula values():
>>> Author.objects.values('name').annotate(average_rating=Avg('book__rating'))
En este ejemplo, los autores se agruparn por su nombre, por lo que se obtendr slo un resultado
anotado para cada un Nombre nico autor. Esto significa que tenemos Dos autores con el mismo
nombre, los resultados se fusionarn en una sola salida de consulta; el promedio se calcula como el
promedio de los libros escritos por ambos autores.
Al igual que con la clusula filter(), el orden en el cual las clausulas``annotate()`` y values() se
aplican a una consulta es significativo. Si la clusula values() precede ala clausula annotate(), la
anotacin ser calculada utilizando la agrupacin descrita por la clusula values().
Sin embargo, si la clusula annotate() precede a la clusula values(), las anotaciones se genera
sobre el conjunto completo de la consulta. En este caso, la clusula values() slo limita los campos
que se generan en la salida.
Por ejemplo, si invertimos el orden de los valores de las clausulas values() y annotate() de nuestro
ejemplo anterior:
>>> Author.objects.annotate(average_rating=Avg('book__rating')).values('name', 'average_rat
ing')
Esto ahora producira un resultado nico para cada autor, sin embargo, slo el nombre del autor y la
anotacin average_rating ser devuelto en los datos de salida.
Tambin debemos tener en cuenta que average_rating se ha incluido explcitamente en la lista de
valores que se devuelven. Esto es necesario debido a la orden de los valores de las
clusulas values() yannotate().
Si la clusula values() precede ala clusula annotate(), las anotaciones se aaden automticamente
El order de clusulas annotate() y values()
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
a la hoja de resultados. Sin embargo, si la clusula values() se aplica despus de la
clusula annotate(), se debe explcitamente incluir la columna agregada.
Los campos que se mencionan en el metodo order_by() por parte de un queryset (o que se utilizan en
el orden predeterminado de un modelo) se usan cuando se selecciona los datos de salida, incluso si
no se especifique otra cosa en la llamada a values(). Estos campos adicionales se utilizan para
agrupar y juntar resultados similares entre s y que pueden tener otros resultados en filas idnticas,
pero de un modo separado. Esto se manifiesta, en particular, al contar cosas.
A modo de ejemplo, supongamos que se tiene un modelo como este:
class Item(models.Model):
name = models.CharField(max_length=10)
data = models.IntegerField()
class Meta:
ordering = ["name"]
La parte importante aqu es el orden predeterminado en el campo name. Si deseamos contar cuntas
veces cada valor data distinto aparece, es posible que intentemos esto:
# Advertencia: No del todo correcto!
Item.objects.values("data").annotate(Count("id"))
... Que agrupar los objetos Item por su valor comn data y luego contara el nmero de valores id en
cada grupo. Slo que no terminara de funcionar. El valor por defecto name tambin jugar un papel
importante en la agrupacin, por lo que si queremos una consulta de grupos de pares de
distintos(data, name) , que no es lo que queremos. En su lugar, devemos construir este queryset:
Item.objects.values("data").annotate(Count("id")).order_by()
...limpiamos y ordenamos la consulta. Tambin podriamos ordenar, por decir, date sin ningn efecto
Interaccin con un orden predeterminado o order_by()
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
perjudicial, puesto que ya est jugando un papel en la consulta.
Este comportamiento es el mismo que se indica en la documentacin para el distinct() y la regla
general es la misma: normalmente no querremos columnas extra que juegan un papel importante en
el resultado, por lo que limpiar el orden, o al menos asegurarse de que se est restringiendo al menos
esos campos que tambien son seleccionados en la llamada a values().
Note
Es razonable preguntar por qu Django no elimina las columnas extraas por nosotros.
La razn principal es por mantener la coherencia con distinc () y otros lugares:
Django nuncaeliminara el orden de retriccion que hayamos especificado (y no podemos
cambiar el comportamiento de los otros mtodos, ya que esto violara
nuestro: /misc/api-stabilitypolicy).
Tambin se puede generar un agregado en el resultado de una anotacin. Cuando definimos una
clausulaaggregate(), los agregados suministrados pueden hacer referencia a cualquier alias definido
como parte de una clusula annotate() de la consulta.
Por ejemplo, si desea calcular el nmero promedio de autores por el conjunto de libros con el recuento
autor, entonces el agregado que cuenta el autor, haciendo referencia al campo de anotaciones:
>>> Book.objects.annotate(num_authors=Count('authors')).aggregate(Avg('num_authors'))
{'num_authors__avg': 1.66}
Publicado 29th November 2012 por Saul Garcia
Etiquetas: base de datos, Django

Agregacin de anotaciones
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API

1
Ver comentarios
Vistas genricas basadas en clase
Changed in Django 1.3: Please see the release notes
Note
A partir de Django 1.3, las vistas genricas basadas en funciones han quedado en desuso
en favor de un enfoque basado en clases, que se describe aqu. Para detalles sobre
implementaciones previas puedes ver el documento topic guide y la detailed reference.
Escribir aplicaciones web pueden ser montono, ya que repetimos ciertos patrones una y otra vez.
Django intenta quitar algo de esa monotona en el modelo y en la capa de plantillas, pero los
desarrolladores web tambin experimentan ese aburrimiento a nivel de vistas.
Las Visitas genricas en Django fueron desarrolladas para aliviar ese dolor. Toman ciertas expresiones
y patrones comunes encontrados en el desarrollo de vista y lo abstraen de modo que podamos
escribir vistas comunes de datos sin tener que escribir demasiado cdigo.
Podemos reconocer ciertas tareas comunes, como mostrar una lista de objetos y escribir el cdigo que
muestra una lista de objetos cualquiera. El modelo en cuestin puede ser pasado como un argumento
adicional a travs de la URLconf.
Django viene con vistas genricas que pueden hacer lo siguiente:
29
NOV
Vistas genricas basadas en clase
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
Django viene con vistas genricas que pueden hacer lo siguiente:
Realizar tareas simples y comunes: redirigir a una pgina diferente y renderizar una plantilla
dada.
Mostrar paginas de listado y detalles para un nico objeto. Si estuviramos creando un aplicacin
para gestionar conferencias tendramos una vista talk_list y tambin
una registered_user_listestas vista seran ejemplos de ListView (listado). Una simple pgina
de discusin es un ejemplo de lo que llamamos una vista de DetailView (detalle).
Presentar objetos basados en datos en paginas del tipo fecha, ao/mes/da y su detalle
asociado, y las paginas nuevas. Los archivo del blog web de Django
(https://www.djangoproject.com/weblog/) son archivos del tipo ao, mes y da y se construyen de esta
forma, como sera un tpico archivo de un peridico
Permitir a los usuarios crear, actualizar y borrar objetos -con o sin autorizacin-.
Tomados en conjunto, estas vistas proporcionan interfaces fciles para realizar los trabajos ms
comunes que puedan encontrar los desarrolladores.
Las vistas basados en clases genricas (y cualquier vista basada en clases heredaran los atributos de
las clases base que proporcionan Django) se puede configurar de dos maneras: creando una subclase
y/o pasando directamente los argumentos en la URLconf.
Cuando sobreescribimos algunos atributos en una subclase de una vista basada en (Tal como
eltemplate_name) o algun mtodo (tal como get_context_data) en la subclase para proporcionar
nuevos valores o mtodos. Consideremos, por ejemplo, una vista que slo muestra una
plantilla about.html. Django posee una vista genrica para hacer esto - TemplateView - para que
podamos simplemente pasarla como una subclase y sobreescribir el nombre de la plantilla:
# alguna_app/views.py
from django.views.generic import TemplateView
Simple uso
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
class AboutView(TemplateView):
template_name = "about.html"
Luego, slo tenemos que aadir esta nueva vista a nuestra URLconf. Como las clases basadas en
vistas son en en s mismo clases, necesitamos apuntar el mtodo as_view ala URL de la clase en su
lugar, que es el punto de entrada para las vistas basadas en clases:
# urls.py
from django.conf.urls import patterns, url, include
from some_app.views import AboutView
urlpatterns = patterns('',
(r'^about/', AboutView.as_view()),
)
Alternativamente, si slo est cambiando algunos pequeos atributos en un vista basada en clases,
slo necesitamos pasar los nuevos atributos en la llamada al mtodo as_view en si mismo:
from django.conf.urls import patterns, url, include
from django.views.generic import TemplateView
urlpatterns = patterns('',
(r'^about/', TemplateView.as_view(template_name="about.html")),
)
Un patrn predominantemente similar se puede utilizar para usar un atributo en la url en la
claseRedirectView, otra sencilla vista genrica.
El mtodo TemplateView es ciertamente til, pero las vistas genricas de Django realmente brillan
cuando se trata de presentar vistas sobre el contenido de tu base de datos. Porque Es una tarea
comn, Django viene con un puado de vistas genricas incorporadas que hacen la generacin de
vistas de listado y detalle de objetos increblemente fcil.
Vistas genricas de objetos
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
Echemos un vistazo a una de estas vistas genricas: la vista object list. Vamos a usar estos
modelos:
# models.py
from django.db import models
class Publisher(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=50)
city = models.CharField(max_length=60)
state_province = models.CharField(max_length=30)
country = models.CharField(max_length=50)
website = models.URLField()
class Meta:
ordering = ["-name"]
def __unicode__(self):
return self.name
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField('Author')
publisher = models.ForeignKey(Publisher)
publication_date = models.DateField()
Para crear una pagina de lista o un listado de todos los publishers, usaremos la URLconf bajo estas
lineas:
from django.conf.urls import patterns, url, include
from django.views.generic import ListView
from books.models import Publisher
urlpatterns = patterns('',
(r'^publishers/$', ListView.as_view(
model=Publisher,
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
)),
)
Este es todo el cdigo Python que necesitamos escribir. Sin embargo, todava tenemos que escribir
una plantilla. Sin embargo podramos decirle explcitamente ala vista que plantilla debe utilizar
mediante la inclusin de un argumento template_name en el mtodo as_view, pero en la ausencia de
una plantilla explcita Django inferir una del nombre del objeto. En este caso, la plantilla inferida
sera"books/publisher_list.html" - la parte books proviene del nombre de la aplicacin que define
el modelo, mientras que el publisher es solo la versin del nombre del modelo en minsculas.
Note
Por lo tanto, cuando (por ejemplo) django.template.loaders.app_directories.Loader el
cargador de plantillas este habilitado en TEMPLATE_LOADERS, la ubicacin de la plantilla
sera:
/path/to/project/books/templates/books/publisher_list.html
Esta plantilla ser renderizada en un contexto que contiene una variable llamada object_list la cual
contiene todos los objetos publisher. Una plantilla muy simple podra verse como la siguiente:
{% extends "base.html" %}
{% block content %}
<h2>Publishers</h2>
<ul>
{% for publisher in object_list %}
<li>{{ publisher.name }}</li>
{% endfor %}
</ul>
{% endblock %}
Eso es realmente todo en lo referente al tema. Todas las geniales caractersticas de las vistas
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
genricas provienen de cambiar el diccionario info pasado a la vista genrica. El
documentogeneric views reference describe todas las vistas genricas y todas sus opciones en
detalle; el resto de este captulo considerar algunas de las formas comunes en que t puedes
personalizar y extender las vistas genricas.
No hay duda de que el uso de las vistas genricas puede acelerar el desarrollo sustancialmente. En la
mayora de los proyectos, sin embargo, llega un momento en el que las vistas genrica no son
suficientes. De hecho, la pregunta ms comn que se hacen los desarrolladores de Django es cmo
hacer que las vistas genricas manejen un rango ms amplio de situaciones.
Esta es una de las razones del por que las vistas genricas fueron rediseadas para el lanzamiento
de la versin 1,3 - anteriormente, solo eran funciones con una desconcertante variedad de opciones;
Ahora, en lugar de pasar una gran cantidad de configuraciones en la URLconf, el mtodo recomendado
para extender las vistas genricas es crear una subclase de ellos, y anular y sobreescribir sus
atributos o mtodos.
Tal vez hayas notado que el ejemplo de la plantilla publisher list almacena todos los books en una
variable llamada object_list. Aunque que esto funciona bien, no es una forma amistosa para los
autores de plantillas: ellos slo tienen que saber aqu que estn trabajando con books. Un nombre
mejor para esa variable sera publisher_list ; el contenido de esa variable es bastante obvio.
Si Bien, si estamos tratando con un objeto de modelo, esto ya est hecho por nosotros. Cuando se
trata de un objeto o queryset, Django es capaz de rellenar el contexto con el nombre verbose, en el
caso la lista de objetos) del objeto que sera mostrado. Esto sera proporcionado por defecto
como object_list, pero contiene exactamente los mismos datos.
Si el nombre verbose no concuerda todava, se puede configurar manualmente el nombre de la
variable de contexto. El atributo context_object_name de una vista genrica especifica la variable de
Extender las vistas genricas
Haciendo contextos de plantilla amigables
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
contexto de su uso. En este ejemplo, vamos a reemplazar el de la URLconf, con un simple cambio:
urlpatterns = patterns('',
(r'^publishers/$', ListView.as_view(
model=Publisher,
context_object_name="publisher_list",
)),
)
Proporcionar un til context_object_name es siempre una buena idea.
Podemos cambiar el nombre de esa variable fcilmente con el argumento template_object_name: Tus
compaeros de trabajo que disean las plantillas te lo agradecern.
A menudo simplemente necesitamos presentar alguna informacin extra aparte de la proporcionada
por la vista genrica. Por ejemplo, piensa en mostrar una lista de todos los otros publisher en cada
pgina de detalle de un publisher. La vista genrica DetailView provee a el publisher el contexto, pero
parece que no hay forma de obtener una lista de todos los publishers en esa plantilla.
Pero s la hay: esta la proporciona la subclase DetailView , extra_context. Este es un diccionario de
objetos extra que sern agregados y provee una implementacin del mtodo get_context_data .La
implementacin por viene con la clase DetailView simplemente agregamos el objeto que vamos a
mostrar en la plantilla, pero podemos sobrescribir mas:
from django.views.generic import DetailView
from books.models import Publisher, Book
class PublisherDetailView(DetailView):
context_object_name = "publisher"
model = Publisher
def get_context_data(self, **kwargs):
Agregar un contexto extra
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
# Llamamos ala implementacion para traer un primer context
context = super(PublisherDetailView, self).get_context_data(**kwargs)
# Agregamos un QuerySet de todos los books
context['book_list'] = Book.objects.all()
return context
Ahora echemos un vistazo ms de cerca el argumento model que hemos estado usando todo el
tiempo. El argumento model, que especifica el modelo de la base de datos sobre la que la vista
operar, est disponible en todos los vistas genricas que operan en un solo objeto o en una
coleccin de objetos. Sin embargo, el argumento model no es la nica manera de especificar los
objetos que la vista que operan - tambin se pueden especificar la lista de objetos utilizando el
argumento QuerySet
from django.views.generic import DetailView
from books.models import Publisher, Book
class PublisherDetailView(DetailView):
context_object_name = "publisher"
queryset = Publisher.objects.all()
Especificando model = Publisher en realidad es una atajo para
decirqueryset = Publisher.objects.all(). Sin embargo, mediante el uso de queryset para definir una
lista filtrada de objetos que pueden ser ms especfico sobre la objetos que sern visibles en la vista
(verRealizando consultas Para obtener ms informacin acerca de los objetos QuerySet, y puedes
verclass-based views reference para detalles completos.
Para escoger un ejemplo sencillo, queremos ordenar una lista de libros por su fecha de publicacin,
con el ms reciente al principio usaramos la siguiente forma en el archivo URLconf:
urlpatterns = patterns('',
Mostrar subconjuntos de objetos
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
(r'^publishers/$', ListView.as_view(
queryset=Publisher.objects.all(),
context_object_name="publisher_list",
)),
(r'^books/$', ListView.as_view(
queryset=Book.objects.order_by("-publication_date"),
context_object_name="book_list",
)),
)
Este es un ejemplo bastante simple, pero ilustra muy bien la idea. Por supuesto, t usualmente
querrs hacer ms que slo reordenar objetos. Si quieres presentar una lista de books de un
publisher en particular, puedes usar la misma tcnica (en este caso, lo ilustramos mediante la creacin
de una subclase en lugar pasar los argumentos en la URLconf)):
from django.views.generic import ListView
from books.models import Book
class AcmeBookListView(ListView):
context_object_name = "book_list"
queryset = Book.objects.filter(publisher__name="Acme Publishing")
template_name = "books/acme_list.html"
Nota que tambin estamos filtrando un queryset , y estamos usando un nombre de plantilla
personalizado. Si no lo hiciramos, la vista genrica usara la misma plantilla que la lista de objetos
genrica, que puede no ser lo que queremos.
Tambin nota que sta no es una forma muy elegante de encontrar los publisher-specific books. Si
queremos agregar otra pgina publisher, necesitamos otro puado de lneas en la URLconf, y ms de
unos pocos publishers no ser razonable. Enfrentaremos este problema en la siguiente seccin.
Note
Si obtienes un error 404 cuando solicitas /books/acme/, para estar seguro, verifica que en
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
realidad tienes un Publisher con el nombre ACME Publishing. Las vistas genricas tienen
un parmetro allow_empty para estos casos. Mira en class-based-views reference para
mas detalles.
Otra necesidad comn es filtrar los objetos que se muestran en una pgina listado por alguna clave
en la URLconf. Anteriormente codificamos el nombre del publisher en la URLconf, pero qu pasa si
queremos escribir una vista que muestre todos los books por algn publisher arbitrario?.
Convenientemente tenemos una vista ListView que tiene un mtodo get_queryset() que podemos
sobreescribir. Anteriormente, solo retornamos los atributos del valor del queryset , pero ahora
podemos aadir ms lgica.
La parte clave para hacer este trabajo es que cuando vistas basadas en clases son llamadas se
almacenas varias cosas tiles self; si bien la peticin (self.request) que incluye la posicin
(self.args) y los nombres basados en argumentos (self.kwargs) capturados de acuerdo ala URLconf.
Aqu tenemos una URLconf con un simple grupo capturado:
from books.views import PublisherBookListView
urlpatterns = patterns('',
(r'^books/(\w+)/$', PublisherBookListView.as_view()),
)
A continuacin, escribiremos la vista PublisherBookListView
from django.shortcuts import get_object_or_404
from django.views.generic import ListView
from books.models import Book, Publisher
class PublisherBookListView(ListView):
Filtrado dinmico
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
context_object_name = "book_list"
template_name = "books/books_by_publisher.html"
def get_queryset(self):
publisher = get_object_or_404(Publisher, name__iexact=self.args[0])
return Book.objects.filter(publisher=publisher)
Como se puede ver, es muy fcil agregar ms lgica al queryset seleccionado; si quisiramos,
podramos usar self.request.user para filtrar el usuario actual , o podemos usar alguna lgica un
poco ms compleja.
Tambin podemos aadir el publisher en el mismo contexto, para poder utilizarlo en la plantilla:
class PublisherBookListView(ListView):
context_object_name = "book_list"
template_name = "books/books_by_publisher.html"
def get_queryset(self):
self.publisher = get_object_or_404(Publisher, name__iexact=self.args[0])
return Book.objects.filter(publisher=self.publisher)
def get_context_data(self, **kwargs):
# Llamamos ala implementacion primero del context
context = super(PublisherBookListView, self).get_context_data(**kwargs)
# Agregamos el publisher
context['publisher'] = self.publisher
return context
El ltimo patrn comn que veremos involucra realizar algn trabajo extra antes o despus de llamar
a la vista genrica.
Imagina que tenemos un campo last_accessed en nuestro objeto Author que estuvimos usando para
tener un registro de la ltima vez que alguien vio ese author:
Realizar trabajo extra
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
# models.py
class Author(models.Model):
salutation = models.CharField(max_length=10)
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=40)
email = models.EmailField()
headshot = models.ImageField(upload_to='/tmp')
last_accessed = models.DateTimeField()
La vista genrica object_detail, por supuesto, no sabra nada sobre este campo, pero una vez ms
podramos fcilmente escribir una vista personalizada para mantener ese campo actualizado:
from books.views import AuthorDetailView
urlpatterns = patterns('',
#...
(r'^authors/(?P<pk>\d+)/$', AuthorDetailView.as_view()),
)
La clase genrica DetailView, por supuesto, no sabe nada de este campo, pero una vez ms,
fcilmente podramos escribir una vista personalizada para mantener ese campo actualizado.
En primer lugar, tendramos que aadir los detalles del autor en la URLconf para que apunte a una
vista personalizada:
from books.views import AuthorDetailView
urlpatterns = patterns('',
#...
(r'^authors/(?P<pk>\d+)/$', AuthorDetailView.as_view()),
)
A continuacin, necesitamos escribir la funcin - get_object que es el mtodo que recupera un objeto -
por lo que slo tenemos que sobrescribir y envolver la llamada:
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
import datetime
from books.models import Author
from django.views.generic import DetailView
from django.shortcuts import get_object_or_404
class AuthorDetailView(DetailView):
queryset = Author.objects.all()
def get_object(self):
# Llamamos ala superclase
object = super(AuthorDetailView, self).get_object()
# Grabamos el ultimo acceso ala base de datos
object.last_accessed = datetime.datetime.now()
object.save()
# Retornamos el objeto
return object
Note
Este cdigo en realidad no funcionar a menos que escribamos la
plantilla books/author_detail.html
Note
La URLconf aqu usa el nombre del grupo pk este nombre es el valor por defecto que
usaDetailView para encontrar el valor primario que se usa para filtrar el queryset.
Si deseamos cambiarlo, necesitamos crear una llamada a el mtodo``get()`` en
un self.querysetusando el nuevo nombre del parmetro de self.kwargs.
Mas que solo HTML
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
Hasta ahora, nos hemos centrado en renderizar plantillas para generar respuestas html. Sin embargo,
eso no es todo lo que las vistas genricas puede hacer.
Cada vista genrica esta compuesta de una una serie de mixins, y cada uno de esos mixin contribuye
con una pequea parte a toda la vista. Algunos de estos mixins - Son tales
como TemplateResponseMixin son especficamente diseado para representar el contenido de una
respuesta HTML usando una plantilla. Sin embargo, podemos escribir nuestros propios mixins para que
devuelvan un contenido diferente.
Por ejemplo, un simple mixin JSON podra ser algo como esto:
from django import http
from django.utils import simplejson as json
class JSONResponseMixin(object):
def render_to_response(self, context):
"Returns a JSON response containing 'context' as payload"
return self.get_json_response(self.convert_context_to_json(context))
def get_json_response(self, content, **httpresponse_kwargs):
"Construct an `HttpResponse` object."
return http.HttpResponse(content,
content_type='application/json',
**httpresponse_kwargs)
def convert_context_to_json(self, context):
"Convert the context dictionary into a JSON object"
# Note: This is *EXTREMELY* naive; in reality, you'll need
# to do much more complex handling to ensure that arbitrary
# objects -- such as Django model instances or querysets
# -- can be serialized as JSON.
return json.dumps(context)
Entonces podramos escribir una vista que nos retorne una respuesta JSON DetailView con los tipos
de mixing JSONResponseMixin con la BaseDetailView (la DetailView antes de que la plantilla sea
renderizada con el mixin ):
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
renderizada con el mixin ):
class JSONDetailView(JSONResponseMixin, BaseDetailView):
pass
Este tipo de vista se puede implementar de igual forma que las otras vista DetailView con el mismo
comportamiento exepto el formato de respuesta
Si somos realmente aventureros podemos usar una mezcla de la clase DetailView para que sea capaz
de de devolver ambos contenidos HTML y JSON dependiendo de alguna propiedad de la solicitud HTTP
tal como un argumento o una cabecera HTTP.Solamente mezclando la clase JSONResponseMixin y la
claseSingleObjectTemplateResponseMixin, sobreescribiendo la implementacion ala
funcinrender_to_response() para aplazar ala subclase apropiada dependiendo del tipo de respuesta
que el usuario pidi:
class HybridDetailView(JSONResponseMixin, SingleObjectTemplateResponseMixin, BaseDetailView
):
def render_to_response(self, context):
# Look for a 'format=json' GET argument
if self.request.GET.get('format','html') == 'json':
return JSONResponseMixin.render_to_response(self, context)
else:
return SingleObjectTemplateResponseMixin.render_to_response(self, context)
Devido ala forma en que python resuelve el mtodo de sobrecarga, la implementacion local del
mtodorender_to_response() sobrescribe la versin proporcionada por la clase JSONResponseMixin y la
claseSingleObjectTemplateResponseMixin.
Para extender el uso de clases genricas no estamos limitado solamente a el uso de mixins.Tambin
podemos usar decoradores.
Decorando clases basadas en vistas
Decorando una URLconf
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
La forma mas simple de decorar una clase genrica es decorando el resultado del mtodo as_view() El
mejor lugar para utilizar un decorador es en la clase del mtodo en si mismo dispatch().
Un mtodo en una clase no es lo mismo que una funcin independiente, por lo que no se puede
simplemente aplicar un decorador ala funcin del mtodo - es necesario transformarlo primero en un
mtodo decorado. El mtodo decorador method_decorator transforma una funcin en un mtodo
decorado que se puede utilizar en un mtodo de una de instancia. Por ejemplo:
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView
class ProtectedView(TemplateView):
template_name = 'secret.html'
@method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(ProtectedView, self).dispatch(*args, **kwargs)
En este ejemplo, cada instancia de ProtectedView tendr proteccin de login, con tan solo licarle el
decorador.
Note
El mtodo method_decorator pasa *args y **kwargs como parmetros al mtodo
representativo de la clase. Si el mtodo no acepta un conjunto compatible de parmetros
sera lanzada una excepcin del tipo TypeError.
Publicado 29th November 2012 por Saul Garcia
Etiquetas: Django, vistas

pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API

0
Aadir un comentario
Relaciones One-to-one
Para definir una relacin uno a uno, utilizamos ref-onetoone.
En este ejemplo, Place opcionalmente puede ser un Restaurant:
from django.db import models, transaction, IntegrityError
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
def __unicode__(self):
return u"%s the place" % self.name
class Restaurant(models.Model):
place = models.OneToOneField(Place, primary_key=True)
serves_hot_dogs = models.BooleanField()
serves_pizza = models.BooleanField()
def __unicode__(self):
return u"%s the restaurant" % self.place.name
class Waiter(models.Model):
restaurant = models.ForeignKey(Restaurant)
28
NOV
Relaciones One-to-one
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
name = models.CharField(max_length=50)
def __unicode__(self):
return u"%s the waiter at %s" % (self.name, self.restaurant)
Los ejemplos que siguen son una muestra de las operaciones que se pueden realizar usando la API
interactiva python.
Primero creamos un par de lugares (Places):
>>> p1 = Place(name='Demon Dogs', address='944 W. Fullerton')
>>> p1.save()
>>> p2 = Place(name='Ace Hardware', address='1013 N. Ashland')
>>> p2.save()
Creamos un restaurant. Pasamos la identificacin del objeto ID padre como ID de este objeto:
>>> r = Restaurant(place=p1, serves_hot_dogs=True, serves_pizza=False)
>>> r.save()
Un restaurante puede tener acceso a un lugar:
>>> r.place
<Place: Demon Dogs the place>
Un lugar puede tener acceso a un restaurante, si est disponible:
>>> p1.restaurant
<Restaurant: Demon Dogs the restaurant>
p2 no tiene un restaurante asociado por lo que lanza un error:
>>> p2.restaurant
Traceback (most recent call last):
...
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
DoesNotExist: Restaurant matching query does not exist.
Establecemos place usando la notacin de asignacin. Porque place es la clave primaria de
el restaurant, al guardar esto creamos un nuevo restaurant:
>>> r.place = p2
>>> r.save()
>>> p2.restaurant
<Restaurant: Ace Hardware the restaurant>
>>> r.place
<Place: Ace Hardware the place>
Establecemos place detrs otra vez, usando la asignacin en la direccin opuesta:
>>> p1.restaurant = r
>>> p1.restaurant
<Restaurant: Demon Dogs the restaurant>
Restaurant.objects.all() devuelve todos los restaurantes, no los lugares.Nota que hay dos
restaurantes - Ace Hardware the Restaurant - fue creado en la llamada a r.place = p2:
>>> Place.objects.order_by('name')
[<Place: Ace Hardware the place>, <Place: Demon Dogs the place>]
Place.objects.all() devuelve todos los lugares, sin importar si tienen Restaurantes:
>>> Place.objects.order_by ("nombre" ")
[<Place: Hardware del as el place>, <Place: El demonio persigue el place>]
Podemos hacer un query a los modelos usando: lookups across relationships:
>>> Restaurant.objects.get(place=p1)
<Restaurant: Demon Dogs the restaurant>
>>> Restaurant.objects.get(place__pk=1)
<Restaurant: Demon Dogs the restaurant>
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
>>> Restaurant.objects.filter(place__name__startswith="Demon")
[<Restaurant: Demon Dogs the restaurant>]
>>> Restaurant.objects.exclude(place__address__contains="Ashland")
[<Restaurant: Demon Dogs the restaurant>]
Esto por supuesto trabaja en forma inversa:
>>> Place.objects.get(pk=1)
<Place: Demon Dogs the place>
>>> Place.objects.get(restaurant__place__exact=p1)
<Place: Demon Dogs the place>
>>> Place.objects.get(restaurant=r)
<Place: Demon Dogs the place>
>>> Place.objects.get(restaurant__place__name__startswith="Demon")
<Place: Demon Dogs the place>
Podemos agregar un camarero al restaurante:
>>> w = r.waiter_set.create(name='Joe')
>>> w.save()
>>> w
<Waiter: Joe the waiter at Demon Dogs the restaurant>
Podemos obtener los camareros:
>>> Waiter.objects.filter(restaurant__place=p1)
[<Waiter: Joe the waiter at Demon Dogs the restaurant>]
>>> Waiter.objects.filter(restaurant__place__name__startswith="Demon")
[<Waiter: Joe the waiter at Demon Dogs the restaurant>]
Publicado 28th November 2012 por Saul Garcia
Etiquetas: base de datos, Django

pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API

0
Aadir un comentario
Relaciones Many-to-Many
Para definir una relacin muchos a muchos, utilizamos la relacin ref-manytomany.
En este ejemplo, un objeto Article puede ser publicado en mltiples objetos Publication y
unaPublication tiene mltiples objetos Articles :
from django.db import models
class Publication(models.Model):
title = models.CharField(max_length=30)
def __unicode__(self):
return self.title
class Meta:
ordering = ('title',)
class Article(models.Model):
headline = models.CharField(max_length=100)
publications = models.ManyToManyField(Publication)
def __unicode__(self):
return self.headline
28
NOV
Relaciones Many-to-Many
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
class Meta:
ordering = ('headline',)
Estos ejemplos que siguen son operaciones que se pueden realizar usando la API interactiva que nos
facilita python.
python manage.py shell
Creamos un par de publicaciones:
>>> p1 = Publication(title='The Python Journal')
>>> p1.save()
>>> p2 = Publication(title='Science News')
>>> p2.save()
>>> p3 = Publication(title='Science Weekly')
>>> p3.save()
Creamos un artculo:
>>> a1 = Article(headline='Django lets you build Web apps easily')
No podemos asociar una publicacin hasta que esta se haya guardado:
>>> a1.publications.add(p1)
Traceback (most recent call last):
...
ValueError: 'Article' instance needs to have a primary key value before a many-to-many rela
tionship can be used.
La guardamos primeramente:
>>> a1.save ()
Ahora ya podemos asociar un Articulo con una Publicacion:
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
>>> a1.publications.add(p1)
Creamos otro artculo y lo guardamos para que aparezca en ambas publicaciones:
>>> a2 = Article(headline='NASA uses Python')
>>> a2.save()
>>> a2.publications.add(p1, p2)
>>> a2.publications.add(p3)
Agregar una segunda vez es ACEPTABLE:
>>> a2.publications.add (p3)
Agregar un objeto de tipo incorrecto levantara un error del tipo TypeError:
>>> a2.publications.add(a1)
Traceback (most recent call last):
...
TypeError: 'Publication' instance expected
Agregamos una publicacin directamente va publications.add usando los argumentos clave:
>>> new_publication = a2.publications.create(title='Highlights for Children')
Los objetos del artculo tienen acceso a las relaciones de sus objetos publication:
>>> a1.publications.all()
[<Publication: The Python Journal>]
>>> a2.publications.all()
[<Publication: Highlights for Children>, <Publication: Science News>, <Publication: Science
Weekly>, <Publication: The Python Journal>]
Los objetos de la publicacin tienen acceso a los objetos relacionados del artculo:
>>> p2.article_set.all()
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
[<Article: NASA uses Python>]
>>> p1.article_set.all()
[<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>]
>>> Publication.objects.get(id=4).article_set.all()
[<Article: NASA uses Python>]
Las relaciones Many-to-many (muchos a muchos) pueden ser obtenidas a travez de la lookups across
relationships
>>> Article.objects.filter(publications__id__exact=1)
[<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>]
>>> Article.objects.filter(publications__pk=1)
[<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>]
>>> Article.objects.filter(publications=1)
[<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>]
>>> Article.objects.filter(publications=p1)
[<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>]
>>> Article.objects.filter(publications__title__startswith="Science")
[<Article: NASA uses Python>, <Article: NASA uses Python>]
>>> Article.objects.filter(publications__title__startswith="Science").distinct()
[<Article: NASA uses Python>]
La funcin count() respecto a distinct() tambin funcionan:
>>> Article.objects.filter(publications__title__startswith="Science").count()
2
>>> Article.objects.filter(publications__title__startswith="Science").distinct().count()
1
>>> Article.objects.filter(publications__in=[1,2]).distinct()
[<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>]
>>> Article.objects.filter(publications__in=[p1,p2]).distinct()
[<Article: Django lets you build Web apps easily>, <Article: NASA uses Python>]
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
Las relaciones inversas m2m son soportadas (es decir, comenzando en la tabla que no tiene un
ManyToManyField):
>>> Publication.objects.filter(id__exact=1)
[<Publication: The Python Journal>]
>>> Publication.objects.filter(pk=1)
[<Publication: The Python Journal>]
>>> Publication.objects.filter(article__headline__startswith="NASA")
[<Publication: Highlights for Children>, <Publication: Science News>, <Publication: Science
Weekly>, <Publication: The Python Journal>]
>>> Publication.objects.filter(article__id__exact=1)
[<Publication: The Python Journal>]
>>> Publication.objects.filter(article__pk=1)
[<Publication: The Python Journal>]
>>> Publication.objects.filter(article=1)
[<Publication: The Python Journal>]
>>> Publication.objects.filter(article=a1)
[<Publication: The Python Journal>]
>>> Publication.objects.filter(article__in=[1,2]).distinct()
[<Publication: Highlights for Children>, <Publication: Science News>, <Publication: Science
Weekly>, <Publication: The Python Journal>]
>>> Publication.objects.filter(article__in=[a1,a2]).distinct()
[<Publication: Highlights for Children>, <Publication: Science News>, <Publication: Science
Weekly>, <Publication: The Python Journal>]
Excluir algun item de un artculo relacionado trabaja tambin como se esperara,(aunque el SQL
implicado es un poco mas complejo):
>>> Article.objects.exclude(publications=p2)
[<Article: Django lets you build Web apps easily>]
Si borramos una publicacin, los objetos artculos no podrn tener acceso a el:
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
>>> p1.delete()
>>> Publication.objects.all()
[<Publication: Highlights for Children>, <Publication: Science News>, <Publication: Science
Weekly>]
>>> a1 = Article.objects.get(pk=1)
>>> a1.publications.all()
[]
Si borramos un artculo, sus publicaciones no podrn tener acceso a el:
>>> a2.delete()
>>> Article.objects.all()
[<Article: Django lets you build Web apps easily>]
>>> p2.article_set.all()
[]
Agregando va el otro extremo de un m2m:
>>> a4 = Article(headline='NASA finds intelligent life on Earth')
>>> a4.save()
>>> p2.article_set.add(a4)
>>> p2.article_set.all()
[<Article: NASA finds intelligent life on Earth>]
>>> a4.publications.all()
[<Publication: Science News>]
Agregando va el otro extremo usando palabras claves:
>>> new_article = p2.article_set.create(headline='Oxygen-free diet works wonders')
>>> p2.article_set.all()
[<Article: NASA finds intelligent life on Earth>, <Article: Oxygen-free diet works wonders>
]
>>> a5 = p2.article_set.all()[1]
>>> a5.publications.all()
[<Publication: Science News>]
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
Eliminando publicaciones de un artculo:
>>> a4.publications.remove(p2)
>>> p2.article_set.all()
[<Article: Oxygen-free diet works wonders>]
>>> a4.publications.all()
[]
Y del otro extremo:
>>> p2.article_set.remove(a5)
>>> p2.article_set.all()
[]
>>> a5.publications.all()
[]
Las relaciones pueden ser asignados. La asignacin borra cualquier miembro determinado existente:
>>> a4.publications.all()
[<Publication: Science News>]
>>> a4.publications = [p3]
>>> a4.publications.all()
[<Publication: Science Weekly>]
Las relaciones de un conjunto se pueden limpiar:
>>> p2.article_set.clear ()
>>> p2.article_set.all ()
[]
Y podemos borrar el otro extremo:
>>> p2.article_set.add(a4, a5)
>>> p2.article_set.all()
[<Article: NASA finds intelligent life on Earth>, <Article: Oxygen-free diet works wonders>
]
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
>>> a4.publications.all()
[<Publication: Science News>, <Publication: Science Weekly>]
>>> a4.publications.clear()
>>> a4.publications.all()
[]
>>> p2.article_set.all()
[<Article: Oxygen-free diet works wonders>]
Volvemos a crear los artculos y las publicacin que hemos borrado:
>>> p1 = Publication(title='The Python Journal')
>>> p1.save()
>>> a2 = Article(headline='NASA uses Python')
>>> a2.save()
>>> a2.publications.add(p1, p2, p3)
Borramos alguna publicaciones en grupo - las referencias a las publicaciones deben ir:
>>> Publication.objects.filter(title__startswith='Science').delete()
>>> Publication.objects.all()
[<Publication: Highlights for Children>, <Publication: The Python Journal>]
>>> Article.objects.all()
[<Article: Django lets you build Web apps easily>, <Article: NASA finds intelligent life on
Earth>, <Article: NASA uses Python>, <Article: Oxygen-free diet works wonders>]
>>> a2.publications.all()
[<Publication: The Python Journal>]
Borramos un grupo de artculos - las referencias a los objetos suprimidos deben ir:
>>> q = Article.objects.filter(headline__startswith='Django')
>>> print q
[<Article: Django lets you build Web apps easily>]
>>> q.delete()
Despus de que borramos, el cache de un QuerySet necesita ser limpiado y la referencia a los objetos
deben de ir:
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
>>> print q
[]
>>> p1.article_set.all()
[<Article: NASA uses Python>]
Un modo alternativo de llamar a clear() es asignar un conjunto vaco:
>>> p1.article_set = []
>>> p1.article_set.all()
[]
>>> a2.publications = [p1, new_publication]
>>> a2.publications.all()
[<Publication: Highlights for Children>, <Publication: The Python Journal>]
>>> a2.publications = []
>>> a2.publications.all()
[]
Publicado 28th November 2012 por Saul Garcia
Etiquetas: base de datos, Django


0
Aadir un comentario
Filtros que hacen referencia a campos de un modelo
28
NOV
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
En los ejemplos dados hasta ahora, hemos construido filtros que comparan el valor de un campo con
un modelo constante. Pero si lo que deseamos es comparar el valor de un campo de un modelo con
otro campo en el mismo modelo?
Django proporciona un F() expressions para permitir tales comparaciones. Las instancias de F() actan
como una referencia a un campo dentro de un modelo de consulta. Estas referencias se pueden usar
en filtros de consulta para comparar los valores de dos campos diferentes en la misma instancia del
modelo.
Por ejemplo, para encontrar una lista de todas las entradas que han tenido ms comentarios que
pingbacks, construimos un objeto F() para hacer una referencia al contador de pingbacks, y usamos el
objeto para hacer la consulta F()
>>> from django.db.models import F
>>> Entry.objects.filter(n_comments__gt=F('n_pingbacks'))
Django soporta el uso de la suma, resta, multiplicacin,la divisin y el modulo aritmtico, con un
objetoF(), tanto para constantes como para otros objetos F(). Para encontrar todas las entradas de
blog con ms de Dos comentarios como pingbacks, modificamos la consulta as:
>>> Entry.objects.filter(n_comments__gt=F('n_pingbacks') * 2)
Para encontrar todas las entradas que tengan un rating menor que la suma del conteo de pingbacks y
el recuento de comentarios, modificamos la consulta:
>>> Entry.objects.filter(rating__lt=F('n_comments') + F('n_pingbacks'))
Tambin podemos utilizar la notacin de guin doble bajo doble para abarcar las relaciones en un
objetoF(). Un objeto F() con un guin doble bajo introducir una unin necesaria para acceder al
objeto relacionado. Por ejemplo, para recuperar todas las entradas en las que el nombre del autor es
el mismo que el nombre del blog, podramos emitir la consulta as:
Filtros que hacen referencia a campos de un modelo
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
>>> Entry.objects.filter(authors__name=F('blog__name'))
New in Django 1.3: Please see the release notes
Para los campos de fecha/hora, podemos aadir o restar un objeto timedelta. El siguiente ejemplo
mostrar todas las entradas que se modificaron 3 das despus de su publicacin:
>>> from datetime import timedelta
>>> Entry.objects.filter(mod_date__gt=F('pub_date') + timedelta(days=3))
Por conveniencia, Django proporciona un atajo de bsqueda pk, que significa Clave primaria(por
primary key en ingles).
En el modelo de ejemplo Blog, la clave principal es el campo id , por lo que estas tres afirmaciones son
equivalentes
>>> Blog.objects.get(id__exact=14) # Forma Explicita
>>> Blog.objects.get(id=14) # __exact esta implcito
>>> Blog.objects.get(pk=14) # pk implica que es id__exact
El uso de claves primarias pk no se limita a consultas __exact - cualquier trmino de consulta se puede
combinar con ``pk` - para realizar una consulta en la clave principal de un modelo -:
# Get blogs entries with id 1, 4 and 7
>>> Blog.objects.filter(pk__in=[1,4,7])
# Get all blog entries with id > 14
>>> Blog.objects.filter(pk__gt=14)
Las bsquedas pk tambin trabajan a travs de uniones. Por ejemplo, estos tres declaraciones son
equivalentes:
>>> Entry.objects.filter(blog__id__exact=3) # Explicita forma
El atajo de bsqueda pk
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
>>> Entry.objects.filter(blog__id=3) # __exact esta implcito
>>> Entry.objects.filter(blog__pk=3) # __pk implica __id__exact
Los patrones de bsqueda que equivalen a una declaracin SQL LIKE ,
(iexact, contains, icontains,startswith, istartswith, endswith y iendswith) automticamente
escapan los dos caracteres especiales utilizados en las declaraciones LIKE - El signo de porcentaje y el
guin bajo. (En una declaracin LIKE , el signo de porcentaje significa un comodn de varios caracteres
y el guin bajo significa un comodn de un solo carcter.)
Esto significa que las cosas deben trabajar de manera intuitiva, por lo que la abstraccin no se
escapa. Por ejemplo, para recuperar todos los registros que contienen un signo de porcentaje, slo se
tiene que utilizar el signo de porcentaje como cualquier otro carcter:
>>> Entry.objects.filter(headline__contains='%')
Django se encarga de escapar estos caracteres por nosotros; El cdigo SQL resultante tendr un
aspecto parecido a este:
SELECT ... WHERE headline LIKE '%\%%';
Lo mismo sucede con los guiones bajos. Los dos signos de porcentaje y guiones bajos son manejados
de forma transparente.
Cada QuerySet contiene un cach, para reducir al mnimo el acceso a la base de datos. Es importante
entender cmo funciona, para escribir cdigo ms eficientemente.
En un QuerySet recin creado , la cach esta vaca. La primera vez que el QuerySet es evaluado - Y por
lo tanto la consulta ala base de datos sucede - Django guarda los resultados de la consulta en el
cache delQuerySets y devuelve los resultados que han sido explcitamente solicitados (por ejemplo, el
Escapando signos de porcentaje y guiones bajos en declaraciones LIKE
Cacheando Consultas
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
elemento siguiente, sobre el que esta iterando el QuerySet) Las evaluaciones siguientes
del QuerySet reusan los resultados de la cach.
Ten en cuenta este comportamiento de la cach, porque puede morderte si no utilizas de manera
correcta los QuerySets. Por ejemplo, el siguiente ejemplo crear dos QuerySets, los evaluara y los
descartara:
>>> print [e.headline for e in Entry.objects.all()]
>>> print [e.pub_date for e in Entry.objects.all()]
Eso significa que la misma consulta ala base de datos se ejecuta dos veces, duplicando la carga de la
base de datos. Adems, existe la posibilidad de que las dos listas no puedan ser incluidas en los
registros de la misma base, ya que una nueva entry puede haber sido aadida o eliminada, entre las
dos peticiones.
Para evitar este problema, simplemente guardamos el QuerySet y lo reutilizamos as:
>>> queryset = Entry.objects.all()
>>> print [p.headline for p in queryset] # Evaluate the query set.
>>> print [p.pub_date for p in queryset] # Re-use the cache from the evaluation.
Consultas de argumentos clave en mtodos filter(), etc. - son unidos a AND -. Si necesitamos
ejecutar consultas ms complejas (por ejemplo, consultas con clausulas OR), podemos usar objetos Q.
Un objeto Q (django.db.models.Q) es un objeto utilizado para encapsular una coleccin de argumentos
de palabras clave. Estos argumentos de palabras clave se especifican en las consultas
sobrepatrones de bsqueda.
Por ejemplo, este objeto Q encapsula una nica consulta LIKE:
from django.db.models import Q
Bsquedas complejas con objetos Q
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
Q(question__startswith='What')
Los objetos Q pueden ser combinados con los operadores & and |. Cuando un operador es utilizado en
dos objetos Q , se produce un nuevo objeto Q.
Por ejemplo, esta declaracin produce un nico objeto Q que representa el OR de dos
consultas"question__startswith":
Q(question__startswith='Who') | Q(question__startswith='What')
Esto es equivalente a la siguiente clusula SQL WHERE
WHERE question LIKE 'Who%' OR question LIKE 'What%'
Se pueden redactar declaraciones de complejidad arbitraria mediante la combinacin de objetos Q con
los operadores & y | y el uso de la agrupacin entre parntesis. Adems, los objetos Q pueden ser
anulados mediante el operador ~, lo que permite bsquedas combinadas que combinan una consulta
normal y una negativa (NOT)
Q(question__startswith='Who') | ~Q(pub_date__year=2005)
Cada funcin de bsqueda que toma argumentos clave (Por ejemplo filter(), exclude(), get())
puede recibir uno o ms objetos Q como argumentos posicionales (sin nombre). Si proporcionamos
mltiples argumentos de objetos Q a una funcin de bsqueda, los argumentos sern unidos con
AND. Por ejemplo:
Poll.objects.get(
Q(question__startswith='Who'),
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
)
... se traduce aproximadamente en SQL
SELECT * from polls WHERE question LIKE 'Who%'
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')
Las Funciones de bsqueda puede mezclar el uso de objetos y argumento de palabras clave Q. Todos
los argumentos provistos a la funcin de bsqueda (sean estos argumentos de palabra clave u
objetos Q) son unidos a AND. Sin embargo, si un objeto Q se proporciona, se debe preceder a la
definicin de los argumentos de palabras clave. Por ejemplo:
Poll.objects.get(
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
question__startswith='Who')
... sera una consulta vlida, equivalente al ejemplo anterior, pero
# INVALID QUERY
Poll.objects.get(
question__startswith='Who',
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))
... no sera vlido.
See also
Las OR lookups examples pruebas unitarias de Django muestran algunos usos posibles de Q.
Para comparar dos instancias de un modelo, slo tenemos que utilizar el operador estndar de
comparacin de Python, el signo doble de igualdad: ==. detrs de escena compara la clave primaria de
dos models. Usando el ejemplo anterior Entry las siguientes dos declaraciones son equivalentes:
>>> some_entry == other_entry
>>> some_entry.id == other_entry.id
Comparando objetos
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
Si la clave primaria del modelo no es llamada id, no hay problema, las comparaciones utilizan siempre
la clave principal siempre que son llamadas. Por ejemplo si una clave primaria de un campo de modelo
es llamada name estas dos declaraciones son equivalentes:
>>> some_obj == other_obj
>>> some_obj.name == other_obj.name
El mtodo para borrar, convenientemente, se llama delete(). Este mtodo elimina inmediatamente el
objeto y no devuelve ningn valor. Ejemplo:
e.delete()
Tambin se pueden eliminar objetos de forma masiva. Cada QuerySet tiene un mtodo delete(), que
elimina todos los miembros del QuerySet.
Por ejemplo, esto elimina todos los objetos Entry con un campo pub_date de el ao 2005:
Entry.objects.filter(pub_date__year=2005).delete()
Devemos tener en cuenta que esto, es siempre posible, porque estamos ejecutando exclusivamente
SQL, el mtodo delete() en instancias de objetos individuales no necesariamente sera llamado
durante el proceso. Si se ha ha proporcionado un mtodo propio delete() en una clase del modelo y
queremos asegurarnos de que se le llama, tendremos que hacerlo de forma Manual eliminando las
instancias de ese modelo (por ejemplo, iterando sobre un QuerySet y llamando al mtodo delete() en
cada objeto individualmente) en lugar de utilizar masivamente el mtodo delete() en un QuerySet.
Cuando se elimina un objeto, por defecto Django emula el comportamiento SQL ON DELETE CASCADE -
es decir, los objetos que tenan claves forneas o foreign keys que apunta al objeto que se desea
borrar se elimina junto con ella. Por ejemplo:
Borrando objetos
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
b = Blog.objects.get(pk=1)
# Esto borra el Blog y todos los objetos Entry.
b.delete()
New in Django 1.3: Este comportamiento de cascada es personalizable a travs del
argumentoon_delete y el argumento ForeignKey.
Ten en cuenta que el mtodo delete() es el nico mtodo QuerySet que no esta expuesto a
una Manageren s mismo. Este es un mecanismo de seguridad para evitar que accidentalmente
solicitandoEntry.objects.delete() borremos todas las entradas. Sin embargo si queremos
borrar todas las entradas tenemos que solicitar explcitamente una consulta completa e invocar a el
mtodo:
Entry.objects.all().delete()
Aunque no existe un mtodo integrado para la copia de instancias de modelo, es posible crear
fcilmente nuevas instancia con los valores de todos los campos copiado. En el caso ms sencillo,
basta con establecerpk a None. Usando nuestro ejemplo blog:
blog = Blog(name='My blog', tagline='Blogging is easy')
blog.save() # post.pk == 1
blog.pk = None
blog.save() # post.pk == 2
Las cosas se complican ms si se utiliza la herencia. Consideremos una subclase de Blog
class ThemeBlog(Blog):
theme = models.CharField(max_length=200)
django_blog = ThemeBlog(name='Django', tagline='Django is easy', theme = 'python')
django_blog.save() # django_blog.pk == 3
Copiando una instancia de un modelo
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
Debido a cmo funciona la herencia, se tiene que especificar tanto pk e id a None:
django_blog.pk = None
django_blog.id = None
django_blog.save() # django_blog.pk == 4
Este proceso no copia las relaciones entre objetos. Si deseas copiar las relaciones, tienes que escribir
un poco ms cdigo. En nuestro ejemplo, Entry tiene un campo muchos a muchos relacionado a un
campoauthor
entry = Entry.objects.all()[0] # some previous entry
old_authors = entry.authors.all()
entry.pk = None
entry.save()
entry.authors = old_authors # saves new many2many relations
Algunas veces lo que deseamos es establecer un valor en particular de un campo para todos los
objetos de un QuerySet. Podemos hacer hacer esto con el mtodo update(). Por ejemplo:
# Update all the headlines with pub_date in 2007.
Entry.objects.filter(pub_date__year=2007).update(headline='Everything is the same')
Lo nico que no podemos establecer es una relacin de campos ForeignKey utilizando este mtodo.
Para actualizar un campo no-relacionado, proveemos el nuevo valor como una constante. Para
actualizar un campo ForeignKey, establesemos el nuevo valor a la instancia del nuevo modelo al que
deseamos apuntar. Por ejemplo:
>>> b = Blog.objects.get(pk=1)
# Cambiamos la entrada para que pertenesca al Blog.
>>> Entry.objects.all().update(blog=b)
Actualizando varios objetos a la vez
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
El mtodo update() se aplica inmediatamente y devuelve el nmero de filas que concuerdan con la
consulta (que puede no ser igual al nmero de filas actualizadas si algunas filas ya tienen el nuevo
valor). La nica restriccin en un QuerySet que se actualiza es que slo se puede acceder a una tabla
de base de datos, la tabla principal del modelo. Podemos filtrar basados en la relacin de campos,
pero slo se pueden actualizar columnas principales del modelo. Ejemplo:
>>> b = Blog.objects.get(pk=1)
# Actualiza todos los ttulos del blog.
>>> Entry.objects.select_related().filter(blog=b).update(headline='Everything is the same')
Ten en cuenta que el mtodo update() es convertido directamente en una sentencia de SQL . Se trata
de una operacin masiva de actualizaciones directas. No se ejecuta ningn mtodo save() en los
modelos, o se emiten seales pre_save o un post_save (que son una consecuencia de la
llamada save()), en honor de la opcin de campo auto_now.Si deseas guardar cada elemento en de
un QuerySet deves asegurarte que el mtodo save() sea llamado en cada caso, No necesitas ninguna
funcin especial para manejar esto. Slo un bucle que llame sobre cada uno de ellos y llame al
mtodo save():
for item in my_queryset:
item.save()
Las llamadas a actualizar tambin pueden utilizar F() objects para actualizar un campo basndose en el
valor de otro campo en el modelo. Esto es especialmente til para incrementar los contadores
basados en los valores actuales. Por ejemplo, para incrementar el contador de pingbacks por cada
entrada en el blog:
>>> Entry.objects.all().update(n_pingbacks=F('n_pingbacks') + 1)
Sin embargo, a diferencia de los objetos F() en filtros y clusulas exclude, no podr introducir uniones
al usar objetos F() en una actualizacin - slo se puede referenciar campos locales al modelo que se
esta actualizando. Si deseas intentar introducir una unin con un objeto F(), un
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
error ``FieldError``sera lanzado:
# THIS WILL RAISE A FieldError
>>> Entry.objects.update(headline=F('blog__name'))
Cuando se define una relacin en un modelo (es decir, un ForeignKey, OneToOneField,
oManyToManyField), las instancias de ese modelo tendrn acceso a una conveniente API para acceder
alas relaciones de los objeto(s).
Utilizando el modelos que definimos en la parte superior de esta pgina, por ejemplo, un objeto e de
unaEntry pueden ser asociado al objeto Blog accediendo al objeto blog mediante su atributo: e.blog.
(Detrs de escena, esta funcionalidad se implementa mediante Python descriptors. Esto no es
realmente importarte, lo sealamos aqu solo para los curiosos).
Django tambin crea un acceso ala API para el otro lado de la relacin - el enlace de la relacin del
modelo relacionado con el modelo que define la relacin -. Por ejemplo, un objeto b del Blog tiene
acceso a una lista de todas las relaciones de objetos Entry mediante el
atributo entry_set : b.entry_set.all().
Todos los ejemplos de esta seccin utilizan el mismo modelo Blog, Author y Entry que definimos en la
parte superior de esta pgina.
Si un modelo tiene una clase ForeignKey, las instancias de ese modelo tendr acceso a la relacin del
objeto forneo a travs de un simple atributo del modelo.
Ejemplo:
Relaciones de objetos
Relaciones One-to-many
Adelante
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
Ejemplo:
>>> e = Entry.objects.get(id=2)
>>> e.blog # Devuelve el objeto relacionado.
Podemos obtener y asignar a travs de un atributo la clave fornea. Como se pueden esperar, los
cambios en la clave fornea no se guardan en la base de datos hasta que se llama explcitamente al
mtodo save(). Por ejemplo
>>> e = Entry.objects.get(id=2)
>>> e.blog = some_blog
>>> e.save()
Si una clase ForeignKey tiene un campo null=True (es decir, permite valores NULL), se le puede
asignarNone como en este ejemplo:
>>> e = Entry.objects.get(id=2)
>>> e.blog = None
>>> e.save() # "UPDATE blog_entry SET blog_id = NULL ...;"
Para tener acceso a una relacin one-to-many esta debe ser cacheada la primera vez que el objeto
relacionado sea accedido. Accesos posteriores a la clave fornea para la misma instancia del objeto
estn almacenados en cach. Ejemplo:
>>> e = Entry.objects.get(id=2)
>>> print e.blog # Hits the database to retrieve the associated Blog.
>>> print e.blog # Doesn't hit the database; uses cached versin.
Nota que el mtodo del QuerySet select_related() recursivamente carga en la cache inmediatamente
todos los objetos de relaciones uno-a-muchos de la instancia:
>>> e = Entry.objects.select_related().get(id=2)
>>> print e.blog # Doesn't hit the database; uses cached versin.
>>> print e.blog # Doesn't hit the database; uses cached versin.
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
Si un modelo tiene una ForeignKey, las instancias del modelo de clave fornea tendrn acceso a
unManager que devuelve todas las instancias del primer modelo. Por defecto, este Manager es
llamadoFOO_set, donde FOO es el nombre de origen del modelo, en minsculas.
El Manager retorna QuerySets , que pueden ser filtrados y manipulados como se describe en la seccin
recuperando objetos mas arriba. Ejemplo:
>>> b = Blog.objects.get(id=1)
>>> b.entry_set.all() # Returns all Entry objects related to Blog.
# b.entry_set is a Manager that returns QuerySets.
>>> b.entry_set.filter(headline__contains='Lennon')
>>> b.entry_set.count()
Podemos sustituir el nombre FOO_set cambiando la configuracin de los parmetros related_name en la
definicin del ForeignKey() . Por ejemplo, si el modelo Entry fuera alterado
ablog = ForeignKey(Blog, related_name='entries'), el cdigo de ejemplo anterior se vera as:
>>> b = Blog.objects.get(id=1)
>>> b.entries.all() # Returns all Entry objects related to Blog.
# b.entries is a Manager that returns QuerySets.
>>> b.entries.filter(headline__contains='Lennon')
>>> b.entries.count()
No se puede acceder a una relacin inversa ForeignKey Manager de la clase, sino que estos deben de
tener acceso desde una instancia:
>>> Blog.entry_set
Traceback:
...
AttributeError:"Manager debe acceder a travs de instancia".
Adems de los mtodos QuerySet definidos anteriormente en Recuperacin de
Siguiendo relaciones inversa
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
objetos ForeignKeyManager tienen mtodos adicionales que se utilizan para manejar un conjunto de
objetos relacionados. Una sinopsis de cada uno es descrita mas abajo y se pueden obtener ms
detalles enrelated objects reference.
add(obj1, obj2, ...)
Agrega los objetos del modelo especificados para el conjunto de objetos relacionados.
create(**kwargs)
Crea un nuevo objeto, lo guarda y lo coloca en el conjunto de objetos relacionados. Devuelve el
objeto recin creado.
remove(obj1, obj2, ...)
Elimina los objetos del modelo especificado en el conjunto de objetos relacionados.
clear()
Elimina todos los objetos del conjunto de objetos relacionados.
Para asignar los miembros de un conjunto relacionado de un solo golpe, podemos asignarle cualquier
objeto iterable. El iterable puede contener instancias de objetos o simplemente una lista de valores
de la clave principal. Por ejemplo:
b = Blog.objects.get(id=1)
b.entry_set = [e1, e2]
En este ejemplo, e1 y e2 pueden tener instancias completas o valores enteros, de claves primarias.
Si el mtodo clear() est definido, los objetos pre-existentes sern removidos de el entry_set antes
que todos los objetos en el iterable (en este caso, una lista) se aade al conjunto. Si el
mtodo clear() no esta disponible, todos los objetos en el iterable sern agregados sin ningn
elemento existente .
Cada operacin inversa descrita en esta seccin tiene un efecto inmediato en la base de datos.
Cada adicin, creacin y eliminacin es inmediata y se guarda automticamente en la base de datos.
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
Ambos extremos de las relaciones muchos a muchos,obtienen acceso automtico a la API. La API
funciona igual que las relaciones inversas uno-a-muchos, descritas anteriormente.
La nica diferencia est en el nombre del atributo: El modelo que define el ManyToManyField usa el
nombre del atributo del campo en s mismo, mientras que el modelo inverso utiliza el nombre del
modelo original en minsculas, adems de un sufijo '_set' (Justo en modo inverso a como lo hacen las
relacin one-to-many).
Un ejemplo lo hace ms fcil de entender:
e = Entry.objects.get(id=3)
e.authors.all() # Returns all Author objects for this Entry.
e.authors.count()
e.authors.filter(name__contains='John')
a = Author.objects.get(id=5)
a.entry_set.all() # Returns all Entry objects for this Author.
Como ForeignKey, ManyToManyField se puede especificar un related_name. En el ejemplo anterior, si
laManyToManyField en Entry se hubiera especificado related_name='entries' , entonces cada instancia
deAuthor tendra un atributo entries en lugar de entry_set.
La relaciones Uno-a-uno son muy parecidas alas relaciones many-to-one.Si definimos
una OneToOneFielden nuestro modelo .Las instancias de este modelo tienen acceso al objeto
relacionado a travs de un simple atributo del modelo.
Por ejemplo:
class EntryDetail(models.Model):
entry = models.OneToOneField(Entry)
details = models.TextField()
Relaciones Many-to-many
Relaciones One-to-one
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
ed = EntryDetail.objects.get(id=2)
ed.entry # Returns the related Entry object.
La diferencia est en las consultas inversas. El modelo relacionado en una relacin uno-a-uno
tambin tiene acceso a un objeto Manager, pero el Manager representa un objeto nico, en lugar de
una coleccin de objetos:
e = Entry.objects.get(id=2)
e.entrydetail # returns the related EntryDetail object
Si ningn objeto ha sido asignado a la relacin, Django lanzara una excepcin DoesNotExist.
Las instancias pueden ser asignados en relaciones inversas de la misma manera como asignaramos
un relacin hacia adelante:
e.entrydetail = ed
Otros mapeadores objeto-relacional requieren que definamos las relaciones en ambos lados. Los
desarrolladores de Django creen que esto es una violacin al principio DRY (no te repitas), as que
Django slo requiere que se defina la relacin en un extremo.
Pero, cmo es esto posible, dado que una clase modelo no sabe qu otras clases modelo estn
relacionados con ella hasta que las clases de otros modelos se cargan?
La respuesta est en los ajustes del archivo de configuracin INSTALLED_APPS . La primera vez que
cualquier modelo se carga, Django itera sobre cada modelo en INSTALLED_APPS y crea las relaciones
inversas en la memoria cuando sea necesario. Esencialmente, una de las funciones
de INSTALLED_APPS es decirle a Django sobre todos los modelos del dominio que utiliza.
Cmo son posibles las relaciones inversas?
Consultas sobre relaciones de objetos
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
Las consultas que involucran relaciones de objetos siguen las mismas reglas que las consultas que
implican los campos de valores normales. Al especificar el valor de una consulta que que coincide con
una bsqueda, es posible que utilizemos cualquiera de las instancias del objeto en s, o el valor de la
clave principal del el objeto.
Por ejemplo, si tenemos un objeto Blog b con id=5, las siguientes tres consultas seran idnticas:
Entry.objects.filter(blog=b) # Query using object instance
Entry.objects.filter(blog=b.id) # Query using id from instance
Entry.objects.filter(blog=5) # Query using id directly
Si lo que necesitas para escribir una consulta SQL es demasiado complejo para el mapeador de la
base de datos de Django, podemos escribir el SQL a mano. Django tiene un par de opciones para
escribir consultas SQL , vase /topics/db/sql.
Finalmente, es importante sealar que la capa de base de datos de Django es meramente una
interfaz a la base de datos. Puedes acceder a ala base de datos a utilizando otras herramientas,
lenguajes de programacin o frameworks de bases de datos, no hay nada especfico de Django sobre
las base de datos.
Publicado 28th November 2012 por Saul Garcia
Etiquetas: base de datos, Django

Creando SQL Crudo

0
Aadir un comentario
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
Para definir una relacion muchos a uno, utilizamos la clase ForeignKey.
from django.db import models
class Reporter(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
email = models.EmailField()
def __unicode__(self):
return u"%s %s" % (self.first_name, self.last_name)
class Article(models.Model):
headline = models.CharField(max_length=100)
pub_date = models.DateField()
reporter = models.ForeignKey(Reporter)
def __unicode__(self):
return self.headline
class Meta:
ordering = ('headline',)
Estos ejemplos que siguen son operaciones que se pueden realizar usando la API interactiva que nos
facilita python.
Creamos algunos reporteros:
>>> r = Reporter(first_name='John', last_name='Smith', email='john@example.com')
>>> r.save()
27
NOV
Relaciones Many-to-one
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
>>> r2 = Reporter(first_name='Paul', last_name='Jones', email='paul@example.com')
>>> r2.save()
Creamos un artculo:
>>> from datetime import datetime
>>> a = Article(id=None, headline="This is a test", pub_date=datetime(2005, 7, 27), reporte
r=r)
>>> a.save()
>>> a.reporter.id
1
>>> a.reporter
<Reporter: John Smith>
Los objetos artculo tienen acceso a sus objetos relacionados reportero:
>>> r = a.reporter
stas son cadenas en vez de las cadenas unicode, porque eso es lo que fue utilizada dentro la
creacin de este reportero (y nosotros no hemos refrescado los datos de la base de datos, por lo que
nos devuelve siempre las cadenas unicode):
>>> r.first_name, r.last_name
('John', 'Smith')
Creamos un artculo va el objeto reportero:
>>> new_article = r.article_set.create(headline="John's second story", pub_date=datetime(20
05, 7, 29))
>>> new_article
<Article: John's second story>
>>> new_article.reporter
<Reporter: John Smith>
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
>>> new_article.reporter.id
1
Creamos un nuevo artculo y lo agregamos al artculo anterior:
>>> new_article2 = Article(headline="Paul's story", pub_date=datetime(2006, 1, 17))
>>> r.article_set.add(new_article2)
>>> new_article2.reporter
<Reporter: John Smith>
>>> new_article2.reporter.id
1
>>> r.article_set.all()
[<Article: John's second story>, <Article: Paul's story>, <Article: This is a test>]
Agregamos el mismo artculo a un diferente artculo - comprobamos que se mueve -:
>>> r2.article_set.add(new_article2)
>>> new_article2.reporter.id
2
>>> new_article2.reporter
<Reporter: Paul Jones>
Si agregamos un objeto del tipo incorrecto django levanta una excepcin del tipo TypeError:
>>> r.article_set.add(r2)
Traceback (most recent call last):
...
TypeError: 'Article' instance expected
>>> r.article_set.all()
[<Article: John's second story>, <Article: This is a test>]
>>> r2.article_set.all()
[<Article: Paul's story>]
>>> r.article_set.count()
2
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
>>> r2.article_set.count()
1
Observamos que en el ejemplo anterior el artculo se ha movido desde John a Paul. El manejador de
relaciones soporta las operaciones de bsqueda tambin en el campo. El API sigue automticamente
las relaciones por lo que no se necesita, utilizar los guiones bajos para separar las relaciones.Esto
trabaja tan profundamente en tantos niveles como queramos. No hay lmite. Por ejemplo:
>>> r.article_set.filter(headline__startswith='This')
[<Article: This is a test>]
# Find all Articles for any Reporter whose first name is "John".
>>> Article.objects.filter(reporter__first_name__exact='John')
[<Article: John's second story>, <Article: This is a test>]
El mismo caso esta implicado aqui:
>>> Article.objects.filter(reporter__first_name='John')
[<Article: John's second story>, <Article: This is a test>]
Podemos hacer un query dos veces sobre el campo relacionado. Trasladamos la condicin AND y la
clausula WHERE:
>>> Article.objects.filter(reporter__first_name__exact='John', reporter__last_name__exact='
Smith')
[<Article: John's second story>, <Article: This is a test>]
Para las operaciones de relaciones y bsqueda podemos suministrar un valor primario o pasar el
objeto relacionado explcitamente:
>>> Article.objects.filter(reporter__pk=1)
[<Article: John's second story>, <Article: This is a test>]
>>> Article.objects.filter(reporter=1)
[<Article: John's second story>, <Article: This is a test>]
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
>>> Article.objects.filter(reporter=r)
[<Article: John's second story>, <Article: This is a test>]
>>> Article.objects.filter(reporter__in=[1,2]).distinct()
[<Article: John's second story>, <Article: Paul's story>, <Article: This is a test>]
>>> Article.objects.filter(reporter__in=[r,r2]).distinct()
[<Article: John's second story>, <Article: Paul's story>, <Article: This is a test>]
Podemos utilizar un queryset en vez de una lista literal de instancias:
>>> Article.objects.filter(reporter__in=Reporter.objects.filter(first_name='John')).distinc
t()
[<Article: John's second story>, <Article: This is a test>]
Podemos hacer una consulta en la direccin opuesta:
>>> Reporter.objects.filter(article__pk=1)
[<Reporter: John Smith>]
>>> Reporter.objects.filter(article=1)
[<Reporter: John Smith>]
>>> Reporter.objects.filter(article=a)
[<Reporter: John Smith>]
>>> Reporter.objects.filter(article__headline__startswith='This')
[<Reporter: John Smith>, <Reporter: John Smith>, <Reporter: John Smith>]
>>> Reporter.objects.filter(article__headline__startswith='This').distinct()
[<Reporter: John Smith>]
El mtodo Counting trabaja en la direccin opuesta conjuntamente con el mtodo distinct():
>>> Reporter.objects.filter(article__headline__startswith='This').count()
3
>>> Reporter.objects.filter(article__headline__startswith='This').distinct().count()
1
Los Queries pueden trabajar en crculos:
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
>>> Reporter.objects.filter (article__reporter__first_name__startswith='John')
[<Reporter: Juan Smith>, <Reporter: Juan Smith>, <Reporter: Juan Smith>, <Reporter: >>> Rep
orter.objects.filter (article__reporter__first_name__startswith='John').distinct de Juan Sm
ith>] ()
[<Reporter: Juan Smith>]
>>> Reporter.objects.filter (article__reporter__exact=r).distinct ()
[<Reporter: Juan Smith>]
Si borramos un reportero, sus artculos sern borrados (asumiendo que el campo ForeignKey fue
definido con el atributo django.db.models.ForeignKey.on_delete lo seteamos a ``CASCADE`, que es el
que usa por defecto):
>>> Article.objects.all()
[<Article: John's second story>, <Article: Paul's story>, <Article: This is a test>]
>>> Reporter.objects.order_by('first_name')
[<Reporter: John Smith>, <Reporter: Paul Jones>]
>>> r2.delete()
>>> Article.objects.all()
[<Article: John's second story>, <Article: This is a test>]
>>> Reporter.objects.order_by('first_name')
[<Reporter: John Smith>]
Podemos borrar usando JOIN en un query:
>>> Reporter.objects.filter(article__headline__startswith='This').delete()
>>> Reporter.objects.all()
[]
>>> Article.objects.all()
[]
Publicado 27th November 2012 por Saul Garcia
Etiquetas: base de datos, Django

pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API

0
Aadir un comentario
Una vez que hayas creado tus data models Django automticamente proporciona a tu API de base de
datos abstraccin que te permite crear, recuperar, actualizar y eliminar objetos. Este documento
explica cmo utilizar esta API. Consulta la data model reference para una referencia completa y
detallada de todos los modelos y las diversas opciones de bsqueda.
A lo largo de esta gua (y en la de referencia), nos referiremos a los siguientes modelos, que incluyen
una aplicacin web blog:
class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField()
def __unicode__(self):
return self.name
class Author(models.Model):
name = models.CharField(max_length=50)
email = models.EmailField()
def __unicode__(self):
return self.name
class Entry(models.Model):
27
NOV
Realizando consultas
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
blog = models.ForeignKey(Blog)
headline = models.CharField(max_length=255)
body_text = models.TextField()
pub_date = models.DateTimeField()
mod_date = models.DateTimeField()
authors = models.ManyToManyField(Author)
n_comments = models.IntegerField()
n_pingbacks = models.IntegerField()
rating = models.IntegerField()
def __unicode__(self):
return self.headline
Para representar una tabla en una base de datos con objetos Python, Django utiliza un intuitivo
sistema: Una clase de modelo representa una tabla de base de datos y una instancia de esta clase
representa un registro en particular en la tabla de base de datos.
Para crear un objeto, lo instanciamos utilizando argumentos clave a la clase del modelo, a
continuacin, llamamos al mtodo save() para guardarlo en la base de datos.
Importamos la clase del modelo del camino de bsqueda de Python o path, como se podra esperar.
(Sealamos esto aqu porque en versiones anteriores de Django se requera importar el modelo de
una forma no muy fina.)
Suponiendo que nuestro modelo viva en el archivo mysite/blog/models.py, he aqu un ejemplo:
>>> from blog.models import Blog
>>> b = Blog(name='Beatles Blog', tagline='All the latest Beatles news.')
>>> b.save()
Esto, detrs de escena, ejecuta una sentencia SQL INSERT. Django no accede a la base de datos
hasta que explcitamente llamemos a el mtodo save().
Creando de objetos
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
El mtodo save() no devuelve ningn valor.
See also
El mtodo save() contiene una serie de opciones avanzadas que no se describen aqu.
Consulta la documentacin del mtodo save() para ms detalles.
Para crear y guardar un objeto en un solo paso, utilizamos el mtodo create().
Para guardar los cambios realizados en un objeto que ya est en la base de datos, utilizamos el
mtodosave().
Dado una instancia Blog que tiene un objeto b5 que ya se ha guardado en la base de datos, este
ejemplo, cambia su nombre y actualiza su registro en la base de datos:
>> b5.name = 'New name'
>> b5.save()
Detrs de escena, esto ejecuta una sentencia SQL UPDATE. Django no accede a la base de datos hasta
que se llama explcitamente a el mtodo save().
La actualizacin de un campo ForeignKey funciona exactamente de la misma forma en que funciona
guardar un campo normal - simplemente asignamos un objeto del tipo adecuado para el campo en
cuestin . Este ejemplo actualiza blog y los atributos Entry con una instancia entry:
>>> from blog.models import Entry
>>> entry = Entry.objects.get(pk=1)
>>> cheese_blog = Blog.objects.get(name="Cheddar Talk")
>>> entry.blog = cheese_blog
Grabando cambios en objetos
Guardar un campo ForeignKey y ManyToManyField
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
>>> entry.save()
La actualizacin de un campo ManyToManyField funciona un poco diferente - utilizamos el
mtodo add()en el campo para agregar un registro a la relacin. En este ejemplo agregamos
a Author una instancia joedel objeto entry:
>>> from blog.models import Author
>>> joe = Author.objects.create(name="Joe")
>>> entry.authors.add(joe)
Para agregar varias grabaciones ManyToManyField en una sola llamada usamos el mtodo add() de
esta forma:
>>> john = Author.objects.create(name="John")
>>> paul = Author.objects.create(name="Paul")
>>> george = Author.objects.create(name="George")
>>> ringo = Author.objects.create(name="Ringo")
>>> entry.authors.add(john, paul, george, ringo)
Django se quejar si se intenta asignar o aadir un objeto del tipo incorrecto.
Para recuperar objetos de la base de datos, construimos un QuerySet o sea una consulta a travs de
una clase Manager.
Un QuerySet representa una coleccin de objetos a partir de la base de datos. Que pueden tener cero,
uno o muchos filtros (filters) - criterios que pueden reducir la coleccin basndose en parmetros
dados -. En trminos SQL, un QuerySet equivale a una declaracin SELECT y un filtro es una clusula de
limitacinWHERE o LIMIT.
Podemos traer un QuerySet usando el Manager de su modelo. Cada modelo tiene al menos
uno Manager, y este es llamado objects por default. Podemos acceder a l directamente a travs de la
Recuperando objetos
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
clase del modelo, as
>>> Blog.objects
<django.db.models.manager.Manager object at ...>
>>> b = Blog(name='Foo', tagline='Bar')
>>> b.objects
Traceback:
...
AttributeError: "Manager isn't accessible via Blog instances."
Note
Los Managers son accesibles nicamente a travs de las clases del modelo, en vez que
desde una instancia, para aplicar una separacin entre las operaciones a nivel de tabla
y las operaciones A nivel de registro.
El Manager es la principal fuente de QuerySets de un modelo. Acta como una clase raz
de QuerySetque describe todos los objetos de la tabla de base de datos del modelo. Por
ejemplo, Blog.objects es elQuerySet inicial que contiene todos los objetos Blog de la base de datos.
La forma ms sencilla de recuperar objetos de una tabla es conseguir todos juntos de una vez. Para
hacer esto, usamos el mtodo all() en un Manager as:
>>> all_entries = Entry.objects.all()
El mtodo all() devuelve un QuerySet de todos los objetos de la base de datos.
(Si Entry.objects es una clase QuerySet, Por qu no podemos usar simplemente Entry.objects ?
Esto es porque la clase raz Entry.objects , es un caso especial que no puede ser evaluado. El
mtodo all()devuelve un QuerySet que puede ser evaluado).
Recuperando todos los objetos
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
La clase raz QuerySet proporcionada por el Manager describe todos los objetos de la base de datos.
Por lo general, solo necesitaremos seleccionar un subconjunto del conjunto completo de objetos.
Para crear un subconjunto, necesitamos refinar el QuerySet inicial agregando condiciones con filtros.
Las dos formas ms comunes para refinar un QuerySet son:
filter(**kwargs)
Devuelve un nuevo QuerySet conteniendo los objetos que coinciden con los parmetros de
bsqueda indicados.
exclude(**kwargs)
Devuelve un nuevo QuerySet conteniendo los objetos que que no coinciden con los parmetros de
bsqueda indicados.
Los parmetros de bsqueda (**kwargs en las definiciones de las funciones anteriores) debern estar
en el formato descrito en las Bsquedas en campos mas abajo.
Por ejemplo, para obtener un QuerySet de las entradas del blog desde el ao 2006, usamos el
mtodofilter() as:
Entry.objects.filter(pub_date__year=2006)
No es necesario agregar un mtodo all() Entry.objects.all().filter(...) . Este mtodo
funciona todava as, pero slo se necesita el all() cuando se quieran todos los objetos de la clase
raz QuerySet.
El resultado de refinar un QuerySet es en s mismo un QuerySet, as que es posible juntar y encadenar
refinamientos. Por ejemplo:
Recuperando objetos especficos mediante filtros
Encadenando filtros
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
>>> Entry.objects.filter(
... headline__startswith='What'
... ).exclude(
... pub_date__gte=datetime.now()
... ).filter(
... pub_date__gte=datetime(2005, 1, 1)
... )
Tomamos el inicial QuerySet de todas las entradas de la base de datos, aadimos un filtro, luego una
exclusin y a continuacin otro filtro. El resultado final es un QuerySet que contiene todas las entradas
con un ttulo que empieza con What, que se publicaron entre 01 de enero del 2005 y el da actual.
Cada vez que se modifica un QuerySet, se obtiene un nuevo QuerySet que no es de ninguna manera el
anterior QuerySet. Cada refinamiento crea distintos y separados QuerySet que pueden ser
almacenados, utilizados y reutilizados.
Ejemplo
>> q1 = Entry.objects.filter(headline__startswith="What")
>> q2 = q1.exclude(pub_date__gte=datetime.now())
>> q3 = q1.filter(pub_date__gte=datetime.now())
Estos tres QuerySets son distintos entre si. El primer es un QuerySet que contiene todas las entradas
que contengan un titulo que comienza con What.
El segundo es un subconjunto del primero, con unos criterios adicionales que excluyen los registros
cuyopub_date sea mayor que ahora.
El tercero es un subconjunto de la primera, con un criterio adicional que selecciona slo los registros
cuyopub_date sea mayor que ahora. El inicial QuerySet (q1) no se ve afectado por el refinamiento del
proceso.
Los QuerySets filtrados son nicos
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
Los QuerySets son perezosos - el acto de crear un QuerySet no involucra ninguna actividad en la base
de datos. Se pueden aplicar filtros todo el da y Django no ejecutara las consultas hasta que
el QuerySet seaEvaluado. Echa un vistazo a este ejemplo
>>> q = Entry.objects.filter(headline__startswith="What")
>>> q = q.filter(pub_date__lte=datetime.now())
>>> q = q.exclude(body_text__icontains="food")
>>> print q
Aunque en este ejemplos parezca que hemos echo tres consultas a la bases de datos, de hecho, solo
llego una vez a la base de datos, en la ltima lnea en que llamamos a (print q). En general, los
resultados de un QuerySet no se obtienen de la base de datos hasta que preguntamos por ellos.
Cuando lo hacemos, elQuerySet es evaluado accediendo a la base de datos. Para ms detalles sobre
como exactamente se lleva a cabo la evaluacin puedes ver when-querysets-are-evaluated.
El mtodo filter() siempre retornara un QuerySet, aunque sea solo un objeto el que coincida con la
consulta en este caso, ser un QuerySet que contiene un solo elemento .
Si conocemos que hay un slo objeto que coincida con la consulta, se puede utilizar el el
mtodo get() en un Manager para que devuelva el objeto directamente:
>>> one_entry = Entry.objects.get(pk=1)
Podemos utilizar cualquier expresin de consulta con el mtodo get(), al igual que con el
mtodo filter()- de nuevo, puedes consultar la seccin Bsquedas en campos a continuacin.
Ten en cuenta que existe una diferencia entre el uso del mtodo get() y el uso de el
mtodo filter()cuando un slice retorna [0]. Si no hay resultados que coincidan con la consulta del
mtodo, get() sera lanzada una excepcin DoesNotExist. Esta excepcin es un atributo de la clase del
modelo que la consulta esta realizando - por lo que en el cdigo anterior, si no hay ningn
Los QuerySets son perezosos
Recuperando un solo objeto con get
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
objeto Entry con una clave primaria 1, Django levantar una excepcin Entry.DoesNotExist.
Del mismo modo, Django se quejar si ms de un elemento coincide con la consulta del get() . En este
caso, lanzara una excepcin MultipleObjectsReturned, que a su vez es un atributo de la clase del
modelo en s mismo.
La mayor parte de las veces usaremos el mtodo all(), get(), filter() y exclude() cuando
necesitemos buscar objetos de la base de datos. Sin embargo, esto es solo una parte de la QuerySet
API Reference para mas mtodos puedes obtener una lista completa de todos los mtodos QuerySet .
Podemos utilizar la sintaxis de python array-slicing o rebanado de matrices para limitar
un QuerySetcon un cierto nmero de resultados. Esta es el equivalente a las clausulas SQL LIMIT y
a OFFSET.
Por ejemplo, este devuelve los 5 primeros objetos (LIMIT 5):
>>> Entry.objects.all()[:5]
Esto devuelve los objetos del sexto al dcimo (OFFSET 5 LIMIT 5):
>>> Entry.objects.all()[5:10]
La Indexacin negativa (por ejemplo, Entry.objects.all()[-1] ) no esta permitida.
Por lo general, rebanar QuerySet devuelve un nuevo QuerySet - Este no evala la consulta. Una
excepcin es si se utilizamos los parmetro de la sintaxis de rebanado python. Por ejemplo, esto
ejecutara la consulta para devolver una lista de cada dos objetos en los primeros 10:
>>> Entry.objects.all()[:10:2]
Otros mtodos de los QuerySet
Limitando QuerySets
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
Para recuperar un solo objeto en lugar de una lista (por ejemplo SELECT foo FROM bar LIMIT 1 ),
utilizamos un simple ndice en lugar de una rebanada. Por ejemplo, esto retornara la primera
entradaEntry de la base de datos, despus de ordenar las entradas en orden alfabtico por ttulo
>>> Entry.objects.order_by('headline')[0]
Esto es aproximadamente equivalente a:
>>> Entry.objects.order_by('headline')[0:1].get()
Nota, sin embargo, que el primero de estos lanzara un error IndexError mientras que el segundo
lanzara un DoesNotExist si no hay objetos que coinciden con los criterios dados. Puedes ver el
mtodo get() para ms detalles.
Las bsquedas en los campos son la forma de especificar la carne a una clausula SQL WHERE. Estas
consisten en argumentos clave tales como QuerySet, mtodos filter(), exclude() y get().
Los argumentos clave y parmetros bsicos que aceptan las bsquedas toman la
formafield__lookuptype=value (Esto es un guin doble bajo). Por ejemplo:
>>> Entry.objects.filter(pub_date__lte='2006-01-01')
traducido(mas o menos) al comando SQL siguiente:
SELECT * FROM blog_entry WHERE pub_date <= '2006-01-01';
Como es esto posible?
Python tiene la capacidad de definir las funciones que aceptan nombres y valores
arbitrarios cuyos nombres, argumentos y valores se evalan en tiempos de ejecucin.
Para obtener ms informacin, consulta la seccin Keyword Arguments en el tutorial oficial
Bsquedas en campos
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
de Python.
Changed in Django 1.4: Please see the release notes
El campo especificado en una bsqueda tiene que ser el nombre de un campo de un modelo. Sin
embargo hay una excepcin, en caso de un ForeignKey se puede especificar el nombre del campo
con el sufijo _id . En este caso, el parmetro de valor que se espera para contener el valor en
bruto de la clave primaria del modelo ForeignKey .
Por ejemplo:
>>> Entry.objects.filter(blog_id__exact=4)
Si se le pasa un argumento o una palabra clave no vlida, la funcin levantara una excepcin del
tipo:TypeError.
La API de base de datos admite unas dos docenas de tipos de bsqueda, una completa referencia se
pueden encontrar en la field lookup reference. Para que te des una idea de las opciones disponibles,
aqu estn algunas de las bsquedas ms comunes que probablemente utilizaras:
exact
Realiza una bsqueda exacta. Por ejemplo:
>>> Entry.objects.get(headline__exact="Man bites dog")
Lo cual generara un SQL con estas lneas:
SELECT ... WHERE headline = 'Man bites dog';
Si no proporcionamos un tipo de bsqueda - es decir, si el argumento de la palabra clave no
contiene el doble guin bajo - el tipo de bsqueda se asume que es exact.
Por ejemplo, las dos sentencias siguientes son equivalentes:
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
>>> Blog.objects.get(id__exact=14) # De forma Explicita
>>> Blog.objects.get(id=14) # __exact esta implcito
Esto es conveniente, porque las bsquedas exact son las mas comunes.
iexact
Realiza bsquedas sin distinguir entre maysculas y minsculas. As, la consulta:
>>> Blog.objects.get(name__iexact="beatles blog")
La bsqueda coincidir con Beatles Blog, blog beatles, o incluso BeAtlES blOG.
contains
Realiza bsquedas distinguiendo maysculas y minsculas en cadenas. Por ejemplo:
>>>Entry.objects.get(headline__contains='Lennon')
Se podra traducir a SQL as:
SELECT ... WHERE headline LIKE '%Lennon%';
Esto coincidir con el titulo 'Today Lennon honored' pero no con 'today lennon honored'.
Tambin hay una versin que no distingue maysculas y minsculas, icontains.
startswith endswith
Realiza bsquedas que comienza con y terminan con, respectivamente. Tambin hay una versin
que no distingue maysculas y minsculas llamada istartswith y iendswith.
De nuevo, esto slo roza la superficie. Una referencia completa se puede encontrar en la field lookup
reference.
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
Django ofrece una forma potente e intuitiva para seguir las relaciones en las bsquedas, hacindose
cargo de los JOINs de SQL de manera automtica. Detrs de escena. Para cruzar una relacin, slo se
tiene que utilizar el nombre de campo de los campos relacionados a travs de modelos, separados por
dos guiones bajos, hasta llegar al campo que se desee.
En este ejemplo se recuperan todos los objetos Entry de el Blog cuyo
nombre name sea 'Beatles Blog'de esta forma:
>>>Entry.objects.filter(blog__name__exact='Beatles Blog')
Esta expansin puede ser tan profunda como lo desees.
Tambin funciona en forma inversa. Para hacer referencia a una relacin inversa, slo se tiene que
utilizar en minsculas el nombre del modelo.
En este ejemplo se recuperan todos los objetos Blog que tienen por lo menos una entrada Entry que
contiene en el headline la palabra 'Lennon':
>>>Blog.objects.filter(entry__headline__contains='Lennon')
Si vamos a filtrar a travs de mltiples relaciones y uno de los intermediarios del modelos no tienen un
valor que cumple la condicin del filtro, Django tratar esto como si hubiera un valor vaco (todos los
valores son NULL), pero vlido, el objeto all. Todo esto significa que ningn error sera lanzado. Por
ejemplo, en este filtro:
Blog.objects.filter(entry__authors__name='Lennon')
(Si haba un modelo relacionado Author ) y si no hay un author asociado con una entrada, sera tratado
como si no tuviera un name adjunto, en lugar de generar un error debido a la falta de un author. Por lo
general, esto es exactamente lo que queremos que suceda. El nico caso donde esto es confuso es
que si estamos usando isnull As:
Consultas Que Cruzan Relaciones
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
Blog.objects.filter(entry__authors__name__isnull=True)
Si queremos retornar los objetos del Blog que tienen un name de un author vaci y estos tambin
tienen un author de una entry vaci. Si no queremos estos ltimos objetos, podemos usar:
Blog.objects.filter(entry__authors__isnull=False,
entry__authors__name__isnull=True)
Cuando hayamos filtrado un objeto basado en una clase ManyToManyField o una inversa ForeignKey,
hay dos diferentes tipos de filtros que te puede interesar, considerando la
relacin Blog/Entry (Blog a Entry es una relacin uno-a-muchos). Podramos estar interesados en la
bsqueda de blogs que tengan una entrada que tenga tanto Lennon en el ttulo y que fue publicado
en 2008. O es posible que deseemos encontrar una entrada con Lennon en el ttulo, as como una
entrada que se public en 2008. Puesto que hay varias entradas asociadas a un nico Blog, muchas
de de estas consultas son posibles y tienen sentido en algunas situaciones.
El mismo tipo de situacin se presenta con una relacin ManyToManyField. Por ejemplo, si una
entradaEntry tiene un campo ManyToManyField llamado tags, si queremos encontrar entradas
relacionadas con etiquetas llamadas msic y bands o si queremos posiblemente una entrada que
contenga una etiqueta con el nombre de msica y con el estatus de pblic.
Para hacer frente a estas dos situaciones, Django tiene una forma coherente de procesar
mtodosexclude() y filter() . Todo dentro de un simple llamada al mtodo filter() la cual es
aplicada simultneamente para filtrar los elementos que coinciden con todos esos requisitos.
Sucesivamente la llamada a el mtodo filter() restringen el conjunto de los objetos, pero para las
relaciones de varios valores, se aplica a cualquier objeto relacionado con el modelo principal, no
necesariamente a aquellos objetos que fueron seleccionados por la primera llamada al
mtodo filter().
Esto puede sonar un poco confuso, as que espero que este ejemplo lo aclarar. Al seleccionar todos
los blogs que contienen entradas con ambos ttulos Lennon y que se publicaron en 2008 (la misma
Abarcando varias relaciones multi-valor
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
entrada puede satisfacer ambas condiciones), podramos escribir:
Blog.objects.filter(entry__headline__contains='Lennon',
entry__pub_date__year=2008)
Para seleccionar todos los blogs que contienen una entrada con Lennon en el ttulo y una entrada
que se public en 2008, escribiramos:
Blog.objects.filter(entry__headline__contains='Lennon').filter(
entry__pub_date__year=2008)
En este segundo ejemplo, el primer filtro restringe el queryset a todos los blogs relacionados con ese
tipo de entrada. El segundo filtro restringe el conjunto de blogs en respuesta a los que tambin se
relacionan con el segundo tipo de entrada. Las entradas seleccionadas por el segundo filtro puede o
no ser el mismo que las entradas en el primer filtro. Estamos filtrado de los objetos Blog con cada filtro
que declaramos, no los elementos Entry.
Todos estos comportamiento tambin se aplica a los exclude(): todas las condiciones de un
nicoexclude() se aplican a un instancia nica (si estas condiciones estn hablando de los mismos
valores de la relacin). Las condiciones subsecuentes filter() o exclude() las llamadas que se
refieren a la misma relacin puede terminar el filtrado en diferentes objetos vinculados.
Publicado 27th November 2012 por Saul Garcia
Etiquetas: base de datos, Django


0
Aadir un comentario
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
La gua de temas sobre Djangos database-abstraction API describe las formas en que podemos usar las
consultas en Django para crear, recuperar, actualizar y eliminar objetos individualmente. Sin embargo,
a veces se tiene la necesidad de obtener valores derivados de una suma o una agregacion de una
coleccin de objetos. Esta gua temtica describe las maneras en que los valores agregados se
pueden generar y devolver usando consultas o querys en Django.
A lo largo de esta gua, nos referiremos a los siguientes modelos. Estos modelos son utilizados para
realizar el seguimiento del inventario de una serie de libreras en lnea:
class Author(models.Model):
name = models.CharField(max_length=100)
age = models.IntegerField()
friends = models.ManyToManyField('self', blank=True)
class Publisher(models.Model):
name = models.CharField(max_length=300)
num_awards = models.IntegerField()
class Book(models.Model):
isbn = models.CharField(max_length=9)
name = models.CharField(max_length=300)
pages = models.IntegerField()
price = models.DecimalField(max_digits=10, decimal_places=2)
rating = models.FloatField()
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
pubdate = models.DateField()
class Store(models.Model):
name = models.CharField(max_length=300)
27
NOV
Agregacin
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
books = models.ManyToManyField(Book)
En una apuracion? Esta es la forma mas comn de hacer consultas de agregados, asumiendo los
modelos arriba mencionados:
# Numero total de libros.
>>> Book.objects.count()
2452
# El numero total de libros con un publisher=BaloneyPress
>>> Book.objects.filter(publisher__name='BaloneyPress').count()
73
# Precio medio de los libros.
>>> from django.db.models import Avg
>>> Book.objects.all().aggregate(Avg('price'))
{'price__avg': 34.35}
# Maximo precio de todos los libros.
>>> from django.db.models import Max
>>> Book.objects.all().aggregate(Max('price'))
{'price__max': Decimal('81.20')}
# Cada publisher, con un contador de libros con un atributo "num_books".
>>> from django.db.models import Count
>>> pubs = Publisher.objects.annotate(num_books=Count('book'))
>>> pubs
[<Publisher BaloneyPress>, <Publisher SalamiPress>, ...]
>>> pubs[0].num_books
73
# El top 5 de publishers, en orden de numero de libros.
>>> from django.db.models import Count
>>> pubs = Publisher.objects.annotate(num_books=Count('book')).order_by('-num_books')[:5]
Cheat Sheet
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
>>> pubs[0].num_books
1323
Django proporciona dos maneras de generar agregados. La primera manera es generar los valores
sumarios sobre un QuerySet entero. Por ejemplo, digamos que queremos calcular el precio medio de
todos los libros disponibles para la venta. Los querys en Django proporcionan una sintaxis para
describir el conjunto de todos los libros:
>>> Book.objects.all()
Lo que necesitamos es una manera de calcular la suma del valor de los objetos que pertenecen a
esteQuerySet. Esto lo hacemos aadiendo una clausula aggregate() a el QuerySet de esta forma:
>>> from django.db.models import Avg
>>> Book.objects.all().aggregate(Avg('price'))
{'price__avg': 34.35}
El metodo all() es redundante en este ejemplo, por lo se podra simplificar a:
>>> Book.objects.aggregate(Avg('price'))
{'price__avg': 34.35}
El argumento para la clusula aggregate() describe el valor agregado que queremos calcular - en este
caso, el promedio de los campos price en el modelo Book - . Una lista de las funciones agregadas est
disponibles en la QuerySet reference.
aggregate() es una clusula terminal para un QuerySet que, cuando se invoca, devuelve un diccionario
de pares de nombre-valor. El nombre es un identificador para el valor agregado, el valor es la suma
calculada. El nombre es generado automticamente a partir del nombre del campo y la funcin de
agregado. Si se desea especificar manualmente un nombre para el valor agregado, puede hacerce
proporcionando ese nombre cuando se especifica la clusula agregada:
Agregados que generan ms de un QuerySet
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
>>> Book.objects.aggregate(average_price=Avg('price'))
{'average_price': 34.35}
Si se desea generar ms de un agregado, solo devemos agregar otro argumento ala
clusula aggregate(). Por lo tanto, si tambin queremos saber el precio mximo y mnimo de todos los
libros, podramos emitir la consulta asi:
>>> from django.db.models import Avg, Max, Min, Count
>>> Book.objects.aggregate(Avg('price'), Max('price'), Min('price'))
{'price__avg': 34.35, 'price__max': Decimal('81.20'), 'price__min': Decimal('12.99')}
La segunda manera de generar sumas de valores es el de generar sumas independientes de cada
objeto en un QuerySet. Por ejemplo, si vamos a recuperar una lista de libros, podriamos querer saber
cuntos autores contribuyeron a cada libro. Cada libro tiene una relacin de muchos a muchos con el
autor, si queremos resumir esta relacin para cada libro del QuerySet
La suma de pre-objetos se pueden generar utilizando la clusula annotate(). Cuando una
clusulaannotate() se especifica, cada objeto del QuerySet ser anotada con los valores especificados.
La sintaxis de estas anotaciones es idntica a la utilizada por la clusula aggregate() . Cada
argumento aannotate() describe un agregado que sera calculado. Por ejemplo, para anotar los libros
por el nmero de autores podemos usar:
# construye un queryset anotado
>>> q = Book.objects.annotate(Count('authors'))
# preguntamos por el primer objeto del queryset
>>> q[0]
<Book: The Definitive Guide to Django>
>>> q[0].authors__count
2
# preguntamos por el segundo objeto del queryset
Generacin de agregados para cada elemento de un QuerySet
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
>>> q[1]
<Book: Practical Django Projects>
>>> q[1].authors__count
1
Al igual que con aggregate(), el nombre de la anotacin se deriva automticamente a partir del
nombre de la funcin de agregado y el nombre del campo que se ha agregado. Se puede sustituir este
nombre por defecto al proporcionar un alias cuando se especifique la anotacin:
>>> q = Book.objects.annotate(num_authors=Count('authors'))
>>> q[0].num_authors
2
>>> q[1].num_authors
1
Tal como aggregate(), annotate() no es una clusula terminal. La salida de la clusula annotate() es
unQuerySet; este QuerySet puede ser modificado como cualquier otro QuerySet con operaciones,
incluyendofilter(), order_by, o incluso con llamadas adicionales a annotate().
Hasta ahora, nos hemos ocupado de los agregados sobre los campos que pertenecen a los modelos
que se est consultando. Sin embargo, a veces el valor que se desea agregar pertenecer a un
modelo que tiene que ver con el modelo que se est consultando.
Al especificar el campo para ser agregados en una funcin de agregado, Django nos permitir utilizar
la mismo double underscore notation (doble guion bajo) que utiliza para referirse a los campos
relacionados en filtros. Django manejara las uniones de las tablas que son requeridas y agregara el
valor reacionado.
Por ejemplo, para encontrar el rango de precios de los libros que se ofrecen en cada tienda, se puede
utilizar la anotacin:
Juntar y Agregar
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
>>> Store.objects.annotate(min_price=Min('books__price'), max_price=Max('books__price'))
Esto le indica a Django que recupere el modelo Store, junto (a travs de la relacion muchos-a-muchos)
con el modelo book, y agregue el precio de campo del modelo de libro para producir un valor mnimo y
mximo.
Las mismas reglas se aplican a clusula aggregate(). Si quisieramos saber el precio ms bajo y ms
alto de todos los libros que estn disponibles para la venta en la tienda(Store), podramos utilizar
elaggregate() siguiente:
>>> Store.objects.aggregate(min_price=Min('books__price'), max_price=Max('books__price'))
Juntar cadenas pueden ser tan profundo como sea necesario. Por ejemplo, para extraer la edad de la
autora ms joven de todos los libros disponibles para la venta, se podra emitir la consulta:
>>> Store.objects.aggregate(youngest_age=Min('books__authors__age'))
Los agregados tambin pueden participar en filtros. Cualquier filter() (o exclude()) aplicado a los
campos normales del modelo tendr el efecto de restringir los objetos que se consideran para la
agregacin.
Cuando se utilizan con un clusula annotate(), un filtro tiene el efecto de restringir los objetos para
los que se calcula una anotacin. Por ejemplo, se puede generar una lista anotada de todos los libros
que tienen un ttulo que empieza con Django utilizando la consulta:
>>> Book.objects.filter(name__startswith="Django").annotate(num_authors=Count('authors'))
Cuando se utiliza con una clusula aggregate(), un filtro tiene un efecto limitador de objetos sobre los
cuales se calcula el agregado. Por ejemplo, se puede generar el precio medio de todos los libros con
Agregaciones y otras clusulas de un QuerySet
filter() y exclude()
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
un ttulo que comience con Django utilizando la consulta:
>>> Book.objects.filter(name__startswith="Django").aggregate(Avg('price'))
Los valores anotados tambin se puede filtrar. Los alias de la anotacin puede ser utilizados en
clausulasfilter() y exclude() de la misma manera que cualquier otro modelo de campo.
Por ejemplo, para generar una lista de libros que tienen ms de un autor, podemos ejecutar la
siguiente consulta:
>>> Book.objects.annotate(num_authors=Count('authors')).filter(num_authors__gt=1)
Esta consulta genera un conjunto de resultados anotados, a continuacin, genera un filtro basado en
que la anotacin.
Cuando se desarrolla una consulta compleja que involucra tanto una clusula annotate() si como
unafilter(), se debe prestar especial atencin al orden en el que se aplican las clusulas
del QuerySet.
Cuando un clusula annotate() es aplicada a una consulta, la anotacin es calculada sobre el estado
de la consulta hasta el punto en que la anotacin se solicita. La implicacin prctica de esto es
que filter() yannotate() no son operaciones conmutativas - es decir, hay una diferencia entre la
consulta -:
>>> Publisher.objects.annotate(num_books=Count('book')).filter(book__rating__gt=3.0)
y la consulta:
>>> Publisher.objects.filter(book__rating__gt=3.0).annotate(num_books=Count('book'))
Filtros o anotaciones
Ordenar clausulas annotate() y filter()
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
Ambas consultas devolver una lista de editores que tienen por lo menos un buen libro (es decir, un
libro con una calificacin superior a 3.0). Sin embargo, la anotacin en la primera consulta
proporcionar el nmero total de todos los libros publicados por la editorial, la segunda consulta
incluir solamente los buenos libros en el contador de la anotacin. En la primera consulta, la
anotacin precede al filtro, por lo que el filtro no tiene efecto en la anotacin. En la segunda consulta,
el filtro precede a la anotacin, y como resultado, el filtro restringe los objetos considerados cuando se
hace la anotacin.
Las anotaciones se pueden utilizar basicamenente para ordenar. Cuando se define una
clausulaorder_by (), los agregados suministrados pueden hacer referencia a cualquier alias definido
como parte de una clusula annotate() en la consulta.
Por ejemplo, para ordenar un QuerySet de libros por el nmero de autores que han colaborado en el
libro, se puede utilizar la siguiente consulta:
>>> Book.objects.annotate(num_authors=Count('authors')).order_by('num_authors')
Por lo general, las anotaciones se generan en funcin de cada objeto - una
anotacion QuerySet devolver un resultado para cada objeto en el original QuerySet -. Sin embargo,
cuando una clusula values() es utilizada para restringir las columnas que se devuelven en el
conjunto de resultados, el mtodo de evaluacin de anotaciones es ligeramente diferente. En lugar de
devolver un resultado anotado para cada resultado en el QuerySet, los resultados originales son
agrupados de acuerdo con las combinaciones particulares de los campos especificados en la
clusula values(). Una anotacin se proporciona entonces para cada grupo nico; la anotacin se
calcula sobre todos los miembros del grupo.
Por ejemplo, consideremos una consulta de un autor que intenta averiguar el promedio de valoracin
de los libros escritos por cada autor:
order_by()
values()
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
>>> Author.objects.annotate(average_rating=Avg('book__rating'))
Esto devolver un resultado por cada autor en la base de datos, con la anotacin, y su clasificacin
promedio contable.
Sin embargo, el resultado ser un poco diferente si se utiliza un clusula values():
>>> Author.objects.values('name').annotate(average_rating=Avg('book__rating'))
En este ejemplo, los autores se agruparn por su nombre, por lo que se obtendr slo un resultado
anotado para cada un Nombre nico autor. Esto significa que tenemos Dos autores con el mismo
nombre, los resultados se fusionarn en una sola salida de consulta; el promedio se calcula como el
promedio de los libros escritos por ambos autores.
Al igual que con la clusula filter(), el orden en el cual las clausulas``annotate()`` y values() se
aplican a una consulta es significativo. Si la clusula values() precede ala clausula annotate(), la
anotacin ser calculada utilizando la agrupacin descrita por la clusula values().
Sin embargo, si la clusula annotate() precede a la clusula values(), las anotaciones se genera
sobre el conjunto completo de la consulta. En este caso, la clusula values() slo limita los campos
que se generan en la salida.
Por ejemplo, si invertimos el orden de los valores de las clausulas values() y annotate() de nuestro
ejemplo anterior:
>>> Author.objects.annotate(average_rating=Avg('book__rating')).values('name', 'average_rat
ing')
Esto ahora producira un resultado nico para cada autor, sin embargo, slo el nombre del autor y la
anotacin average_rating ser devuelto en los datos de salida.
El order de clusulas annotate() y values()
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
Tambin debemos tener en cuenta que average_rating se ha incluido explcitamente en la lista de
valores que se devuelven. Esto es necesario debido a la orden de los valores de las
clusulas values() yannotate().
Si la clusula values() precede ala clusula annotate(), las anotaciones se aaden automticamente
a la hoja de resultados. Sin embargo, si la clusula values() se aplica despus de la
clusula annotate(), se debe explcitamente incluir la columna agregada.
Los campos que se mencionan en el metodo order_by() por parte de un queryset (o que se utilizan en
el orden predeterminado de un modelo) se usan cuando se selecciona los datos de salida, incluso si
no se especifique otra cosa en la llamada a values(). Estos campos adicionales se utilizan para
agrupar y juntar resultados similares entre s y que pueden tener otros resultados en filas idnticas,
pero de un modo separado. Esto se manifiesta, en particular, al contar cosas.
A modo de ejemplo, supongamos que se tiene un modelo como este:
class Item(models.Model):
name = models.CharField(max_length=10)
data = models.IntegerField()
class Meta:
ordering = ["name"]
La parte importante aqu es el orden predeterminado en el campo name. Si deseamos contar cuntas
veces cada valor data distinto aparece, es posible que intentemos esto:
# Advertencia: No del todo correcto!
Item.objects.values("data").annotate(Count("id"))
... Que agrupar los objetos Item por su valor comn data y luego contara el nmero de valores id en
cada grupo. Slo que no terminara de funcionar. El valor por defecto name tambin jugar un papel
importante en la agrupacin, por lo que si queremos una consulta de grupos de pares de
Interaccin con un orden predeterminado o order_by()
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
distintos(data, name) , que no es lo que queremos. En su lugar, devemos construir este queryset:
Item.objects.values("data").annotate(Count("id")).order_by()
...limpiamos y ordenamos la consulta. Tambin podriamos ordenar, por decir, date sin ningn efecto
perjudicial, puesto que ya est jugando un papel en la consulta.
Este comportamiento es el mismo que se indica en la documentacin para el distinct() y la regla
general es la misma: normalmente no querremos columnas extra que juegan un papel importante en
el resultado, por lo que limpiar el orden, o al menos asegurarse de que se est restringiendo al menos
esos campos que tambien son seleccionados en la llamada a values().
Note
Es razonable preguntar por qu Django no elimina las columnas extraas por nosotros.
La razn principal es por mantener la coherencia con distinc () y otros lugares:
Django nuncaeliminara el orden de retriccion que hayamos especificado (y no podemos
cambiar el comportamiento de los otros mtodos, ya que esto violara
nuestro: /misc/api-stabilitypolicy).
Tambin se puede generar un agregado en el resultado de una anotacin. Cuando definimos una
clausulaaggregate(), los agregados suministrados pueden hacer referencia a cualquier alias definido
como parte de una clusula annotate() de la consulta.
Por ejemplo, si desea calcular el nmero promedio de autores por el conjunto de libros con el recuento
autor, entonces el agregado que cuenta el autor, haciendo referencia al campo de anotaciones:
>>> Book.objects.annotate(num_authors=Count('authors')).aggregate(Avg('num_authors'))
{'num_authors__avg': 1.66}
Publicado 27th November 2012 por Saul Garcia
Agregacin de anotaciones
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
Etiquetas: Django


0
Aadir un comentario
Definir mtodos personalizados en un modelo para agregar funcionalidad a nivel de fila a los
objetos. Considerando que el mtodo Manager est destinados a trabajar del lado de las tablas en
toda las cosas, los mtodos de un modelo debe actuar en un caso de modelo en particular.
Esta es una tcnica valiosa para mantener la lgica de negocio en un solo lugar - el modelo -.
Por ejemplo, este modelo tiene un par de mtodos personalizados:
class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
birth_date = models.DateField()
address = models.CharField(max_length=100)
city = models.CharField(max_length=50)
state = USStateField() # Yes, this is America-centric...
def baby_boomer_status(self):
"Returns the person's baby-boomer status."
import datetime
27
NOV
Mtodos de los modelos
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
import datetime
if datetime.date(1945, 8, 1) <= self.birth_date <= datetime.date(1964, 12, 31):
return "Baby boomer"
if self.birth_date < datetime.date(1945, 8, 1):
return "Pre-boomer"
return "Post-boomer"
def is_midwestern(self):
"Returns True if this person is from the Midwest."
return self.state in ('IL', 'WI', 'MI', 'IN', 'OH', 'IA', 'MO')
def _get_full_name(self):
"Returns the person's full name."
return '%s %s' % (self.first_name, self.last_name)
full_name = property(_get_full_name)
El ltimo mtodo en este ejemplo es una property.
La referencia model instance reference contiene una lista completa de methods automatically given to
each model. que puede ser sobrescritos la mayor parte de ellos puedes ver sobrescribiendo mtodos de
un modelo mas adelante, pero hay un par de cosas que siempre querremos definir.
__unicode__()
Un mtodo mgico que devuelve una representacin unicode de cualquier objeto. Esto es lo que
Python y Django usarn cada vez que una instancia de un modelo necesita ser coaccionada y se
muestra como una simple cadena. En particular, esto ocurre cuando se muestra un objeto en una
consola interactiva o en la interfaz de administracin.
Siempre debemos definir este mtodo, el valor predeterminado no es muy til ni amigable.
get_absolute_url()
Esto le indica a Django cmo calcular la URL de un objeto. Django usa esto en su interfaz de
administracin y en cualquier tiempo que necesita para encontrar una direccin URL de un objeto.
Cualquier objeto que tenga una URL que identifica de forma exclusiva debe definir este mtodo.
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
Hay otro conjunto de mtodos de un modelo que encapsulan un montn de comportamientos de la
base de datos que tal vez quieras personalizar. En particular, a menudo se desea cambiar la forma en
que elsave() y delete() trabajan.
Eres libre para reemplazar estos mtodos (y cualquier otro mtodo de algn modelo) para alterar su
comportamiento.
Un clsico uso de estos casos puede ser para reemplazar algunos mtodos integrados, es decir que si
quieres que algo suceda cada vez que guardas un objeto. Por ejemplo (save() para documentarte
sobre los parmetros que acepta) Puedes usar:
class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField()
def save(self, *args, **kwargs):
do_something()
super(Blog, self).save(*args, **kwargs) # Call the "real" save() method.
do_something_else()
O puedes prevenir que algo se guarde:
class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField()
def save(self, *args, **kwargs):
if self.name == "Yoko Ono's blog":
return # Yoko shall never have her own blog!
else:
super(Blog, self).save(*args, **kwargs) # Call the "real" save() method.
Sobreescribiendo mtodos predefinidos de un modelo
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
Es importante recordar que devemos llamar al mtodo de la
superclasesuper(Blog, self).save(*args, **kwargs) - para asegurarse de que el objeto se guardo
en la base de datos. Si se te olvida llamar al mtodo de la superclase, el comportamiento
predeterminado no va a suceder y la base de datos no se tocara.
Tambin es importante que se pasen los argumentos a travs de los mtodos del modelo - que es lo
que los *args, **kwargs hacen, Django de vez en cuando, amplia las capacidades de los mtodos de
los modelos incorporados, agregando nuevos argumentos. Si utilizamos *args, **kwargs en las
definiciones de los mtodo, garantizamos que el cdigo pueda automticamente dar soporte a los
argumentos cuando estos sean agregados.
Los mtodos reemplazados en un modelo no se llaman en operaciones masivas.
Tenga en cuenta que el mtodo delete() de un objeto no se llama necesariamente al
eliminar objetos de forma masiva utilizando un QuerySet. Para asegurarse de borrar de
una forma lgica y personalizada ejecutamos las seales pre_delete y/o post_delete.
Desafortunadamente, no hay una solucin al usar creating o updating en los objetos
cuando se llaman de forma masiva, ya que ninguno de los
metodos save(), pre_save ypost_save emite seales hasta que son llamados.
Otro patrn comn es escribir sentencias SQL personalizadas en los mtodos del modelo y los
mtodos a nivel de mdulo. Para obtener ms informacin sobre el uso crudo de SQL, consulte la
documentacinusing raw SQL.
La herencia de modelos en Django funciona de forma idntica a la herencia de clases normales en
Python. La nica decisin que se tiene que tomar es si se desea que los modelos padres tengan sus
modelos propios (con sus propias tablas de la base de datos), o si los modelos padres puedan
Ejecutando SQL personalizado
Herencia de Modelos
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
contener informacin comn que slo ser visible a travs de los modelos hijos.
Hay tres estilos de herencia posibles en Django.
1. A menudo, usted slo tendr que usar la clase padre para contener la informacin que no quiere
escribir para cada modelo hijo. Esta clase no se va a utilizar nunca de forma aislada, por lo que
lasabstract-base-classes son las que usted est buscando.
2. Si es una subclase de un modelo existente (tal vez algo de otra aplicacin completamente) y
desea que cada modelo tenga su tabla de base de datos propia, multi-herencia multi-table-
inheritance es el camino a seguir.
3. Por ltimo, si slo se desea modificar el comportamiento Python a nivel de un modelo, sin
necesidad de ninguna manera cambiar los modelos de los campos, puede utilizar los Modelos proxy.
Las clases base abstractas son tiles cuando se quiere poner alguna informacin comn en otros
modelos. Se puede escribir la clase base con el argumento abstract=True en la clase Meta. Este
modelo no podr entonces ser usado para crear cualquier tabla de base de datos. En cambio, cuando
se utiliza como una clase base para otros modelos, sus campos se aaden a los de la clase hija. Es un
error tener campos de la clase base abstracta con el mismo nombre que los del hijo (y Django lanzar
una excepcin).
Un ejemplo:
class InfoComun(models.Model):
nombre = models.CharField(max_length=100)
edad = models.PositiveIntegerField()
class Meta:
abstract = True
class Estudiante(InfoComun):
grupo = models.CharField(max_length=5)
Las clases base abstractas
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
El modelo Estudiante tendr tres campos : nombre, edad y grupo. El modelo InfoComun no puede ser
utilizado como un modelo normal de Django, ya que es una clase base abstracta. No genera una tabla
de base de datos o un manager y no puede ser instanciado o guardar directamente.
Para muchos usos, este tipo de herencia de modelos ser exactamente lo que quieres. Proporciona
una manera de factorizar informacin comn a nivel Python, aunque slo sea la creacin de una tabla
de base de datos para un modelo hijo a nivel de base de datos.
Cuando una clase base abstracta se crea, hace que cualquier clase interna Meta que se declar en la
clase base este disponible como un atributo. Si una clase hija no se declara con su propia clase Meta,
heredar de la clase padre las opciones Meta. Si el modelo hijo quiere extender la clase Meta padre,
necesita una subclase.
Por ejemplo:
class InfoComun(models.Model):
...
class Meta:
abstract = True
ordering = ['nombre']
class Estudiante(InfoComun):
...
class Meta(InfoComun.Meta):
db_table = 'estudiantes_info'
Django hace que un ajuste en una clase Meta en una clase abstracta base Meta antes de instalar los
atributos Meta, este sea abstract=False . Esto significa que las clases hijos de las clases base
abstractas no se convierten automticamente en clases abstractas en s mismos. Por supuesto, usted
puede hacer que una clase base abstracta que herede de otra clase base abstracta. Slo tiene que
recordar establecer explcitamente abstract=True en cada ocasin.
Herencia Meta
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
Algunos atributos no tiene sentido incluir en la clase Meta de una clase base abstracta. Por ejemplo,
incluirdb_table significara que todas las clases secundarias (las que no especifiquen su propia Meta )
utilizaran la misma tabla de la base de datos, lo cual es casi seguro que no es lo que quieres.
Si ests utilizando un atributo related_name en un ForeignKey o en ManyToManyField, siempre debes
especificar un nombre nico para el nombre del campo contrario. Normalmente, esto causa un
problema en las clases base abstractas, ya que los campos de esta clase se incluyen en cada una de
las clases secundarias, con exactamente los mismos valores para los atributos
(incluyendo related_name ) cada vez.
Changed in Django 1.2: Please see the release notes
Para evitar este problema, cuando se utiliza related_name en una clase base abstracta (nicamente),
es que parte del nombre debe contener '%(app_label)s' y '%(class)s'.
'%(class)s' es remplazado por el nombre en minsculas de la clase hijo que el campo esta
utilizando.
'%(app_label)s' es remplazado por el nombre en minsculas de la aplicacin en que est
contenida la clase hija. El nombre de cada aplicacin instalada debe ser nico y los nombres de
las clases del modelo dentro de cada aplicacin tambin debe ser nicas, por lo que el nombre
resultante va a terminar siendo diferente.
Por ejemplo, dada una aplicacin common/models.py:
class Base(models.Model):
m2m = models.ManyToManyField(OtherModel, related_name="%(app_label)s_%(class)s_related"
)
class Meta:
abstract = True
class ChildA(Base):
Ten cuidado con related_name
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
pass
class ChildB(Base):
pass
Junto con otra aplicacin rare/models.py:
from common.models import Base
class ChildB(Base):
pass
El nombre inverso del campo common.ChildA.m2m sera common_childa_related mientras que el nombre
inverso del nombre del campo common.ChildB.m2m sera common_childb_related y finalmente el nombre
inverso de el campo rare.ChildB.m2m sera rare_childb_related. Depende de cmo se utilize
el'%(class)s' y '%(app_label)s en parte para construir su nombre relacionado, pero si usted se olvida
de usarlo, Django generara errores al validar sus modelos (o al ejecutar syncdb).
Si no se especifica un atributo related_name para un campo de una clase base abstracta, la inversa de
nombres por defecto ser el nombre de la clase hija seguido de '_set', tal y como normalmente sera
si se hubiera declarado el campo directamente en la clase hija. Por ejemplo, en el cdigo anterior, si el
atributorelated_name el atributo se omite, el nombre inverso para el campo m2m sera para
el childa_setchildb_set y en el caso de ChildA el childb_set sera ChildB para el campo.
El segundo tipo de modelo de herencia soportado por Django es cuando cada modelo de la jerarqua
es un modelo de s mismo. Cada modelo corresponde con sus propias tablas de base de datos y se
puede consultar y crear individualmente. La relacin de herencia presenta vnculos entre el modelo
hijo y cada uno de sus padres (a travs de una creada automticamente OneToOneField)
Por ejemplo:
Herencias Multi-tabla
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
class Restaurant(Place):
serves_hot_dogs = models.BooleanField()
serves_pizza = models.BooleanField()
Todos los campos del objeto Place tambin estarn disponibles en el objeto Restaurant, a pesar de
que los datos residen en una tabla de base de datos diferente. As que estas relaciones son posibles:
>>> Place.objects.filter(name="Bob's Cafe")
>>> Restaurant.objects.filter(name="Bob's Cafe")
Si tenemos un objeto Place que sea tambin un
objetoRestaurant ``, podemos traer los los objetos desde el ``Place a los objetos ``Restaurant
`` utilizando la versin en minsculas del nombre del modelo:
>>> p = Place.objects.get(id=12)
# Si p es un objeto Restaurant, podemos traer las clase hijas:
>>> p.restaurant
<Restaurant: ...>
Sin embargo, si p en el ejemplo anterior no era un
objetoRestaurant `` (que haba sido creado directamente como un objeto ``Place o era el padre
de alguna otra clase), refirindose a p.restaurant lanzara una excepcin Restaurant.DoesNotExist
En situaciones de herencia multi-tabla, no tiene sentido que una clase hija herede de su padre una
clase Meta. Todas los opciones Meta ya han sido aplicados a la clase padre y aplicarlas de nuevo
normalmente slo conducen a un comportamiento contradictorio (lo que contrasta con el caso de la
clase base abstracta, donde la clase base no existe por derecho propio).
As, un modelo hijo no tiene acceso a las clases Meta de su su padre. Sin embargo, hay unos pocos
Herencia Multitabla y Meta
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
As, un modelo hijo no tiene acceso a las clases Meta de su su padre. Sin embargo, hay unos pocos
casos limitados en que el hijo hereda el comportamiento de los padres: si el hijo no especifica
un ordering o un atributo get_latest_by , heredar estos de su padre.
Si el modelo padre tiene un orden y no queremos usarlo en el modelo, se puede inhabilitar
explcitamente as:
class ChildModel(ParentModel):
...
class Meta:
# Remove parent's ordering effect
ordering = []
Debido a la herencia multi-tabla que utiliza un campo implcito OneToOneField para vincular el hijo y el
padre, es posible moverse del padre al hijo hacia abajo, como en el ejemplo anterior. Sin embargo, se
usa el nombre que es el valor predeterminado para related_name para las
relaciones ForeignKey yManyToManyField. Si se va a colocar ese tipo de relaciones en una subclase de
otro modelo, se debeespecificar el atributo related_name en cada campo como tal. Si se olvida
colocarlo, Django generar un error al ejecutar validate o syncdb.
Por ejemplo, utilizando la clase anterior Place otra vez, vamos a crear otra subclase con un
campoManyToManyField:
class Supplier(Place):
# Se debe especificar el nombre de la relacin en todas las relaciones.
castores = models.ManyToManyField(Restaurant, related_name='provider')
Como se ha mencionado anteriormente, Django crea automticamente una
vinculacin OneToOneField a la clase hija de cualquier de los modelos padres no abstractos. Si se
desea controlar el nombre del atributo que une de nuevo al padre, se puede crear un campo
propio OneToOneField y colocar parent_link=Truepara indicar que el campo es el enlace a la clase
Herencia y relaciones inversas
Especificar el campo de enlace padre
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
padre.
Cuando se utiliza multi-table inheritance , una nueva tabla de base de datos se crea, por cada
subclase de un modelo. Este suele ser el comportamiento deseado, ya que la subclases necesitan un
lugar para almacenar los campos de datos adicionales que no estn presentes en la clase base. A
veces, sin embargo, slo se quiere cambiar el comportamiento de un modelo Python - tal vez para
cambiar el manager por defecto o aadir un nuevo mtodo.
Esto es lo que la herencia de modelo proxy hace: crea un proxy para que el modelo original. Puede
crear, borrar y actualizar las instancias del modelo de proxy y todos los datos se guardarn como si se
estuviera usando el modelo original (no-proxy). La diferencia es que se pueden cambiar cosas como el
ordenamiento del modelo predeterminado o el gestor por defecto en el proxy, sin tener que alterar el
original.
Los modelos proxy se declaran como los modelos normales. Le decimos a Django que es un modelo
proxy mediante el establecimiento del atributo Meta de la clase a True.
Por ejemplo, supongamos que queremos agregar un mtodo a un User estndar en un modelo usado
en las plantillas. Podemos hacerlo as:
from django.contrib.auth.models import User
class MyUser(User):
class Meta:
proxy = True
def do_something(self):
La clase MyUser funciona de igual manera en la misma tabla de base de datos que su padre la
clase User. Particularmente, cualquier nueva instancia de User ser accesible con MyUser, y viceversa:
Modelos proxy
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
>>> u = User.objects.create(username="foobar")
>>> MyUser.objects.get(username="foobar")
<MyUser: foobar>
Tambin es posible usar un modelo proxy para definir un valor de ordenamiento predeterminado
diferente de un modelo. La clase normal del modelo User no tiene definido en el mismo
(intencionalmente; la clasificacin es costosa y no queremos hacerlo todo el tiempo cuando traemos
usuarios). Es posible que deseemos ordenar regularmente por el nombre del atributo
del username cuando se utiliza el proxy. Esto es fcil:
class OrderedUser(User):
class Meta:
ordering = ["username"]
proxy = True
Ahora una consulta a User puede ser desordenada y OrderedUser y los querys sern ordenados
porusername.
No hay una manera de retornar en Django, por decir, un objeto MyUser cada vez que se consulta el
query de un objeto User. Un queryset para los objetos User devolver este tipo de objetos. El punto
central de objetos proxy es que el cdigo se basa en el cdigo original del objeto User y puede utilizar
las extensiones que se incluyen en el (que no se incluyen en cualquier otro caso). Esta no es una
forma de reemplazar a un objeto User (o cualquier otra parte) del modelo con algo de su propia
creacin.
Un modelo de representacin deber heredar exactamente una clase modelo no abstracta. No puede
heredar de mltiples modelos no abstractos como el modelo proxy, no proporciona ninguna conexin
entre las filas de las tablas de bases de datos diferentes. Un modelo proxy se puede heredar de
cualquier nmero de clases del modelo abstracto, siempre que se no define ninguno de sus campos
del modelo.
QuerySets que devuelven el modelo que fue pedido
Restricciones en una clase base
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
Los modelos proxy heredan cualquier opcin Meta que no se defina en su modelo padre no-abstracto
(el modelo proxy).
Si no se especifica un manager en un modelo proxy, este hereda los managers de los modelos padre. Si
se define un manager en el modelo proxy, se convertir en el valor predeterminado, a pesar de que se
haya definido en la clase padre seguirn estando disponibles.
Continuando con nuestro ejemplo anterior, se puede cambiar el manager predeterminado que se utiliza
cuando se consulta el modelo User de la siguiente manera:
class NewManager(models.Manager):
...
class MyUser(User):
objects = NewManager()
class Meta:
proxy = True
Si se desea agregar un nuevo manager para el Proxy, sin tener que reemplazar el valor
predeterminado existente, pueden utilizarse las tcnicas descritas en la custom manager y crear una
clase base que contiene los nuevos managers y los que hereda de la clase base primaria:
# Creamos una clase abstracta para el nuevo manager.
class ExtraManagers(models.Model):
secondary = NewManager()
class Meta:
abstract = True
class MyUser(User, ExtraManagers):
class Meta:
Managers en modelos proxy
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
proxy = True
Sin embargo no necesitaremos probablemente hacer esto muy a menudo, pero cuando esto se
necesite, es posible.
La herencia de un modelo proxy puede tener un aspecto bastante similar a la creacin de un modelo
no manejado, usando managed y los atributos de una clase Meta de un modelo . Las dos alternativas
no son exactamente lo mismo y vale la pena considerar cul se debe usar.
Una diferencia es que se puede (y de hecho se debe a menos que queramos tener un modelo vaco)
especificar los campos del modelo en los modelos con Meta.managed=False. Con esto podemos, ajustar
cuidadosamente el atributo Meta.db_table al crear un modelo unmanaged que sombre un modelo
existente y agregar los mtodos python en l. Sin embargo, eso sera muy repetitivo y frgil para
mantener ambas copias sincronizadas si realizamos cualquier cambio en ellas.
La otra diferencia ms importante para los modelos proxy, es cmo los managers de un modelo se
manejan. Los modelos de proxy se comportan exactamente igual que los modelos no manejado. As
que heredan los managers de el modelo de los padres, incluyendo el gestor por defecto. En lo normal
de los casos en la herencia multi-tabla, los hijos no heredan los managers de sus padres,
los managerspersonalizados no son siempre apropiados cuando los campos adicionales estn
involucrados. La documentacin de manager documentation tiene ms informacin acerca de este ltimo
caso.
Cuando estas dos funciones fueron implementadas, se hicieron intentos para acoplarlos en una sola
opcin. Result que las interacciones con la herencia, en general, y los managers, en particularmente
hicieron la API muy complicada y potencialmente difcil de entender y utilizar. Result que se necesitan
dos opciones en cualquier caso, por lo que surgi la actual separacin.
Por lo tanto, las reglas generales son:
1. Si va a reflejar un modelo existente o una tabla de base de datos y no se desea que todas las
Las diferencias entre la herencia proxy y los modelos no manejados
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
columnas originales de la tabla de base de datos, utilice Meta.managed=False. Esta opcin suele
ser til para modelar vistas de bases de datos y tablas que no estn bajo el control de Django.
2. Si ests interesado en cambiar el comportamiento de un modelo python, pero quieres mantener
todos los mismos campos que en el original, deves utilizar Meta.proxy=True. Esto pone las cosas
de modo que el modelo proxy sea una copia exacta de la estructura de almacenamiento del
modelo original cuando se guardan los datos.
Al igual que con la subclasificacin de Python, es posible que un modelo Django herede de sus
mltiples modelos padre. Tenga en cuenta que las reglas normales de Python en la resolucin de
nombres se aplican. La primera clase base que aparece en un nombre en particular (por ejemplo Meta)
ser el que se utiliza, por ejemplo, esto significa que si los padres contienen mltiples clases Meta,
slo el primero se va a utilizar y todos los dems sern ignorados.
En general, usted no tendr que heredan de mltiples padrea. El uso principal de los casos donde
esto es til es en las clases mix-in la adicin de un campo en particular o un mtodo adicional para
cada clase que herede el mix-in. Trate de mantener las jerarquas de herencia tan sencillas y directas
como sea posible para que usted no tenga que calcular dnde se encuentra y de donde proviene una
determinada pieza de informacin.
En la herencia normal de clases Python, est permitido que una clase hija pueda anular cualquier
atributo de la clase padre. En Django, esto no est permitido para las instancias de los los
atributos Field (al menos, no por el momento). Si una clase base tiene un campo llamado author no
se puede crear otro modelo con un campo author de cualquier clase que hereda de la clase base.
Sobrescribir los campos de un modelo padre conduce a dificultades en reas como la inicializacin de
nuevas instancias (especificando qu campo se esta inicializando con Model.__init__ ) y la
serializacin. Estas son las caractersticas que la herencia normal de clase Python no tiene que tratar
Herencia mltiple
Nombres de campos hiding no estn permitidos
pdfcrowd.com open in browser PRO version Are you a developer? Try out the HTML to PDF API
en la misma manera, por lo que la diferencia entre la herencia de un modelo de Django y las herencias
de clases de Python no es arbitraria.
Esta restriccin slo se aplica a los atributos que estn sobre la instancia Field, Los atributos
normales python se pueden modificar si se desea. Adems, slo se aplica al nombre del atributo como
Python lo ve: si va a especificar manualmente el nombre de la columna de base de datos, usted puede
tener el mismo nombre de columna que aparece tanto en el hijo y el modelo ancestro de la herencia
multi-tabla (que son las columnas en dos tablas de bases de datos diferentes).
Django levantar una exepcion FieldError si se invalida cualquier campo de un modelo en cualquier
modelo ancestro.
Publicado 27th November 2012 por Saul Garcia
Etiquetas: base de datos, Django


0
Aadir un comentario

You might also like