<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Cibernatural &#187; Django</title>
	<atom:link href="http://www.cibernatural.com/tag/django/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.cibernatural.com</link>
	<description>Diseño y desarrollo web en Lanzarote</description>
	<lastBuildDate>Thu, 19 Jan 2012 14:19:30 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.4</generator>
<atom:link rel="hub" href="http://pubsubhubbub.appspot.com"/><atom:link rel="hub" href="http://superfeedr.com/hubbub"/>		<item>
		<title>Gestión web de Tienda de Bicicletas</title>
		<link>http://www.cibernatural.com/gestion-web-de-tienda-de-bicicletas/</link>
		<comments>http://www.cibernatural.com/gestion-web-de-tienda-de-bicicletas/#comments</comments>
		<pubDate>Mon, 14 Mar 2011 16:35:37 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Portales y Aplicaciones web complejas]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[Intranet]]></category>
		<category><![CDATA[Lanzarote]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[ReportLab]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://www.cibernatural.com/?p=829</guid>
		<description><![CDATA[Cibernatural ha estrenado una nueva aplicación web en Django de gestión de las tiendas de alquiler y venta de bicicletas en Lanzarote Papagayo Bike. La página web privada permite gestionar todas y cada una de las entidades relacionadas con la empresa. En concreto: Gestión de Bicicletas y Productos (Repuestos, Accesorios, Nutricionales, etc.) Gestión de alquileres [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.cibernatural">Cibernatural</a> ha estrenado una nueva aplicación <strong>web</strong> en <a href="http://www.cibernatural.com/tag/django">Django</a> de gestión de las tiendas de alquiler y venta de bicicletas en <strong>Lanzarote</strong> <a href="http://www.papagayobike.com">Papagayo Bike</a>.</p>
<p>La <strong>página web</strong> privada permite gestionar todas y cada una de las entidades relacionadas con la empresa.<br />
<span id="more-829"></span><br />
<a href="http://www.cibernatural.com/wp-content/uploads/2011/03/gestion-web-papagayo-bike1.jpg"><img src="http://www.cibernatural.com/wp-content/uploads/2011/03/gestion-web-papagayo-bike1.jpg" alt="" title="gestion-web-papagayo-bike1" width="400" height="300" class="aligncenter size-full wp-image-832" /></a></p>
<p>En concreto:</p>
<ul>
<li>Gestión de Bicicletas y Productos (Repuestos, Accesorios, Nutricionales, etc.)</li>
<li>Gestión de alquileres y generación de contratos de alquiler<br />
<a href="http://www.cibernatural.com/wp-content/uploads/2011/03/gestion-web-papagayo-bike3.jpg"><img src="http://www.cibernatural.com/wp-content/uploads/2011/03/gestion-web-papagayo-bike3.jpg" alt="" title="gestion-web-papagayo-bike3" width="400" height="300" class="aligncenter size-full wp-image-834" /></a>
</li>
<li>Gestión de alquileres de grupos para Hoteles, etc.</li>
<li>Gestión de Reparaciones</li>
<li>Gestión de Compras y Ventas<br />
<a href="http://www.cibernatural.com/wp-content/uploads/2011/03/gestion-web-papagayo-bike4.jpg"><img src="http://www.cibernatural.com/wp-content/uploads/2011/03/gestion-web-papagayo-bike4.jpg" alt="" title="gestion-web-papagayo-bike4" width="400" height="300" class="aligncenter size-full wp-image-835" /></a>
</li>
<li>Gestión de Clientes, Presupuestos y Facturas<br />
<a href="http://www.cibernatural.com/wp-content/uploads/2011/03/gestion-web-papagayo-bike2.jpg"><img src="http://www.cibernatural.com/wp-content/uploads/2011/03/gestion-web-papagayo-bike2.jpg" alt="" title="gestion-web-papagayo-bike2" width="400" height="300" class="aligncenter size-full wp-image-833" /></a>
</li>
<li>Auditoría</li>
</ul>
<p>El proyecto se enmarca dentro del <a href="http://www.cibernatural.com/proveedor-de-bonos-tecnologicos-del-gobierno-de-canarias">Programa de Subvenciones de Bonos Tecnológicos del Gobierno de Canarias</a>.</p>
<p>La aplicación web mantiene los datos de la empresa en &#8220;la nube&#8221;, lo que permite al usuario acceder a ellos en cualquier momento y en cualquier lugar, y a través de diferentes perfiles de acceso.</p>
<h3>Enlaces Relacionados</h3>
<ul>
<li><a href="http://www.cibernatural.com/pagina-web-de-papagayo-bike-lanzarote/">Página web de Papagayo Bike Lanzarote</a></li>
<li><a href="http://www.cibernatural.com/aplicacion-web-de-gestion-de-excursiones-de-cruceros-para-shore2shore/">Aplicación web de Gestión de Excursiones de Cruceros para Shore2Shore</a></li>
<li><a href="http://www.cibernatural.com/demo-online-del-programa-de-gestion-web-en-django/">Demo online del Programa de Gestión Web en Django</a></li>
<li><a href="http://www.cibernatural.com/aplicacion-web-de-reserva-de-canchas-de-padel/">Aplicación web de Reserva de Canchas de Padel</a></li>
</ul>

                            <div id="aspdf">
                                <a href="http://www.cibernatural.com/wp-content/plugins/as-pdf/generate.php?post=829">
                                    <span>Descargar en PDF</span>
                                </a>
                            </div>
                        ]]></content:encoded>
			<wfw:commentRss>http://www.cibernatural.com/gestion-web-de-tienda-de-bicicletas/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Demo online del Programa de Gestión Web en Django</title>
		<link>http://www.cibernatural.com/demo-online-del-programa-de-gestion-web-en-django/</link>
		<comments>http://www.cibernatural.com/demo-online-del-programa-de-gestion-web-en-django/#comments</comments>
		<pubDate>Fri, 11 Feb 2011 09:09:55 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Destacado]]></category>
		<category><![CDATA[Diseño de páginas web]]></category>
		<category><![CDATA[Noticias]]></category>
		<category><![CDATA[Software de Gestión]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[ReportLab]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://www.cibernatural.com/?p=786</guid>
		<description><![CDATA[Cibernatural estrena una demo online de su Aplicación web de Gestión de Clientes, Facturación, Compras y Ventas realizado en Django. Los datos para la demo son los siguientes: URL: http://demoweb.cibernatural.com/admin Usuario: demo Clave: demo Nota: El usuario demo, puede hacer inserciones y modificaciones pero no puede realizar eliminaciones. El programa es muy sencillo pero a [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://demoweb.cibernatural.com/admin"><img src="http://www.cibernatural.com/wp-content/uploads/2011/02/demo-gestionweb-clientes1-300x108.jpg" alt="" title="demo-gestionweb-clientes" width="300" height="108" class="alignleft size-medium wp-image-956" /></a><a href="http://www.cibernatural.com">Cibernatural</a> estrena una <a href="http://demoweb.cibernatural.com/admin" target="_blank">demo online</a> de su <strong>Aplicación web de Gestión de Clientes, Facturación, Compras y Ventas</strong> realizado en <strong>Django</strong>.<br />
<br/><br />
Los datos para la demo son los siguientes:</p>
<ul>
<li>URL:    <a href="http://demoweb.cibernatural.com/admin"  target="_blank">http://demoweb.cibernatural.com/admin</a></li>
<li>Usuario:     <strong>demo</strong></li>
<li>Clave:        <strong>demo</strong></li>
</ul>
<p>Nota: El usuario demo, puede hacer inserciones y modificaciones pero no puede realizar eliminaciones.<br />
<span id="more-786"></span><br />
El programa es muy sencillo pero a la vez potente. Permite gestionar desde cualquier lugar y en cualquier momento los aspectos básicos de una empresa a través de un navegador. En concreto gestiona las siguientes entidades:</p>
<ul>
<li>Clientes</li>
<li>Facturas, Presupuestos, Partes de Entrega y Abonos de cada Cliente</li>
<li>Proveedores</li>
<li>Productos con Stockage</li>
<li>Compras de Productos</li>
<li>Ventas de Productos</li>
<li>Contactos</li>
<li>Tareas simples</li>
</ul>
<p>Además, genera mediante <strong>ReportLab</strong> todos los documentos PDF correspondientes: Factura, Presupuesto, etc., así como listados, como por ejemplo, listado de Facturas Pendientes de Cobro, Resumen de Facturación Mensual, etc. </p>
<p>El programa está preparado para operar en Canarias (IGIC), pero puede adaptarse fácilmente para otro tipo de requerimientos.</p>
<p><a href="http://www.cibernatural.com">Cibernatural</a> con tan sólo unos pequeños ajustes de configuración le personaliza su instancia para que la interfaz, los documentos, y los listados se ajusten a la imagen corporativa de su empresa.</p>
<p>La aplicación pretende pues, simplificar la gestión de la empresa y llevarla a la &#8220;nube” para que usted administre su empresa cuándo y donde quiera.</p>
<h3>Precios</h3>
<ul>
<li>Configuración y Despliegue de su instancia:  <strong>350 €  (pago único)</strong></li>
<li>Alojamiento y Soporte de actualizaciones:  <strong>90 € (año)</strong></li>
</ul>
<p>Si desea más información, puede ponerse en <a href="http://www.cibernatural.com/contacto">CONTACTO</a> con nosotros.</p>
<h3>Enlaces Relacionados</h3>
<ul>
<li><a href="http://www.cibernatural.com/gestion-web-de-clientes-y-facturacion-en-django/">Gestión web de clientes y facturación en Django</a></li>
</ul>

                            <div id="aspdf">
                                <a href="http://www.cibernatural.com/wp-content/plugins/as-pdf/generate.php?post=786">
                                    <span>Descargar en PDF</span>
                                </a>
                            </div>
                        ]]></content:encoded>
			<wfw:commentRss>http://www.cibernatural.com/demo-online-del-programa-de-gestion-web-en-django/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Web Corporativa del Estudio de Arquitectura en Lanzarote Equo6</title>
		<link>http://www.cibernatural.com/web-corporativa-del-estudio-de-arquitectura-en-lanzarote-equo6/</link>
		<comments>http://www.cibernatural.com/web-corporativa-del-estudio-de-arquitectura-en-lanzarote-equo6/#comments</comments>
		<pubDate>Wed, 29 Dec 2010 16:10:58 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Diseño de páginas web]]></category>
		<category><![CDATA[Arrecife]]></category>
		<category><![CDATA[Desarrollo web]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[Flash]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Lanzarote]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Página web]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://www.cibernatural.com/?p=767</guid>
		<description><![CDATA[Cibernatural acaba de estrenar la web corporativa del Estudio de Arquitectura en Lanzarote EQUO6 &#8211; Arquitectura, Forma, Luz y Color, proyecto realizado dentro del programa de bonos tecnológicos del Gobierno de Canarias, del que Cibernatural es proveedor. El desarrollo del portal web lo podemos dividir en la parte de diseño donde se ha utilizado un [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.equo6.com"><img src="http://www.cibernatural.com/wp-content/uploads/2010/12/logo_equo61.png" alt="" title="logo_equo6" width="80" height="133" class="alignleft size-full wp-image-969" /></a><a href="http://www.cibernatural.com">Cibernatural</a> acaba de estrenar la <strong>web corporativa</strong> del Estudio de Arquitectura en Lanzarote <a href="http://www.equo6.com">EQUO6 &#8211; Arquitectura, Forma, Luz y Color</a>, proyecto realizado dentro del <a href="http://www.gobiernodecanarias.org/aciisi/bonos/">programa de bonos tecnológicos del Gobierno de Canarias</a>, del que Cibernatural es <a href="http://www.cibernatural.com/proveedor-de-bonos-tecnologicos-del-gobierno-de-canarias/">proveedor</a>.</p>
<p>El desarrollo del <strong>portal web</strong> lo podemos dividir en la parte de diseño donde se ha utilizado un diseño para la sección de inicio y las secciones comunes a las 4 actividades del estudio (arquitectura, escultura, vidrio artístico y pintura), y otro diseño para cada una de dichas cuatro actividades. El primero presenta una animación en Flash que dota de una imagen dinámica al estudio, y el segundo diseño basado más en Javascript y CSS, pretende a partir de imágenes de fondo y distintos tonos de colores, diferenciar cada actividad y presentar a los visitantes las distintas obras de forma muy visual.<br />
<span id="more-767"></span><br />
Para la gestión del contenido, se ha utilizado una base de datos MySql, y <a href="http://www.cibernatural/tag/django">Django</a> como framework de desarrollo. Se han desarrollado las distintas plantillas Django como mezcla de los diseños expuestos anteriormente y las zonas de contenido dinámico que gestionará el mismo cliente desde la interfaz del Sitio de Administración de Django.</p>
<p>Las distintas entidades que el usuario puede manejar de forma dinámica incluyen los Servicios, Proyectos y Clientes de cada una de las 4 actividades (arquitectura, forma, luz y color), así como las noticias comunes al estudio.</p>
<p><br/><br />
<a href="http://www.equo6.com/arquitectura"><img src="http://www.cibernatural.com/wp-content/uploads/2010/12/arquitectura.jpg" alt="" title="arquitectura" width="500" height="274" class="aligncenter size-full wp-image-770" /></a><br />
<br/><br />
<a href="http://www.equo6.com/forma"><img src="http://www.cibernatural.com/wp-content/uploads/2010/12/forma.jpg" alt="" title="forma" width="500" height="350" class="aligncenter size-full wp-image-772" /></a><br />
<br/><br />
<a href="http://www.equo6.com/luz"><img src="http://www.cibernatural.com/wp-content/uploads/2010/12/luz.jpg" alt="" title="luz" width="500" height="319" class="aligncenter size-full wp-image-774" /></a><br />
<br/><br />
<a href="http://www.equo6.com/color"><img src="http://www.cibernatural.com/wp-content/uploads/2010/12/color.jpg" alt="" title="color" width="500" height="331" class="aligncenter size-full wp-image-775" /></a><br />
<br/></p>
<h3>Enlaces relacionados</h3>
<ul>
<li><a href="http://www.cibernatural.com/pagina-web-de-excellent-lanzarote/">Página web de Excellent Lanzarote</a></li>
<li><a href="http://www.cibernatural.com/web-corporativa-de-hormicasa-servicios-inmobiliarios/">Web corporativa de Hormicasa – Servicios inmobiliarios</a></li>
<li><a href="http://www.cibernatural.com/web-residencial-las-caletas/">Web Residencial Las Caletas</a></li>
<li><a href="http://www.cibernatural.com/gestion-inmobiliaria-y-gestion-web-para-remax-lanzarote/">Gestión inmobiliaria y gestión web para Remax Lanzarote</a></li>
<li><a href="http://www.cibernatural.com/web-residencial-apartamentos-playa-blanca/">Web Residencial Apartamentos Playa Blanca</a></li>
<li><a href="http://www.cibernatural.com/seo-y-sem-para-c2-gestion-inmobiliaria/">SEO y SEM para C2 Gestión Inmobiliaria</a></li>
</ul>

                            <div id="aspdf">
                                <a href="http://www.cibernatural.com/wp-content/plugins/as-pdf/generate.php?post=767">
                                    <span>Descargar en PDF</span>
                                </a>
                            </div>
                        ]]></content:encoded>
			<wfw:commentRss>http://www.cibernatural.com/web-corporativa-del-estudio-de-arquitectura-en-lanzarote-equo6/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Aplicación web de Gestión de Excursiones de Cruceros para Shore2Shore</title>
		<link>http://www.cibernatural.com/aplicacion-web-de-gestion-de-excursiones-de-cruceros-para-shore2shore/</link>
		<comments>http://www.cibernatural.com/aplicacion-web-de-gestion-de-excursiones-de-cruceros-para-shore2shore/#comments</comments>
		<pubDate>Fri, 10 Dec 2010 16:10:12 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Destacado]]></category>
		<category><![CDATA[Portales y Aplicaciones web complejas]]></category>
		<category><![CDATA[Bonos tecnológicos]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://www.cibernatural.com/?p=746</guid>
		<description><![CDATA[Cibernatural S.L. acaba de estrenar una potente aplicación web de gestión de excursiones de cruceros para Shore2Shore. Dicha aplicación se ha realizado dentro del Programa de Bonos Tecnológicos del Gobierno de Canarias, con objeto de mejorar el funcionamiento interno de la empresa, de conseguir un importante ahorro de tiempo, y en definitiva de mejorar la [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.shore2shore.es"><img src="http://www.cibernatural.com/wp-content/uploads/2010/12/logo_s2s.png" alt="" title="logo_s2s" width="165" height="165" class="alignleft size-full wp-image-944" /></a><a href="http://www.cibernatural.com">Cibernatural S.L. </a>acaba de estrenar una potente aplicación web de <strong>gestión de excursiones de cruceros</strong> para <a href="http://www.shore2shore.es">Shore2Shore</a>.</p>
<p>Dicha aplicación se ha realizado dentro del <a href="http://www.gobiernodecanarias.org/aciisi/bonos/">Programa de Bonos Tecnológicos del Gobierno de Canarias</a>, con objeto de mejorar el funcionamiento interno de la empresa, de conseguir un importante ahorro de tiempo, y en definitiva de mejorar la productividad y aumentar la rentabilidad de la misma.<br />
<span id="more-746"></span><br />
Una vez finalizado el análisis inicial donde se definieron todos los requisitos de la aplicación, se procedió al diseño de la aplicación, especialmente centrado en el diseño de los modelos de la base de datos, y en este caso en la definición exacta de los modelos de datos para las entidades de toda la aplicación (grupo, cliente, reserva, puerto, barco, agencia, proveedor, factura, etc.). </p>
<p>También se comenzó con el diseño de las plantillas de la parte de administración, y de la interfaz de proveedores, las cuales se eligió fueran diseñadas a partir de las plantillas base del sitio de administración de Django, debido a su simplicidad y claridad.</p>
<p>Una vez definido un modelo de datos inicial, se empezó a desarrollar la lógica de negocio establecida durante la fase de análisis por Shore2Shore, en forma de vistas y urls de Django, y que cubre todos los servicios solicitados por el cliente de forma personalizada. En resumen, y por citar algunos de ellos tenemos:</p>
<ul>
<li><strong>Gestión y carga inicial de datos de todas las entidades auxiliares involucradas en el sistema</strong> tales como: Paises, Puertos, Navieras, Barcos y Formas de Pago.</li>
<li><strong>Gestión y alta de todos los proveedores de buses y guías</strong> para cada uno de los puertos de cruceros donde se desarrollarán las excursiones.<br />
<a href="http://www.cibernatural.com/wp-content/uploads/2010/12/s2s-proveedores.jpg"><img src="http://www.cibernatural.com/wp-content/uploads/2010/12/s2s-proveedores.jpg" alt="" title="s2s-proveedores" width="400" height="300" class="aligncenter size-full wp-image-753" /></a>
</li>
<li><strong>Gestión y alta de todas las agencias de viajes colaboradoras</strong>.</li>
<li><strong>Gestión de Grupos de excursiones</strong>, con toda la lógica que ello conlleva: gestión de los clientes de excursiones, generación de documentos tales como el estado del grupo, la tarjeta de excursión o bono de cada cliente, los envíos via email de apertura, estado o cierre del grupo a los proveedores, los envíos de bonos a clientes que cumplen determinados criterios, la creación de una reserva asociada al grupo, etc.<br />
<a href="http://www.cibernatural.com/wp-content/uploads/2010/12/s2s-grupo.jpg"><img src="http://www.cibernatural.com/wp-content/uploads/2010/12/s2s-grupo.jpg" alt="" title="s2s-grupo" width="400" height="300" class="aligncenter size-full wp-image-751" /></a>
</li>
<li>Gestión de Reservas (Booking List):  gestión de toda la lógica de reservas para interactuar con los proveedores a la hora de la petición de servicios (buses y guías) en cada puerto. Establecimiento de la forma de pago asociada a esa reserva de entre 5 formas de pago posibles. Generación y Envío por Email del booking list (lista de reservas) actual para cada proveedor de buses y/o guías y del booking list total para Shore2Shore.<br />
<a href="http://www.cibernatural.com/wp-content/uploads/2010/12/s2s-booking-list.jpg"><img src="http://www.cibernatural.com/wp-content/uploads/2010/12/s2s-booking-list.jpg" alt="" title="s2s-booking-list" width="400" height="300" class="aligncenter size-full wp-image-754" /></a>
</li>
<li><strong>Intefaz en inglés para que los proveedores de buses y guías</strong> en los distintos países acepten/deniegen servicios solicitados por Shore2Shore según disponibilidad y precios.</li>
<li><strong>Generación automática de todas las facturas por comisiones</strong> del mes a cada uno de los proveedores y agencias con reservas liquidadas durante dicho mes y envío automático por email de todas ellas. Este punto conlleva un ahorro de tiempo muy importante para Shore2Shore y es un aspecto clave del sistema de gestión.<br />
<a href="http://www.cibernatural.com/wp-content/uploads/2010/12/s2s-facturas.jpg"><img src="http://www.cibernatural.com/wp-content/uploads/2010/12/s2s-facturas.jpg" alt="" title="s2s-facturas" width="400" height="300" class="aligncenter size-full wp-image-755" /></a>
</li>
<li>Con el sistema de usuarios y roles de Django se crean usuarios dentro de la aplicación que puedan realizar determinadas tareas, como por ejemplo, dar de alta clientes dentro de un grupo de excursión, etc., de forma que Shore2Shore pueda contratar personal para realizar tareas determinadas sin acceder a información crítica.</li>
</ul>

                            <div id="aspdf">
                                <a href="http://www.cibernatural.com/wp-content/plugins/as-pdf/generate.php?post=746">
                                    <span>Descargar en PDF</span>
                                </a>
                            </div>
                        ]]></content:encoded>
			<wfw:commentRss>http://www.cibernatural.com/aplicacion-web-de-gestion-de-excursiones-de-cruceros-para-shore2shore/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Aplicación web de Reserva de Canchas de Padel</title>
		<link>http://www.cibernatural.com/aplicacion-web-de-reserva-de-canchas-de-padel/</link>
		<comments>http://www.cibernatural.com/aplicacion-web-de-reserva-de-canchas-de-padel/#comments</comments>
		<pubDate>Fri, 01 Oct 2010 09:12:59 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Destacado]]></category>
		<category><![CDATA[Portales y Aplicaciones web complejas]]></category>
		<category><![CDATA[Software de Gestión]]></category>
		<category><![CDATA[Arrecife]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[Lanzarote]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Reservas]]></category>

		<guid isPermaLink="false">http://www.cibernatural.com/?p=704</guid>
		<description><![CDATA[Cibernatural S.L. estrena una nueva aplicación de gestión de reservas de canchas de Padel en Arrecife &#8211; Lanzarote, para FullPadel S.L. http://reservas.fullpadel.com La aplicación desarrollada en Django, en su parte de administración, permite el registro de todos los datos de los clientes, la asignación de un nombre de usuario y contraseña para que puedan realizar [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://reservas.fullpadel.com"><img src="http://www.cibernatural.com/wp-content/uploads/2010/10/fullpadellogo.jpg" alt="" title="fullpadellogo" width="200" height="79" class="alignleft size-full wp-image-960" /></a><a href="http://www.cibernatural.com">Cibernatural S.L.</a> estrena una nueva aplicación de gestión de <strong>reservas de canchas de Padel</strong> en Arrecife &#8211; Lanzarote, para <a href="http://www.fullpadel.com">FullPadel S.L.</a></p>
<p><a href="http://reservas.fullpadel.com" target="_blank">http://reservas.fullpadel.com</a></p>
<p>La aplicación desarrollada en <strong>Django</strong>, en su parte de administración, permite el registro de todos los datos de los clientes, la asignación de un nombre de usuario y contraseña para que puedan realizar las reservas, y se les proporciona determinados privilegios en función de si son socios o no (número de días vista para poder realizar reservas).<br />
<span id="more-704"></span><br />
En la interfaz pública, los clientes reservan las canchas de Padel en los horarios que más les convengan de forma sencilla, en cualquier momento y desde cualquier lugar, por ejemplo, mediante un dispositivo móvil (IPhone, etc.)</p>

                            <div id="aspdf">
                                <a href="http://www.cibernatural.com/wp-content/plugins/as-pdf/generate.php?post=704">
                                    <span>Descargar en PDF</span>
                                </a>
                            </div>
                        ]]></content:encoded>
			<wfw:commentRss>http://www.cibernatural.com/aplicacion-web-de-reserva-de-canchas-de-padel/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Tutorial de Django – VII</title>
		<link>http://www.cibernatural.com/tutorial-de-django-vii/</link>
		<comments>http://www.cibernatural.com/tutorial-de-django-vii/#comments</comments>
		<pubDate>Thu, 19 Aug 2010 10:37:45 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Guía Django]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://www.cibernatural.com/?p=678</guid>
		<description><![CDATA[Vistas y URLconfs avanzadas Trucos URLconf No hay nada &#8220;especial&#8221; en URLconfs &#8211; como todo en Django, sólo código Python.  Racionalizar las importaciones de funciones Considerar la siguiente URLconf, basada en un ejemplo visto anteriormente: from django.conf.urls.defaults import * from mysite.views import hello, current_datetime, hours_ahead urlpatterns = patterns(&#8221;, (r&#8217;^hello/$&#8217;, hello), (r&#8217;^time/$&#8217;, current_datetime), (r&#8217;^time/plus/(\d{1,2})/$&#8217;, hours_ahead), ) [...]]]></description>
			<content:encoded><![CDATA[<h2><strong><span style="text-decoration: underline;">Vistas y URLconfs avanzadas</span></strong></h2>
<p><br/></p>
<h3>Trucos URLconf</h3>
<p>No hay nada &#8220;especial&#8221; en URLconfs &#8211; como todo en Django, sólo código Python. </p>
<p>Racionalizar las importaciones de funciones</p>
<p>Considerar la siguiente URLconf, basada en un ejemplo visto anteriormente: </p>
<blockquote><p>from django.conf.urls.defaults import *<br />
from mysite.views import hello, current_datetime, hours_ahead</p>
<p>urlpatterns = patterns(&#8221;,</p>
<p style="padding-left:30px">	(r&#8217;^hello/$&#8217;, hello),<br />
	(r&#8217;^time/$&#8217;, current_datetime),<br />
	(r&#8217;^time/plus/(\d{1,2})/$&#8217;, hours_ahead),</p>
<p>)</p></blockquote>
<p><span id="more-678"></span><br />
Cada entrada en la URLconf incluye su vista asociada, pasada directamente como un objeto de función. Esto significa que es necesario importar la vista al prinicipio del módulo.</p>
<p>Pero, cuando una aplicación de Django crece en complejidad, su URLconf también crece, y gestionar esas importaciones puede ser tedioso. (Para cada nueva vista, usted tendría que recordar importarla, y la declaración de importación tiende a ser demasiado larga si se utiliza este enfoque.) Es posible evitar esto con la importación de propio módulo views. Este ejemplo de URLconf es equivalente al anterior: </p>
<blockquote><p>from django.conf.urls.defaults import *<br />
from mysite import views</p>
<p>urlpatterns = patterns(&#8221;,</p>
<p style="padding-left:30px">(r&#8217;^hello/$&#8217;, views.hello),<br />
	(r&#8217;^time/$&#8217;, views.current_datetime),<br />
	(r&#8217;^time/plus/(d{1,2})/$&#8217;, views.hours_ahead),</p>
<p>)
</p></blockquote>
<p>Django ofrece otra manera de especificar la vista de un patrón particular en el URLconf: se puede pasar una cadena que contenga el nombre del módulo y el nombre de la vista en lugar del objeto de función en sí mismo. Continuando con el ejemplo en curso: </p>
<blockquote><p>from django.conf.urls.defaults import *</p>
<p>urlpatterns = patterns(&#8221;,</p>
<p style="padding-left:30px">(r&#8217;^hello/$&#8217;, &#8216;mysite.views.hello&#8217;),<br />
	(r&#8217;^time/$&#8217;, &#8216;mysite.views.current_datetime&#8217;),<br />
	(r&#8217;^time/plus/(d{1,2})/$&#8217;, &#8216;mysite.views.hours_ahead&#8217;),</p>
<p>)
</p></blockquote>
<p>Notar las comillas que delimitan los nombres de las vistas.</p>
<p>Usando esta técnica, ya no es necesario importar las vistas; Django automáticamente importa la función de vista apropiada la primera vez que se necesita, según la cadena que describe el nombre y la ruta de la función de vista.</p>
<p>Una abreviatura más que usted puede usar cuando utiliza esta técnica es factorizar un &#8220;prefijo de vista&#8221; común. En nuestro ejemplo de URLconf, cada una de las cadenas de vista comienza con &#8216;mysite.views&#8217;. Podemos factorizar este prefijo común y pasarlo como el primer argumento a los patrones, así: </p>
<blockquote><p>from django.conf.urls.defaults import *<br />
urlpatterns = patterns(&#8216;mysite.views&#8217;,</p>
<p style="padding-left:30px">(r&#8217;^hello/$&#8217;, &#8216;hello&#8217;),<br />
	(r&#8217;^time/$&#8217;, &#8216;current_datetime&#8217;),<br />
	(r&#8217;^time/plus/(d{1,2})/$&#8217;, &#8216;hours_ahead&#8217;),</p>
<p>)
</p></blockquote>
<p>Con estos dos enfoques en mente, ¿cuál es mejor? Realmente depende de su estilo personal de programación y de sus necesidades.</p>
<p>Las ventajas de la cadena son las siguientes:</p>
<ul>
<li>Es más compacto, porque no es necesario importar las funciones de vista.</li>
<li>El resultado es URLconfs más legibles y manejables si las funciones de su vista se reparten entre diferentes módulos de Python.</li>
</ul>
<p>Las ventajas del enfoque de objeto de función son las siguientes:</p>
<ul>
<li>Se permite un fácil &#8220;ajuste&#8221; de las funciones de vista.</li>
<li>Es más acorde con las tradiciones de Python, como pasar funciones como objetos.</li>
</ul>
<p>Ambos enfoques son válidos, e incluso se pueden mezclar en el mismo URLconf. La elección es suya.</p>
<h3>Usar varios Prefijos de Vista</h3>
<p>En la práctica, si utiliza la técnica de cadena, probablemente acabe mezclando vistas que no tienen un prefijo común. Sin embargo, usted aún puede usar la abreviatura del prefijo de vistas para eliminar la duplicación. Sólo tiene que añadir varios objetos patterns() juntos, así:</p>
<blockquote><p>from django.conf.urls.defaults import *</p>
<p>urlpatterns = patterns(&#8216;mysite.views&#8217;,</p>
<p style="padding-left:30px">(r&#8217;^hello/$&#8217;, &#8216;hello&#8217;),<br />
	(r&#8217;^time/$&#8217;, &#8216;current_datetime&#8217;),<br />
	(r&#8217;^time/plus/(\d{1,2})/$&#8217;, &#8216;hours_ahead&#8217;),</p>
<p>)</p>
<p>urlpatterns += patterns(&#8216;weblog.views&#8217;,</p>
<p style="padding-left:30px">(r&#8217;^tag/(\w+)/$&#8217;, &#8216;tag&#8217;),</p>
<p>)
</p></blockquote>
<h3>URLs especiales en modo Debug</h3>
<p>Hablando de la construcción de urlpatterns de forma dinámica, es posible que desee tomar ventaja de esta técnica alterando el comportamiento de su URLconf en el modo de depuración de Django. Para ello, basta con comprobar el valor de la propiedad DEBUG en tiempo de ejecución, así: </p>
<blockquote><p>from django.conf import settings<br />
from django.conf.urls.defaults import *<br />
from mysite import views</p>
<p>urlpatterns = patterns(&#8221;,</p>
<p style="padding-left:30px">(r&#8217;^$&#8217;, views.homepage),<br />
	(r&#8217;^(\d{4})/([a-z]{3})/$&#8217;, views.archive_month),</p>
<p>)</p>
<p>if settings.DEBUG:</p>
<p style="padding-left:30px">urlpatterns += patterns(&#8221;,</p>
<p style="padding-left:60px">(r&#8217;^debuginfo/$&#8217;, views.debug),</p>
<p style="padding-left:30px">)</p>
</blockquote>
<p>En este ejemplo, la URL /debuginfo/ estará disponible sólo si la propiedad DEBUG es True.</p>
<h3>Uso de Grupos con nombre</h3>
<p>En todos nuestros ejemplos de URLconf hasta ahora, hemos usado, grupos de expresiones regulares sin nombre, es decir, ponemos entre paréntesis las partes de la URL que queremos capturar y, Django pasa ese texto capturado a la función de vista como un argumento posicional. En un uso más avanzado, es posible utilizar grupos con nombre de expresiones regulares para capturar los bits de la URL y pasarlos como argumentos de palabra clave a una vista. </p>
<p>En las expresiones regulares Python, la sintaxis para grupos con nombre de expresiones regulares es (?P<name>pattern), donde name es el nombre del grupo y pattern es un patrón de concordancia.</p>
<p>He aquí un ejemplo de URLconf que usa grupos sin nombre: </p>
<blockquote><p>from django.conf.urls.defaults import *<br />
from mysite import views</p>
<p>urlpatterns = patterns(&#8221;,</p>
<p style="padding-left:30px">(r&#8217;^articles/(\d{4})/$&#8217;, views.year_archive),<br />
	(r&#8217;^articles/(\d{4})/(\d{2})/$&#8217;, views.month_archive),</p>
<p>)
</p></blockquote>
<p>Aquí, la misma URLConf reescrita, usando grupos con nombre:</p>
<blockquote><p>from django.conf.urls.defaults import *<br />
from mysite import views</p>
<p>urlpatterns = patterns(&#8221;,</p>
<p style="padding-left:30px">(r&#8217;^articles/(?P<year>\d{4})/$&#8217;, views.year_archive),<br />
	(r&#8217;^articles/(?P<year>\d{4})/(?P<month>\d{2})/$&#8217;, views.month_archive),</p>
<p>)
</p></blockquote>
<p>Esto logra exactamente lo mismo que el ejemplo anterior, con una sutil diferencia: los valores capturados se pasan a las funciones de vista como argumentos de palabras clave en lugar de argumentos posicionales.</p>
<p>Por ejemplo, con grupos sin nombre, una petición a /articles/2006/03/ daría lugar a una llamada a la función equivalente a esto: </p>
<p>month_archive(request, &#8217;2006&#8242;, &#8217;03&#8242;)</p>
<p>Con grupos con nombre, la misma petición resultaría en esta llamada a función:</p>
<p>month_archive(request, year=&#8217;2006&#8242;, month=&#8217;03&#8242;)</p>
<p>En la práctica, usar grupos con nombre hace a su URLconfs un poco más explícita y menos propensa a los errores del orden de los argumentos y puede volver a ordenar los argumentos de la función sus definiciones de vistas. Siguiendo el ejemplo anterior, si quisieramos cambiar la URL para incluir el mes antes del año, y  estamos utilizando grupos sin nombre, tendríamos que recordar cambiar el orden de los argumentos en la vista month_archive. Si estuviéramos utilizando grupos con nombre, cambiar el orden de los parámetros capturados en la URL no tendría ningún efecto en la vista.</p>
<p>Por supuesto, los beneficios de los grupos con nombre llegan a costa de la brevedad; algunos desarrolladores encuentran la sintaxis de un grupo con nombre fea y demasiado detallada. Sin embargo, otra de las ventajas de los grupos con nombre es la legibilidad, especialmente para aquellos que no están íntimamente familiarizados con expresiones regulares o su aplicación de Django particular. Es más fácil ver lo que sucede, de un vistazo, en una URLconf que utiliza grupos con nombre. </p>
<h3>Comprender el algoritmo de agrupación/concordancia</h3>
<p>Una advertencia con el uso de grupos con nombre en una URLconf es que un único patrón de URLconf no puede contener tanto grupos con nombre como sin nombre. Si usted hace esto, Django no dará ningún error, pero usted probablemente encontrará que sus URLs no son coincidentes tal y como usted espera. En concreto, aquí está el algoritmo que sigue el analizador URLconf:</p>
<ul>
<li>Si hay algunos argumentos con nombre, utilizará esos, haciendo caso omiso de los argumentos con nombre.</li>
<li>De lo contrario, pasará todos los argumentos sin nombre como argumentos posicionales.</li>
<li>En ambos casos, pasará opciones adicionales como argumentos de palabra clave.</li>
</ul>
<h3>Pasar opciones extra a funciones de vista</h3>
<p>A veces usted se encontrará con la escritura de funciones de vista que son bastante similares, con sólo unas pequeñas diferencias. Por ejemplo, supongamos que tiene dos vistas cuyos contenidos son idénticos, excepto por las plantillas que utilizan: </p>
<blockquote><p>
# urls.py<br />
from django.conf.urls.defaults import *<br />
from mysite import views</p>
<p>urlpatterns = patterns(&#8221;,</p>
<p style="padding-left:30px">(r&#8217;^foo/$&#8217;, views.foo_view),<br />
	(r&#8217;^bar/$&#8217;, views.bar_view),</p>
<p>)</p>
<p># views.py<br />
from django.shortcuts import render_to_response<br />
from mysite.models import MyModel</p>
<p>def foo_view(request):</p>
<p style="padding-left:30px">m_list = MyModel.objects.filter(is_new=True)<br />
	return render_to_response(&#8216;template1.html&#8217;, {&#8216;m_list&#8217;: m_list})</p>
<p>def bar_view(request):</p>
<p style="padding-left:30px">m_list = MyModel.objects.filter(is_new=True)<br />
	return render_to_response(&#8216;template2.html&#8217;, {&#8216;m_list&#8217;: m_list})</p>
</blockquote>
<p>Estamos repitiendo el código, y eso es poco elegante. En principio, usted puede pensar eliminar la redundancia utilizando el mismo punto de vista, tanto para las direcciones URL, poniendo entre paréntesis la URL a capturar, y comprobar la URL dentro de la vista para determinar la plantilla, así:</p>
<blockquote><p>
# urls.py<br />
from django.conf.urls.defaults import *<br />
from mysite import views</p>
<p>urlpatterns = patterns(&#8221;,</p>
<p style="padding-left:30px">(r&#8217;^(foo)/$&#8217;, views.foobar_view),<br />
	(r&#8217;^(bar)/$&#8217;, views.foobar_view),</p>
<p>)</p>
<p># views.py<br />
from django.shortcuts import render_to_response<br />
from mysite.models import MyModel</p>
<p>def foobar_view(request, url):</p>
<p style="padding-left:30px">m_list = MyModel.objects.filter(is_new=True)<br />
	if url == &#8216;foo&#8217;:</p>
<p style="padding-left:60px">template_name = &#8216;template1.html&#8217;</p>
<p style="padding-left:30px">elif url == &#8216;bar&#8217;:</p>
<p style="padding-left:60px">template_name = &#8216;template2.html&#8217;</p>
<p style="padding-left:30px">return render_to_response(template_name, {&#8216;m_list&#8217;: m_list})</p>
</blockquote>
<p>El problema con esta solución, sin embargo, es que acopla las URL a su código. Si usted decide cambiar el nombre /foo/ a /fooey/, tendrá que acordarse de cambiar el código de la vista.</p>
<p>La solución elegante implica un parámetro URLconf opcional. Cada patrón en una URLconf puede incluir un tercer elemento: un diccionario de los argumentos de palabra clave para pasar a la función de vista.</p>
<p>Con esto en mente, podemos volver a escribir nuestro ejemplo actual de esta manera: </p>
<blockquote><p>
# urls.py<br />
from django.conf.urls.defaults import *<br />
from mysite import views<br />
urlpatterns = patterns(&#8221;,</p>
<p style="padding-left:30px">(r&#8217;^foo/$&#8217;, views.foobar_view, {&#8216;template_name&#8217;: &#8216;template1.html&#8217;}),<br />
	(r&#8217;^bar/$&#8217;, views.foobar_view, {&#8216;template_name&#8217;: &#8216;template2.html&#8217;}),</p>
<p>)</p>
<p># views.py<br />
from django.shortcuts import render_to_response<br />
from mysite.models import MyModel</p>
<p>def foobar_view(request, template_name):</p>
<p style="padding-left:30px">m_list = MyModel.objects.filter(is_new=True)<br />
	return render_to_response(template_name, {&#8216;m_list&#8217;: m_list})</p>
</blockquote>
<p>Esta técnica de opciones URLconf extra es una buena forma de enviar información adicional a las funciones de la vista con una sobrecarga mínimo.</p>
<p>Las siguientes secciones contienen un par de ideas sobre cómo utilizar la técnica de opciones de URLconf extra en sus propios proyectos.</p>
<h3>Fingiendo valores URLConf capturados</h3>
<p>Digamos que tiene un conjunto de vistas que coinciden con un patrón, junto con otra URL que no se ajusta a ese patrón, pero cuya lógica de la vista es la misma. En este caso, puede &#8220;falsear&#8221; la captación de valores URL mediante el uso de opciones URLconf extra para manejar esa URL adicional con la misma vista.</p>
<p>Por ejemplo, usted podría tener una aplicación que muestre algunos datos de un día en particular, con direcciones de Internet tales como las siguientes:</p>
<p>/mydata/jan/01/<br />
/mydata/jan/02/<br />
/mydata/jan/03/<br />
# &#8230;<br />
/mydata/dec/30/<br />
/mydata/dec/31/</p>
<p>Esto es bastante simple &#8211; usted puede capturarlos con una URLconf como esta (con sintaxis de grupos con nombre): </p>
<blockquote><p>
urlpatterns = patterns(&#8221;,</p>
<p style="padding-left:30px">(r&#8217;^mydata/(?P<month>\w{3})/(?P<day>\d\d)/$&#8217;, views.my_view),</p>
<p>)
</p></blockquote>
<p>Y la función de vista sería así: </p>
<blockquote><p>
def my_view(request, month, day):</p>
<p style="padding-left:30px"># &#8230;.</p>
</blockquote>
<p>Ese método es sencillo &#8211; no es nada que no haya visto antes. El truco viene cuando se quiere añadir otra URL que utiliza my_view pero cuya URL no incluye un mes y/o día.</p>
<p>Por ejemplo, usted podría querer agregar otra URL, /mydata/birthday/, que sería equivalente a /mydata/jan/06/ :</p>
<blockquote><p>
urlpatterns = patterns(&#8221;,</p>
<p style="padding-left:30px">(r&#8217;^mydata/birthday/$&#8217;, views.my_view, {&#8216;month&#8217;: &#8216;jan&#8217;, &#8216;day&#8217;: &#8217;06&#8242;}),<br />
	(r&#8217;^mydata/(?P<month>\w{3})/(?P<day>\d\d)/$&#8217;, views.my_view),</p>
<p>)
</p></blockquote>
<p>Usted no tiene que cambiar su función de vista en absoluto.</p>
<h3>Hacer una vista genérica</h3>
<p>Es buena práctica de programación &#8220;factorizar&#8221; puntos comunes en el código. Por ejemplo, con estas dos funciones de Python: </p>
<blockquote><p>
def say_hello(person_name):</p>
<p style="padding-left:30px">print &#8216;Hello, %s&#8217; % person_name</p>
<p>def say_goodbye(person_name):</p>
<p style="padding-left:30px">print &#8216;Goodbye, %s&#8217; % person_name</p>
</blockquote>
<p>podemos factorizarlas usando un parámetro:</p>
<blockquote><p>
def greet(person_name, greeting):</p>
<p style="padding-left:30px">print &#8216;%s, %s&#8217; % (greeting, person_name)</p>
</blockquote>
<p>Podemos aplicar esta misma filosofía a las vista Django usando parámetros adicionales URLconf. Con esto en mente, usted puede comenzar a hacer abstracciones de alto nivel de sus vistas. En lugar de pensar: &#8220;Esta vista muestra una lista de objetos Event,&#8221; y &#8220;Esta vista muestra una lista de objetos BlogEntry&#8221;, dese cuenta que ambos son casos específicos de vista que muestra una lista de objetos, donde el tipo de objeto es variable.</p>
<p>Tome este código, por ejemplo: </p>
<blockquote><p>
# urls.py<br />
from django.conf.urls.defaults import *<br />
from mysite import views</p>
<p>urlpatterns = patterns(&#8221;,</p>
<p style="padding-left:30px">(r&#8217;^events/$&#8217;, views.event_list),<br />
	(r&#8217;^blog/entries/$&#8217;, views.entry_list),</p>
<p>)</p>
<p># views.py<br />
from django.shortcuts import render_to_response<br />
from mysite.models import Event, BlogEntry</p>
<p>def event_list(request):</p>
<p style="padding-left:30px">obj_list = Event.objects.all()<br />
	return render_to_response(&#8216;mysite/event_list.html&#8217;, {&#8216;event_list&#8217;: obj_list})</p>
<p>def entry_list(request):</p>
<p style="padding-left:30px">obj_list = BlogEntry.objects.all()<br />
	return render_to_response(&#8216;mysite/blogentry_list.html&#8217;,{&#8216;entry_list&#8217;: obj_list})</p>
</blockquote>
<p>Las dos vistas hacen esencialmente lo mismo: mostrar una lista de objetos. Factoricemos el tipo de objeto que estamos mostrando: </p>
<blockquote><p>
# urls.py<br />
from django.conf.urls.defaults import *<br />
from mysite import models, views</p>
<p>urlpatterns = patterns(&#8221;,</p>
<p style="padding-left:30px">(r&#8217;^events/$&#8217;, views.object_list, {&#8216;model&#8217;: models.Event}),<br />
	(r&#8217;^blog/entries/$&#8217;, views.object_list, {&#8216;model&#8217;: models.BlogEntry}),</p>
<p>)</p>
<p># views.py<br />
from django.shortcuts import render_to_response</p>
<p>def object_list(request, model):</p>
<p style="padding-left:30px">obj_list = model.objects.all()<br />
	template_name = &#8216;mysite/%s_list.html&#8217; % model.__name__.lower()<br />
	return render_to_response(template_name, {&#8216;object_list&#8217;: obj_list})</p>
</blockquote>
<p>Con estos pequeños cambios, de repente tenemos una vista reutilizable, independiente del modelo. A partir de ahora, cada vez que necesitemos una vista que muestre un conjunto de objetos, podemos simplemente volver a utilizar esta vista object_list.  Un par de apuntes de lo realizado:</p>
<ul>
<li>Pasamos las clases del modelo directamente, como el parámetro model. El diccionario de opciones URLConf extra puede pasar cualquier tipo de objeto – no sólo cadenas.</li>
<li>Usamos model.__name__.lower () para determinar el nombre de la plantilla. Cada clase Python tiene un atributo __name__ que devuelve el nombre de la clase. Esta función es útil en momentos como éste, cuando no sabemos el tipo de clase hasta el tiempo de ejecución.</li>
<li>Pasamos el nombre de variable genérico object_list a la plantilla. Fácilmente podríamos cambiar este nombre a blogentry_list o event_list.</li>
</ul>
<p>Dado que los sitios web de bases de datos tienen varios patrones comunes, Django viene con un conjunto de &#8220;vistas genéricas&#8221; que utilizan esta técnica para ahorrar tiempo.</p>
<h3>Dar opciones de configuración de vista</h3>
<p>Si está desarrollando una aplicación Django, lo más probable es que los usuarios quieran algún grado de configuración. En este caso, es una buena idea añadir ganchos a sus vistas para las opciones de configuración que crea que la gente puede cambiar. Puede utilizar parámetros URLConf adicionales para este propósito.</p>
<p>Un parte común de una aplicación para configurar es el nombre de la plantilla:</p>
<blockquote><p>
def my_view(request, template_name):</p>
<p style="padding-left:30px">var = do_something()<br />
	return render_to_response(template_name, {&#8216;var&#8217;: var}) </p>
</blockquote>
<h3>Comprender la precedencia de los valores capturados frente a las opciones extra</h3>
<p>Cuando hay un conflicto, los parámetros URLconf extra tienen prioridad sobre los parámetros de captura.</p>
<p>En otras palabras, si su URLconf captura una variable de un grupo con nombre y un parámetro URLconf extra incluye una variable con el mismo nombre, el valor del parámetro URLconf extra será utilizado. Por ejemplo, considere esta URLconf: </p>
<blockquote><p>
from django.conf.urls.defaults import *<br />
from mysite import views</p>
<p>urlpatterns = patterns(&#8221;,</p>
<p style="padding-left:30px">(r&#8217;^mydata/(?P<id>\d+)/$&#8217;, views.my_view, {&#8216;id&#8217;: 3}),</p>
<p>)
</p></blockquote>
<p>Aquí, tanto la expresión regular como el diccionario extra incluyen un id. <br />
Cualquier petición (por ejemplo, /mydata/2/ o /mydata/432432/) será tratada como si id es 3, con independencia del valor capturado en la URL. Notamos esto sólo para ayudarle a evitar caer en el error. </p>
<h3>Usar argumentos de vista por defecto</h3>
<p>Otro truco conveniente es especificar los parámetros por defecto para los argumentos de una vista. Esto le dice a la vista que valor usar porn defecto para un parámetro si no se especifica ninguno. He aquí un ejemplo: </p>
<blockquote><p>
# urls.py<br />
from django.conf.urls.defaults import *<br />
from mysite import views</p>
<p>urlpatterns = patterns(&#8221;,</p>
<p style="padding-left:30px">(r&#8217;^blog/$&#8217;, views.page),<br />
	(r&#8217;^blog/page(?P<num>\d+)/$&#8217;, views.page),</p>
<p>)</p>
<p># views.py<br />
def page(request, num=&#8217;1&#8242;):</p>
<p style="padding-left:30px"># Output the appropriate page of blog entries, according to num.<br />
	# &#8230;</p>
</blockquote>
<p>Aquí, ambas URLpatterns apuntan a la misma vista <em>views.page</em>, pero el primer patrón no captura cualquier cosa desde la URL. Si el primer patrón concuerda, la función page() usará su argumento predeterminado para num, &#8220;1&#8243;. Si el segundo patrón concuerda, page() utilizará cualquier valor num capturado por la expresión regular.</p>
<p>Es común el uso de esta técnica en relación con las opciones de configuración, como se explicó anteriormente. En el siguiente ejemplo se hace una ligera mejora con el ejemplo de la sección &#8220;Dar opciones de configuración de vista&#8221;, proporcionando un valor predeterminado para <em>template_name</em>: </p>
<blockquote><p>
def my_view(request, template_name=&#8217;mysite/my_view.html&#8217;):</p>
<p style="padding-left:30px">var = do_something()<br />
	return render_to_response(template_name, {&#8216;var&#8217;: var})</p>
</blockquote>
<h3>Vistas de casos especiales</h3>
<p>A veces usted tiene un patrón en su URLconf que maneja un gran conjunto de direcciones URL, pero usted necesitará un caso especial de ellas. En este caso, aprovechar la manera lineal en que trabaja una URLconf y colocar el caso particular en primer lugar.</p>
<p>Por ejemplo, usted puede pensar en páginas de &#8220;agregar un objeto&#8221; en el sitio de administración de Django, representado por un URLpattern así: </p>
<blockquote><p>
urlpatterns = patterns(&#8221;,</p>
<p style="padding-left:30px"># &#8230;<br />
	(&#8216;^([^/]+)/([^/]+)/add/$&#8217;, views.add_stage),<br />
	# &#8230;</p>
<p>)
</p></blockquote>
<p>Esto coincide con las URL como /myblog/entries/add/ y /auth/groups/add/. Sin embargo, la página &#8220;Añadir&#8221; para un objeto de usuario (/auth/user/add/) es un caso especial &#8211; que no muestra todos los campos del formulario, muestra dos campos de contraseña, etc. Podríamos resolver este problema mediante el caso especial en la vista, de este modo: </p>
<blockquote><p>
def add_stage(request, app_label, model_name):</p>
<p style="padding-left:30px">if app_label == &#8216;auth&#8217; and model_name == &#8216;user&#8217;:</p>
<p style="padding-left:60px"># do special-case code</p>
<p style="padding-left:30px">else:</p>
<p style="padding-left:60px"># do normal code</p>
</blockquote>
<p>pero eso es poco elegante por la razón que hemos visto varias veces en este capítulo: pone lógica de URL en la vista. Como una solución más elegante, podemos aprovechar el hecho de que las URLconfs se procesan en orden de arriba a abajo:</p>
<blockquote><p>
urlpatterns = patterns(&#8221;,</p>
<p style="padding-left:30px"># &#8230;<br />
	(&#8216;^auth/user/add/$&#8217;, views.user_add_stage),<br />
	(&#8216;^([^/]+)/([^/]+)/add/$&#8217;, views.add_stage),<br />
	# &#8230;</p>
<p>)
</p></blockquote>
<p>Ahora, una petición a /auth/user/add/ será manejada por la vista user_add_stage. A pesar de que la URL coincide con el segundo patrón, coincide con el de arriba primero.</p>
<h3>Capturar texto en las URLs</h3>
<p>Cada argumento capturado es enviado a la vista como una simple cadena Unicode de Python, independientemente del orden de concordancia que la expresión regular hace. Por ejemplo, en esta línea URLconf, el argumento year para views.year_archive() será una cadena, no un entero, incluso aunque \d{4} sólo concuerde con cadenas de enteros:</p>
<blockquote><p>(r&#8217;^articles/(?P<year>\d{4})/$&#8217;, views.year_archive),</p></blockquote>
<p>Esto es importante tenerlo en cuenta cuando se está escribiendo el código de la vista. Muchas funciones Python sólo aceptann objetos de cierto tipo. Un error común es tratar de crear un objeto datetime.date con valores de cadena en lugar de valores enteros valores: </p>
<blockquote><p>
&gt;&gt;&gt; import datetime<br />
&gt;&gt;&gt; datetime.date(&#8217;1993&#8242;, &#8217;7&#8242;, &#8217;9&#8242;)<br />
Traceback (most recent call last):<br />
&#8230;<br />
TypeError: an integer is required<br />
&gt;&gt;&gt; datetime.date(1993, 7, 9)<br />
datetime.date(1993, 7, 9)
</p></blockquote>
<p>Trasladado a una URLConf y vista, el error se parecería a esto:</p>
<blockquote><p>
# urls.py<br />
from django.conf.urls.defaults import *<br />
from mysite import views</p>
<p>urlpatterns = patterns(&#8221;,</p>
<p style="padding-left:30px">(r&#8217;^articles/(\d{4})/(\d{2})/(\d{2})/$&#8217;, views.day_archive),</p>
<p>)</p>
<p># views.py<br />
import datetime</p>
<p>def day_archive(request, year, month, day):</p>
<p style="padding-left:30px"># The following statement raises a TypeError!<br />
	date = datetime.date(year, month, day)</p>
</blockquote>
<p>En lugar de esto, day_archive() podría escribirse correctamente así:</p>
<blockquote><p>
def day_archive(request, year, month, day):</p>
<p style="padding-left:30px">date = datetime.date(int(year), int(month), int(day))</p>
</blockquote>
<p>Tenga en cuenta que int () eleva un ValueError al pasar una cadena que no está compuesto exclusivamente de dígitos, pero estamos evitando el error en este caso porque la expresión regular en nuestra URLconf asegura que sólo se pase cadenas que contienen dígitos a la función de vista. </p>
<h3>Determinar contra qué busca la URLConf</h3>
<p>Cuando una petición llega, Django intenta hacer coincidir los patrones de la URLConf contra la URL solicitada, como una cadena de Python. Esto no incluye los parámetros GET o POST, o el nombre de dominio. Tampoco incluye la barra principal, ya que cada dirección tiene una barra principal. Por ejemplo, en una solicitud de http://www.example.com/myapp/, Django tratará de satisfacer myapp/. En una solicitud de http://www.example.com/myapp/?page=3, Django tratará de satisfacer myapp/.</p>
<p>El método de petición (por ejemplo, POST, GET) no se tiene en cuenta a la hora de tratar con el URLconf. En otras palabras, todos los métodos de petición serán enviados a la misma función para la misma URL. Es la responsabilidad de una función de vista llevar a cabo la ramificación basada en el método de la solicitud. </p>
<h3>Abstracciones de alto nivel de las funciones de vista</h3>
<p>Hablando de ramificación basada en el método de la petición, vamos a echar un vistazo a cómo podríamos construir una buena manera de hacerlo. Considerar este diseño URLconf/Vista:</p>
<blockquote><p>
# urls.py<br />
from django.conf.urls.defaults import *<br />
from mysite import views<br />
urlpatterns = patterns(&#8221;,</p>
<p style="padding-left:30px"># &#8230;<br />
	(r&#8217;^somepage/$&#8217;, views.some_page),<br />
	# &#8230;</p>
<p>)</p>
<p># views.py<br />
from django.http import Http404, HttpResponseRedirect<br />
from django.shortcuts import render_to_response<br />
def some_page(request):</p>
<p style="padding-left:30px">if request.method == &#8216;POST&#8217;:</p>
<p style="padding-left:60px">do_something_for_post()<br />
		return HttpResponseRedirect(&#8216;/someurl/&#8217;)</p>
<p style="padding-left:30px">elif request.method == &#8216;GET&#8217;:</p>
<p style="padding-left:60px">do_something_for_get()<br />
		return render_to_response(&#8216;page.html&#8217;)</p>
<p style="padding-left:30px">else:</p>
<p style="padding-left:60px">raise Http404()</p>
</blockquote>
<p>En este ejemplo, el manejo de la vista some_page() de las peticiones POST y GET es muy diferente.</p>
<p>Lo único que tienen en común es una URL compartida URL: /somepage/. Como tal, es una falta de elegancia hacer frente tanto a POST y GET en la misma función de vista. Sería bueno si pudiéramos tener dos funciones de vista separadas – una que gestione las peticiones GET y otra que gestione las POST &#8211; y garantizar que cada una se invoque sólo cuando sea necesario.</p>
<p>Podemos hacer eso escribiendo una función de vista que delege a otras vistas, ya sea antes o después de ejecutar alguna lógica personalizada. He aquí un ejemplo de cómo esta técnica podría ayudar a simplificar nuestra vista some_page(): </p>
<blockquote><p>
# views.py<br />
from django.http import Http404, HttpResponseRedirect<br />
from django.shortcuts import render_to_response</p>
<p>def method_splitter(request, GET=None, POST=None):</p>
<p style="padding-left:30px">if request.method == &#8216;GET&#8217; and GET is not None:</p>
<p style="padding-left:60px">return GET(request)</p>
<p style="padding-left:30px">elif request.method == &#8216;POST&#8217; and POST is not None:</p>
<p style="padding-left:60px">return POST(request)</p>
<p style="padding-left:30px">raise Http404</p>
<p>def some_page_get(request):</p>
<p style="padding-left:30px">assert request.method == &#8216;GET&#8217;<br />
	do_something_for_get()<br />
	return render_to_response(&#8216;page.html&#8217;)</p>
<p>def some_page_post(request):</p>
<p style="padding-left:30px">assert request.method == &#8216;POST&#8217;<br />
	do_something_for_post()<br />
	return HttpResponseRedirect(&#8216;/someurl/&#8217;)</p>
<p># urls.py<br />
from django.conf.urls.defaults import *<br />
from mysite import views</p>
<p>urlpatterns = patterns(&#8221;,</p>
<p style="padding-left:30px"># &#8230;<br />
	(r&#8217;^somepage/$&#8217;, views.method_splitter, {&#8216;GET&#8217;: views.some_page_get, &#8216;POST&#8217;: views.some_page_post}),<br />
	# &#8230;</p>
<p>)
</p></blockquote>
<p>Veamos que hace esto:</p>
<ul>
<li>Escribimos una nueva vista, method_splitter(), que delega a otras vistas según request.method. Busca dos argumentos de palabra clave, GET y POST, que deben ser funciones de vista. Si  request.method es &#8216;GET&#8217;, llama a la vista GET. Si request.method es &#8220;POST&#8221;, llama a la vista POST. Si request.method es otra cosa (HEAD, etc), o si GET o POST no fueron suministrados a la función, se eleva un Http404.</li>
<li>En el URLconf, apuntamos /somepage/ al method_splitter() y le pasarmos argumentos extra – las funciones para el uso de GET y POST, respectivamente.</li>
<li>Por último, dividimos la vista some_page() vista en dos funciones de vista: some_page_get() y some_page_post (). Esto es mucho mejor que colocar toda la lógica en una sola vista.</li>
</ul>
<p>Ahora tenemos una bonita función de vista genérica que encapsula la lógica de delegar una vista mediante request.method. Nada de method_splitter() está ligado a nuestra aplicación específica, por supuesto, asi que podemos reutilizarla en otros proyectos.</p>
<p>Pero hay una forma de mejorar el method_splitter(). Ahora, se asume que las vistas GET y POST no toman otros argumentos que request. ¿Qué pasa si se quiere utilizar method_splitter() con vistas que, por ejemplo, capturen texto de URLs o tomen argumentos de palabra clave opcionales?</p>
<p>Para ello, podemos usar una característica agradable de Python: argumentos variables con asteriscos. Vamos a mostrar el ejemplo primero y luego explicarlo: </p>
<blockquote><p>
def method_splitter(request, *args, **kwargs):</p>
<p style="padding-left:30px">get_view = kwargs.pop(&#8216;GET&#8217;, None)<br />
	post_view = kwargs.pop(&#8216;POST&#8217;, None)<br />
	if request.method == &#8216;GET&#8217; and get_view is not None:</p>
<p style="padding-left:60px">return get_view(request, *args, **kwargs)</p>
<p style="padding-left:30px">elif request.method == &#8216;POST&#8217; and post_view is not None:</p>
<p style="padding-left:60px">return post_view(request, *args, **kwargs)</p>
<p style="padding-left:30px">raise Http404</p>
</blockquote>
<p>Aquí, refactorizamos method_splitter() para eliminar los argumentos de palabra clave GET y POST en favor de *args y **kwargs. Esta es una característica Python que permite a una función aceptar un número arbitrario dinámico de argumentos cuyos nombres no se conocen hasta el tiempo de ejecución. Si coloca un asterisco delante de un parámetro en una definición de la función, cualquier argumento posicional a esa función se guarda en una sola tupla. Si coloca dos asteriscos delante de un parámetro en una definición de la función, cualquier argumento de palabras clave para esa función se guardará en un diccionario único.</p>
<p>Por ejemplo, tenga en cuenta esta función: </p>
<blockquote><p>
def foo(*args, **kwargs):</p>
<p style="padding-left:30px">print &#8220;Positional arguments are:&#8221;<br />
	print args<br />
	print &#8220;Keyword arguments are:&#8221;<br />
	print kwargs</p>
</blockquote>
<p>Así es como funcionaría:</p>
<blockquote><p>
&gt;&gt;&gt; foo(1, 2, 3)<br />
Positional arguments are:<br />
(1, 2, 3)<br />
Keyword arguments are:<br />
{}<br />
&gt;&gt;&gt; foo(1, 2, name=&#8217;Adrian&#8217;, framework=&#8217;Django&#8217;)<br />
Positional arguments are:<br />
(1, 2)<br />
Keyword arguments are:<br />
{&#8216;framework&#8217;: &#8216;Django&#8217;, &#8216;name&#8217;: &#8216;Adrian&#8217;}
</p></blockquote>
<p>Llevando esto a method_splitter(), se puede ver que estamos usando *args y **kwargs para aceptar argumentos a la función y distribuirlos a la vista apropiada. Pero antes de hacer eso, hacemos dos llamadas a kwargs.pop() para obtener los argumentos GET y POST, si están disponibles. (Estamos usando pop() con un valor por defecto None para evitar KeyError si alguno no está definido.) </p>
<h3>Envolviendo funciones de vista</h3>
<p>Nuestro truco de vista final se basa en una avanzada técnica de Python. Supongamos que se encuentre un montón de código repetitivo a través de diversas vistas, como en este ejemplo: </p>
<blockquote><p>
def my_view1(request):</p>
<p style="padding-left:30px">if not request.user.is_authenticated():</p>
<p style="padding-left:60px">return HttpResponseRedirect(&#8216;/accounts/login/&#8217;)</p>
<p style="padding-left:30px"># &#8230;<br />
	return render_to_response(&#8216;template1.html&#8217;)</p>
<p>def my_view2(request):</p>
<p style="padding-left:30px">if not request.user.is_authenticated():</p>
<p style="padding-left:60px">return HttpResponseRedirect(&#8216;/accounts/login/&#8217;)</p>
<p style="padding-left:30px"># &#8230;<br />
	return render_to_response(&#8216;template2.html&#8217;)</p>
<p>def my_view3(request):</p>
<p style="padding-left:30px">if not request.user.is_authenticated():</p>
<p style="padding-left:60px">return HttpResponseRedirect(&#8216;/accounts/login/&#8217;)</p>
<p style="padding-left:30px"># &#8230;<br />
	return render_to_response(&#8216;template3.html&#8217;)</p>
</blockquote>
<p>Aquí, cada vista comienza comprobando que request.user está autenticado, es decir, que el usuario se ha validado correctamente en el sitio web y sino lo redirige a /accounts/login/. </p>
<p>Sería bueno si pudiéramos eliminar ese trozo de código repetitivo de cada una de estas vistas y sólo  marcarlos como que requieren autenticación. Podemos hacer esto haciendo un envoltorio de la vista. Tome un momento para estudiar esto: </p>
<blockquote><p>
def requires_login(view):</p>
<p style="padding-left:30px">def new_view(request, *args, **kwargs):</p>
<p style="padding-left:60px">if not request.user.is_authenticated():</p>
<p style="padding-left:90px">return HttpResponseRedirect(&#8216;/accounts/login/&#8217;)</p>
<p style="padding-left:60px">return view(request, *args, **kwargs)</p>
<p style="padding-left:30px">return new_view</p>
</blockquote>
<p>Esta función, requires_login, toma una función de vista (view) y devuelve una nueva función de vista (new_view). La nueva función, new_view, se define dentro de requires_login y se encarga la lógica de controlar request.user.is_authenticated() y delegar a la vista original (view).</p>
<p>Ahora, podemos eliminar las comprobaciones if not request.user.is_authenticated() de nuestras vistas y simplemente envolverlas con requires_login en nuestra URLconf:</p>
<blockquote><p>
from django.conf.urls.defaults import *<br />
from mysite.views import requires_login, my_view1, my_view2, my_view3</p>
<p>urlpatterns = patterns(&#8221;,</p>
<p style="padding-left:30px">(r&#8217;^view1/$&#8217;, requires_login(my_view1)),<br />
	(r&#8217;^view2/$&#8217;, requires_login(my_view2)),<br />
	(r&#8217;^view3/$&#8217;, requires_login(my_view3)),</p>
<p>)
</p></blockquote>
<p>Esto tiene el mismo efecto que antes, pero con menos código redundante. Ahora hemos creado una buena función genérica &#8211; requires_login() que nos puede envolver cualquier vista para requerir un inicio de sesión. </p>
<h3>Incluir otras URLconfs</h3>
<p>Si desea que su código sea usado en varios sitios basados en Django, debe considerar la organización de sus URLconfs de tal manera que se puedan &#8220;incluir&#8221;.</p>
<p>De esta forma, su URLconf puede &#8220;incluir&#8221; otros módulos URLconf. Por ejemplo, esta URLconf incluye otros URLconfs: </p>
<blockquote><p>
from django.conf.urls.defaults import *</p>
<p>urlpatterns = patterns(&#8221;,</p>
<p style="padding-left:30px">(r&#8217;^weblog/&#8217;, include(&#8216;mysite.blog.urls&#8217;)),<br />
	(r&#8217;^photos/&#8217;, include(&#8216;mysite.photos.urls&#8217;)),<br />
	(r&#8217;^about/$&#8217;, &#8216;mysite.views.about&#8217;),</p>
<p>)
</p></blockquote>
<p>Hay un aspecto importante: las expresiones regulares en este ejemplo que apuntan a un include() no acaban en $, pero si una barra final. Cuando Django se encuentra con include(), corta parte de la URL concordante hasta ese punto y envía la cadena restante a la URLconf incluida para su posterior procesamiento. </p>
<p>Siguiendo este ejemplo, aquí está el URLconf mysite.blog.urls: </p>
<blockquote><p>
from django.conf.urls.defaults import *</p>
<p>urlpatterns = patterns(&#8221;,</p>
<p style="padding-left:30px">(r&#8217;^(\d\d\d\d)/$&#8217;, &#8216;mysite.blog.views.year_detail&#8217;),<br />
	(r&#8217;^(\d\d\d\d)/(\d\d)/$&#8217;, &#8216;mysite.blog.views.month_detail&#8217;),</p>
<p>)
</p></blockquote>
<p>Con estas dos URLconfs, aquí se muestra como se gestionarían algunas solicitudes:</p>
<ul>
<li>/weblog/2007/: En la primera URLconf, el patrón r&#8217;^weblog/&#8217; coincide. Debido a que es un include(), Django divide todo el texto coincidente, que es &#8216;weblog/&#8217; en este caso. La parte restante de la dirección es 2007/, que coincide con la primera línea en el URLconf mysite.blog.urls.</li>
<li>/weblog//2007/ (con dos barras inclinadas): En la primera URLconf, el patrón r&#8217;^weblog/&#8217; coincide. Debido a que es un include(), Django divide todo el texto coincidente, que es &#8216;weblog/&#8217; en este caso. La parte restante de la dirección es /2007/, que no coincide con ninguna de las líneas en el URLconf mysite.blog.urls.</li>
<li>/about/: Coincide con la vista mysite.views.about la primera URLconf, lo que demuestra que se pueden mezclar patrones include() con patrones no include. </li>
</ul>
<h3>Cómo trabajan con include() los parámetros capturados</h3>
<p>Un URLconf incluido recibe cualquier parámetro capturado del URLconf padre, por ejemplo:</p>
<blockquote><p>
# root urls.py<br />
from django.conf.urls.defaults import *</p>
<p>urlpatterns = patterns(&#8221;,</p>
<p style="padding-left:30px">(r&#8217;^(?P<username>\w+)/blog/&#8217;, include(&#8216;foo.urls.blog&#8217;)),</p>
<p>)</p>
<p># foo/urls/blog.py<br />
from django.conf.urls.defaults import *</p>
<p>urlpatterns = patterns(&#8221;,</p>
<p style="padding-left:30px">(r&#8217;^$&#8217;, &#8216;foo.views.blog_index&#8217;),<br />
	(r&#8217;^archive/$&#8217;, &#8216;foo.views.blog_archive&#8217;),</p>
<p>)
</p></blockquote>
<p>En este ejemplo, la variable username capturada se pasa al URLconf incluido y, por lo tanto, a cada función de vista dentro de ese URLconf.</p>
<p>Tenga en cuenta que los parámetros capturados siempre serán pasados a todas las líneas del URLconf incluido, independientemente de si la vista de la línea en realidad acepta esos parámetros como válidos. Por esta razón, esta técnica es útil sólo si estás seguro de que todas las vistas de la URLconf incluida aceptan los parámetros que está pasando. </p>
<h3>Cómo trabajan con include() las opciones URLconf extras</h3>
<p>Del mismo modo, se pueden pasar opciones adicionales URLconf a include(), tal como se pueden pasar opciones URLconf adicionales para una vista normal &#8211; como un diccionario. Al hacer esto, a cada línea de la URLconf incluida se le pasan las opciones extra.</p>
<p>Por ejemplo, los siguientes conjuntos URLconf son funcionalmente idénticos.</p>
<p>Conjunto uno: </p>
<blockquote<br />
# urls.py<br />
from django.conf.urls.defaults import *</p><p>urlpatterns = patterns('',
<p style="padding-left:30px">(r&#8217;^blog/&#8217;, include(&#8216;inner&#8217;), {&#8216;blogid&#8217;: 3}),</p>
<p>)</p>
<p># inner.py<br />
from django.conf.urls.defaults import *</p>
<p>urlpatterns = patterns(&#8221;,</p>
<p style="padding-left:30px">(r&#8217;^archive/$&#8217;, &#8216;mysite.views.archive&#8217;),<br />
	(r&#8217;^about/$&#8217;, &#8216;mysite.views.about&#8217;),<br />
	(r&#8217;^rss/$&#8217;, &#8216;mysite.views.rss&#8217;),</p>
<p>)
</p></blockquote>
<p>Conjunto dos:</p>
<blockquote><p>
# urls.py<br />
from django.conf.urls.defaults import *</p>
<p>urlpatterns = patterns(&#8221;,</p>
<p style="padding-left:30px">(r&#8217;^blog/&#8217;, include(&#8216;inner&#8217;)),</p>
<p>)</p>
<p># inner.py<br />
from django.conf.urls.defaults import *</p>
<p>urlpatterns = patterns(&#8221;,</p>
<p style="padding-left:30px">(r&#8217;^archive/$&#8217;, &#8216;mysite.views.archive&#8217;, {&#8216;blogid&#8217;: 3}),<br />
	(r&#8217;^about/$&#8217;, &#8216;mysite.views.about&#8217;, {&#8216;blogid&#8217;: 3}),<br />
	(r&#8217;^rss/$&#8217;, &#8216;mysite.views.rss&#8217;, {&#8216;blogid&#8217;: 3}),</p>
<p>)
</p></blockquote>
<p>Como es el caso de los parámetros capturados, las opciones adicionales siempre se pasarán a todas las líneas del URLconf incluido, independientemente de si la vista de la línea acepta esas opciones como válidas. Por esta razón, esta técnica es útil sólo si tiene la certeza de que todas las vistas incluidas en la URLconf aceptan las opciones extra que está pasando. </p>
<h3>Enlaces Relacionados:</h3>
<ul>
<li><a href="http://www.cibernatural.com/tutorial-de-django-i">Tutorial de Django I</a></li>
<li><a href="http://www.cibernatural.com/tutorial-de-django-ii">Tutorial de Django II</a></li>
<li><a href="http://www.cibernatural.com/tutorial-de-django-iii">Tutorial de Django III</a></li>
<li><a href="http://www.cibernatural.com/tutorial-de-django-iv">Tutorial de Django IV</a></li>
<li><a href="http://www.cibernatural.com/tutorial-de-django-v">Tutorial de Django V</a></li>
<li><a href="http://www.cibernatural.com/tutorial-de-django-vi">Tutorial de Django VI</a></li>
<li>Tutorial de Django VII</li>
</ul>

                            <div id="aspdf">
                                <a href="http://www.cibernatural.com/wp-content/plugins/as-pdf/generate.php?post=678">
                                    <span>Descargar en PDF</span>
                                </a>
                            </div>
                        ]]></content:encoded>
			<wfw:commentRss>http://www.cibernatural.com/tutorial-de-django-vii/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Gestión web de clientes y facturación en Django</title>
		<link>http://www.cibernatural.com/gestion-web-de-clientes-y-facturacion-en-django/</link>
		<comments>http://www.cibernatural.com/gestion-web-de-clientes-y-facturacion-en-django/#comments</comments>
		<pubDate>Fri, 16 Jul 2010 16:33:00 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Destacado]]></category>
		<category><![CDATA[Software de Gestión]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[Facturación]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[ReportLab]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://www.cibernatural.com/?p=656</guid>
		<description><![CDATA[Cibernatural S.L. estrena una nueva y sencilla aplicación web de Gestión de clientes y facturas, presupuestos, partes de entrega y abonos, desarrollada completamente a partir del Sitio de Administración de Django, que proporciona una interfaz limpia y eficiente. Con ella, se puede gestionar una empresa fácilmente en cualquier momento, lugar y desde cualquier dispositivo que [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.cibernatural.com">Cibernatural S.L.</a> estrena una nueva y sencilla <strong>aplicación web de Gestión de clientes y facturas</strong>, presupuestos, partes de entrega y abonos, desarrollada completamente a partir del Sitio de Administración de <strong>Django</strong>, que proporciona una interfaz limpia y eficiente.</p>
<p>Con ella, se puede gestionar una empresa fácilmente en cualquier momento, lugar y desde cualquier dispositivo que disponga de un navegador e Internet (ordenador, portátil, teléfono móvil, etc.), sin necesidad de ninguna instalación,  etc.</p>
<p>La aplicación permite la búsqueda y edición de cualquier cliente, factura, presupuesto, etc., de forma rápida y sencilla, así como la generación en PDF de cualquiera de estos elementos personalizados para la empresa usuaria de la aplicación. Además, permite realizar varias tareas con un solo click, como volcar un presupuesto en una factura, etc., y proporciona multitud de listados estadísticos en PDF como por ejemplo, resúmenes de facturación por meses, por trimestres, por años, por clientes, etc.</p>
<p>Muchas empresas ya están utilizando esta aplicación, que pretende simplificar la facturación de la empresa y llevarla a la &#8220;nube&#8221; para gestionar su empresa cuándo y donde quiera.</p>
<h3>Enlaces Relacionados</h3>
<ul>
<li><a href="http://www.cibernatural.com/demo-online-del-programa-de-gestion-web-en-django/">Demo Online del Programa de Gestión Web en Django</a></li>
</ul>

                            <div id="aspdf">
                                <a href="http://www.cibernatural.com/wp-content/plugins/as-pdf/generate.php?post=656">
                                    <span>Descargar en PDF</span>
                                </a>
                            </div>
                        ]]></content:encoded>
			<wfw:commentRss>http://www.cibernatural.com/gestion-web-de-clientes-y-facturacion-en-django/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Tutorial de Django – VI</title>
		<link>http://www.cibernatural.com/tutorial-de-django-vi/</link>
		<comments>http://www.cibernatural.com/tutorial-de-django-vi/#comments</comments>
		<pubDate>Fri, 16 Jul 2010 12:35:28 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Guía Django]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://www.cibernatural.com/?p=640</guid>
		<description><![CDATA[Formularios Los formularios HTML son la columna vertebral de sitios Web interactivos. Este capítulo comprende cómo se puede utilizar Django para acceder a los datos de formulario emitidos por el usuario, validarlos, y hacer algo con ellos. En el camino, cubriremos los objetos HttpRequest y Form. Obtener datos del objeto Request Los objetos HttpRequest, tienen una serie [...]]]></description>
			<content:encoded><![CDATA[<h2><strong><span style="text-decoration: underline;">Formularios</span></strong></h2>
<p>Los formularios HTML son la columna vertebral de sitios Web interactivos. Este capítulo comprende cómo se puede utilizar Django para acceder a los datos de formulario emitidos por el usuario, validarlos, y hacer algo con ellos. En el camino, cubriremos los objetos HttpRequest y Form.</p>
<h3>Obtener datos del objeto Request</h3>
<p>Los objetos HttpRequest, tienen una serie de atributos y de métodos que son interesantes y debería familiarizarse con ellos para saber lo que es posible hacer con ellos.</p>
<p>Puede usar estos atributos para obtener información acerca de la petición actual (por ejemplo el usuario / navegador web que está cargando la página actual en su sitio Django) en el momento en que se ejecuta la la función de la vista.<br />
<span id="more-640"></span></p>
<h3>Información sobre la URL</h3>
<p>Los objetos HttpRequest contienen varias piezas de información sobre la URL solicitada actualmente:</p>
<p>Usar siempre los atributos / métodos en lugar de codificar las direcciones URL en sus vista. Esto hace que el código sea más flexible y que pueda ser reutilizado en otros lugares. He aquí un simple ejemplo: </p>
<blockquote><p>
# BAD!<br />
def current_url_view_bad(request):</p>
<p style="padding-left:30px">	return HttpResponse(&#8220;Welcome to the page at /current/&#8221;)</p>
<p># GOOD<br />
def current_url_view_good(request):</p>
<p style="padding-left:30px">	return HttpResponse(&#8220;Welcome to the page at %s&#8221; % request.path)</p></blockquote>
<h3>Otra información sobre la petición</h3>
<p>request.META es un diccionario Python que contiene todas las cabeceras HTTP disponibles para la solicitud dada, incluyendo la dirección IP del usuario y el agente de usuario (generalmente el nombre y la versión del navegador Web).  Las siguientes son algunas claves comunes en este diccionario:</p>
<ul>
<li>HTTP_REFERER: La URL de referencia, si la hubiese.</li>
<li>HTTP_USER_AGENT: La cadena de agente de usuario (si existe) del navegador del usuario. Esto se parecerá a algo como lo siguiente: &#8220;Mozilla 5.0 (X11; U; Linux i686) Gecko/20080829 Firefox/2.0.0.17&#8243;</li>
<li>REMOTE_ADDR: La dirección IP del cliente.</li>
</ul>
<p>Usted debe usar una cláusula try / except, o un método get() para manejar el caso de claves indefinidas, como en este ejemplo:</p>
<blockquote><p># BAD!<br />
def ua_display_bad(request):</p>
<p style="padding-left:30px">	ua = request.META['HTTP_USER_AGENT'] # Might raise KeyError!<br />
	return HttpResponse(&#8220;Your browser is %s&#8221; % ua)</p>
<p># GOOD (VERSION 1)<br />
def ua_display_good1(request):</p>
<p style="padding-left:30px">	try:</p>
<p style="padding-left:60px">	ua = request.META['HTTP_USER_AGENT']</p>
<p style="padding-left:30px">	except KeyError:</p>
<p style="padding-left:60px">	ua = &#8216;unknown&#8217;</p>
<p style="padding-left:30px">	return HttpResponse(&#8220;Your browser is %s&#8221; % ua)</p>
<p># GOOD (VERSION 2)<br />
def ua_display_good2(request):</p>
<p style="padding-left:30px">	ua = request.META.get(&#8216;HTTP_USER_AGENT&#8217;, &#8216;unknown&#8217;)<br />
	return HttpResponse(&#8220;Your browser is %s&#8221; % ua)</p>
</blockquote>
<p>Le animamos a escribir una pequeña vista que muestra todos los datos de request.META para que pueda conocer lo que está disponible. Se podría parecer a esto:</p>
<blockquote><p>def display_meta(request):</p>
<p style="padding-left:30px">	values = request.META.items()<br />
	values.sort()<br />
	html = []<br />
	for k, v in values:</p>
<p style="padding-left:60px">	html.append(&#8216;&lt;tr&gt;&lt;td&gt;%s&lt;/td&gt;&lt;td&gt;%s&lt;/td&gt;&lt;/tr&gt;&#8217; % (k, v))</p>
<p style="padding-left:30px">	return HttpResponse(&#8216;&lt;table&gt;%s&lt;/table&gt;&#8217; % &#8216;\n&#8217;.join(html))</p>
</blockquote>
<h3>Información sobre datos emitidos</h3>
<p>Más allá de los metadatos básicos acerca de la solicitud, los objetos HttpRequest tienen dos atributos que contienen la información que envía el usuario: request.GET y request.POST. Ambas son objetos como diccionarios que le dan acceso a los datos GET y POST.</p>
<p>Los datos POST generalmente son emitidos desde un formulario HTML, mientras que los datos GET pueden provenir de un formulario o del querystring de la URL de la página.</p>
<h3>Un ejemplo simple de gestión de formulario</h3>
<p>Creemos una vista simple que permita a los usuarios buscar en nuestra base de datos de libros por el título.</p>
<p>En general, hay dos partes para el desarrollo de un formulario: la interfaz de usuario HTML y el código de la vista que procesa los datos presentados. La primera parte es fácil, vamos a crear una vista que muestre un formulario de búsqueda:</p>
<blockquote><p>from django.shortcuts import render_to_response</p>
<p>def search_form(request):</p>
<p style="padding-left:30px">	return render_to_response(&#8216;search_form.html&#8217;)</p>
</blockquote>
<p>Esta vista puede residir en cualquier parte de su ruta de acceso Python. Para este ejemplo, colocarla en <em>books/views.py</em>.</p>
<p>La plantilla de acompañamiento, <em>search_form.html</em>, podría tener este aspecto: </p>
<blockquote><p>
&lt;html&gt;<br />
&lt;head&gt;</p>
<p style="padding-left:30px">&lt;title&gt;Search&lt;/title&gt;</p>
<p>&lt;/head&gt;<br />
&lt;body&gt;</p>
<p style="padding-left:30px">&lt;form action=&#8221;/search/&#8221; method=&#8221;get&#8221;&gt;</p>
<p style="padding-left:60px">&lt;input type=&#8221;text&#8221; name=&#8221;q&#8221;&gt;<br />
		&lt;input type=&#8221;submit&#8221; value=&#8221;Search&#8221;&gt;</p>
<p style="padding-left:30px">&lt;/form&gt;</p>
<p>&lt;/body&gt;<br />
&lt;/html&gt;</p></blockquote>
<p>El patrón URL en <em>urls.py</em> podría ser algo como esto:</p>
<blockquote><p>urlpatterns = patterns(&#8221;,</p>
<p style="padding-left:30px">	# &#8230;<br />
	(r&#8217;^search-form/$&#8217;, views.search_form),<br />
	# &#8230;</p>
<p>)</p></blockquote>
<p>Ahora, si ejecuta el runserver y visita <strong>http://127.0.0.1:8000/search-form/</strong>, verá la interfaz de búsqueda. Bastante simple.</p>
<p>Intente emitir el formulario, sin embargo, y obtendrá un error 404 de Django. El formulario apunta a la URL /search/, que aún no ha sido implementada. Vamos a arreglar eso con una segunda función de vista:</p>
<blockquote><p># urls.py<br />
urlpatterns = patterns(&#8221;,</p>
<p style="padding-left:30px"># &#8230;<br />
	(r&#8217;^search-form/$&#8217;, views.search_form),<br />
	(r&#8217;^search/$&#8217;, views.search),<br />
	# &#8230;</p>
<p>)</p></blockquote>
<blockquote><p># views.py<br />
def search(request):</p>
<p style="padding-left:30px">if &#8216;q&#8217; in request.GET:</p>
<p style="padding-left:60px">message = &#8216;You searched for: %r&#8217; % request.GET['q']</p>
<p style="padding-left:30px">else:</p>
<p style="padding-left:60px">message = &#8216;You submitted an empty form.&#8217;</p>
<p style="padding-left:30px">return HttpResponse(message)</p>
</blockquote>
<p>Por el momento, esto sólo muestra el término de búsqueda del usuario de modo que pueda asegurarse que los datos se presentan a Django correctamente y para que pueda tener una idea de cómo los términos de la búsqueda fluyen a través del sistema. En resumen, esto es lo que sucede:</p>
<ol>
<li>El formulario HTML define una variable q. Cuando se emite, el valor de q se envía a través de GET (method = &#8220;get&#8221;) a la URL /search/.</li>
<li>La vista Django que se encarga de la dirección /search/ tiene acceso al valor de q en request.GET.</li>
</ol>
<p>Tenga en cuenta que comprobamos explícitamente que &#8216;q&#8217; existe en request.GET. Como hemos señalado, usted no debe confiar en nada presentado por los usuarios. Si no ha añadido esta verificación, cualquier emisión de un formulario vacío lanzaría KeyError en la vista:</p>
<blockquote><p># BAD!<br />
def bad_search(request):</p>
<p style="padding-left:30px"># The following line will raise KeyError if &#8216;q&#8217; hasn&#8217;t<br />
	# been submitted!<br />
	message = &#8216;You searched for: %r&#8217; % request.GET['q']<br />
	return HttpResponse(message)</p>
</blockquote>
<p>Los datos POST funcionan de la misma manera que los datos GET. ¿Cuál es la diferencia entre GET y POST?  Utilice GET cuando el acto de emitir el formulario es sólo una solicitud para &#8220;obtener&#8221; datos. Utilice POST siempre que el acto de emitir el formulario tenga algunos efectos secundarios de actualización de datos o enviar un e-mail, o algo más de la simple exhibición de los datos.  En nuestro ejemplo de búsqueda de libro, estamos utilizando GET porque la consulta no cambia ningún dato en nuestro servidor. Ahora que hemos verificado que request.GET se está pasando correctamente, vamos a conectar la consulta de búsqueda del usuario con nuestra base de datos de libros (de nuevo, en <em>views.py</em>):</p>
<blockquote><p>from django.http import HttpResponse<br />
from django.shortcuts import render_to_response<br />
from mysite.books.models import Book</p>
<p>def search(request):</p>
<p style="padding-left:30px">if &#8216;q&#8217; in request.GET and request.GET['q']:</p>
<p style="padding-left:60px">q = request.GET['q']<br />
		books = Book.objects.filter(title__icontains=q)<br />
		return render_to_response(&#8216;search_results.html&#8217;, {&#8216;books&#8217;: books, &#8216;query&#8217;: q})</p>
<p style="padding-left:30px">else:</p>
<p style="padding-left:60px">return HttpResponse(&#8216;Please submit a search term.&#8217;)</p>
</blockquote>
<p>El código de la plantilla  <em>search_results.html</em> podría ser algo como esto:</p>
<blockquote><p>
&lt;p&gt;You searched for: &lt;strong&gt;{{ query }}&lt;/strong&gt;&lt;/p&gt;</p>
<p>{% if books %}</p>
<p style="padding-left:30px">&lt;p&gt;Found {{ books|length }} book{{ books|pluralize }}.&lt;/p&gt;<br />
	&lt;ul&gt;</p>
<p style="padding-left:60px">{% for book in books %}<br />
		&lt;li&gt;{{ book.title }}&lt;/li&gt;<br />
		{% endfor %}</p>
<p style="padding-left:30px">&lt;/ul&gt;</p>
<p>{% else %}</p>
<p style="padding-left:30px">&lt;p&gt;No books matched your search criteria.&lt;/p&gt;</p>
<p>{% endif %}
</p></blockquote>
<h3>Mejorar nuestro ejemplo de gestión de formulario simple</h3>
<p>En primer lugar, nuestra gestión de la vista search() de una consulta vacía es pobre &#8211; estamos mostrando solo un mensaje &#8220;Por favor, envíe un término de búsqueda&#8221;, que requiere que el usuario pulse el botón Atrás del navegador. Esto es horrible y poco profesional.</p>
<p>Sería mucho mejor volver a mostrar el formulario, con un error sobre él, de modo que el usuario pueda volver a intentarlo inmediatamente. La forma más sencilla de hacerlo sería la de renderizar la plantilla de nuevo, de esta forma:</p>
<blockquote><p>from django.http import HttpResponse<br />
from django.shortcuts import render_to_response<br />
from mysite.books.models import Book</p>
<p>def search_form(request):</p>
<p style="padding-left:30px">return render_to_response(&#8216;search_form.html&#8217;)</p>
<p>def search(request):</p>
<p style="padding-left:30px">if &#8216;q&#8217; in request.GET and request.GET['q']:</p>
<p style="padding-left:60px">q = request.GET['q']<br />
		books = Book.objects.filter(title__icontains=q)<br />
		return render_to_response(&#8216;search_results.html&#8217;, {&#8216;books&#8217;: books, &#8216;query&#8217;: q})</p>
<p style="padding-left:30px">else:</p>
<p style="padding-left:60px">return render_to_response(&#8216;search_form.html&#8217;, {&#8216;error&#8217;: True})</p>
</blockquote>
<p>Hemos mejorado search() renderizando la plantilla search_form.html de nuevo, si la consulta está vacía. Y ya que tenemos que mostrar un mensaje de error en esa plantilla, pasamos una variable de plantilla. Ahora podemos editar search_form.html para comprobar la variable de error:</p>
<blockquote><p>
&lt;html&gt;<br />
&lt;head&gt;</p>
<p style="padding-left:30px">&lt;title&gt;Search&lt;/title&gt;</p>
<p>&lt;/head&gt;<br />
&lt;body&gt;</p>
<p style="padding-left:30px">{% if error %}<br />
	&lt;p style=&#8221;color: red;&#8221;&gt;Please submit a search term.&lt;/p&gt;<br />
	{% endif %}<br />
	&lt;form action=&#8221;/search/&#8221; method=&#8221;get&#8221;&gt;</p>
<p style="padding-left:60px">&lt;input type=&#8221;text&#8221; name=&#8221;q&#8221;&gt;<br />
		&lt;input type=&#8221;submit&#8221; value=&#8221;Search&#8221;&gt;</p>
<p style="padding-left:30px">&lt;/form&gt;</p>
<p>&lt;/body&gt;<br />
&lt;/html&gt;
</p></blockquote>
<p>Todavía podemos utilizar esta plantilla desde nuestra vista original, search_form(), ya que search_form() no pasa el error a la plantilla &#8211; el mensaje de error no se mostrará en ese caso.</p>
<p>Con este cambio es una aplicación mejor, pero ahora surge la pregunta: ¿es una vista search_form() dedicada realmente necesaria? Tal como está, una solicitud a la dirección URL /search/ (sin los parámetros GET) mostrará el formulario vacío (pero con un error). Podemos eliminar la vista search_form(), junto con su patrón URL asociado, siempre y cuando cambiemos search() para ocultar el mensaje de error cuando alguien visite /search/ sin parámetros GET:</p>
<blockquote><p>def search(request):</p>
<p style="padding-left:30px">error = False<br />
	if &#8216;q&#8217; in request.GET:</p>
<p style="padding-left:60px">q = request.GET['q']<br />
		if not q:</p>
<p style="padding-left:90px">error = True</p>
<p style="padding-left:60px">else:</p>
<p style="padding-left:90px">books = Book.objects.filter(title__icontains=q)<br />
			return render_to_response(&#8216;search_results.html&#8217;, {&#8216;books&#8217;: books, &#8216;query&#8217;: q})</p>
<p style="padding-left:30px">return render_to_response(&#8216;search_form.html&#8217;, {&#8216;error&#8217;: error})</p>
</blockquote>
<p>En esta vista actualizada, si un usuario visita /search/ sin parámetros GET, verá el formulario de búsqueda sin mensaje de error. Si un usuario envía el formulario con un valor vacío para &#8216;q&#8217;, verá el formulario de búsqueda con un mensaje de error. Y, por último, si un usuario envía el formulario con un valor no vacío de &#8216;q&#8217;, verá los resultados de búsqueda.</p>
<p>Podemos hacer una mejora final a esta aplicación, para quitar un poco de redundancia. Ahora que hemos mezclado las dos vistas y URLs en una sola y /search/ maneja tanto la pantalla del formulario de búsqueda como la del resultado, el formulario HTML en <em>search_form.html</em> no tiene que codificar una URL a pelo. En lugar de esto:</p>
<blockquote><form action="/search/" method="get"></blockquote>
<p>puede cambiarse a:</p>
<blockquote><form action="" method="get"></blockquote>
<p>El action = &#8220;&#8221; significa &#8220;Enviar el formulario a la misma URL que la página actual.&#8221; Con este cambio, usted no tendrá que acordarse de cambiar la acción, incluso si alguna vez la vista search() apunta a otra URL.</p>
<h3>Validación simple</h3>
<p>Nuestro ejemplo de búsqueda es todavía bastante simple, especialmente en términos de validación de sus datos, hacemos una mera comprobación para asegurar que la consulta de búsqueda no está vacía. Muchos de los formularios HTML incluyen un nivel de validación que es más complejo que asegurar que el valor no está vacío. Todos hemos visto la siguientes mensajes de error en los sitios Web:<br />
&#8220;Por favor introduzca una dirección de correo electrónico&#8221;.<br />
&#8220;Por favor, introduzca un código postal de cinco dígitos válido EE.UU.&#8221;<br />
&#8220;Por favor, introduzca una fecha válida con formato AAAA-MM-DD&#8221;.<br />
&#8220;Por favor, introduzca una contraseña que sea por lo menos de 8 caracteres de longitud y contenga al menos un número&#8221;. </p>
<p>Vamos a afinar la vista search() para validar que el término de búsqueda sea menor o igual a 20 caracteres de largo. ¿Cómo podemos hacerlo? Lo más sencillo sería integrar la lógica directamente en la vista, así:</p>
<blockquote><p>def search(request):</p>
<p style="padding-left:30px">error = False<br />
	if &#8216;q&#8217; in request.GET:</p>
<p style="padding-left:60px">q = request.GET['q']<br />
		if not q:</p>
<p style="padding-left:90px">error = True</p>
<p style="padding-left:60px">elif len(q) > 20:</p>
<p style="padding-left:90px">error = True</p>
<p style="padding-left:60px">else:</p>
<p style="padding-left:90px">books = Book.objects.filter(title__icontains=q)<br />
			return render_to_response(&#8216;search_results.html&#8217;,{&#8216;books&#8217;: books, &#8216;query&#8217;: q})</p>
<p style="padding-left:30px">	return render_to_response(&#8216;search_form.html&#8217;, {&#8216;error&#8217;: error})</p>
</blockquote>
<p>Ahora bien, si se intenta emitir una consulta de búsqueda mayor de 20 caracteres de largo, obtendrá un mensaje de error. Pero ese mensaje de error en <em>search_form.html</em> actualmente dice: &#8220;Por favor, introduzca un término de búsqueda.&#8221;, así que tendremos que cambiarlo para ser exactos en ambos casos (una búsqueda vacía o un término de búsqueda demasiado largo).</p>
<blockquote><p>
&lt;html&gt;<br />
&lt;head&gt;</p>
<p style="padding-left:30px">&lt;title&gt;Search&lt;/title&gt;<br />
&lt;/head&gt;<br />
&lt;body&gt;</p>
<p style="padding-left:30px">{% if error %}<br />
	&lt;p style=&#8221;color: red;&#8221;&gt;</p>
<p style="padding-left:60px">Please submit a search term<br />
		20 characters or shorter.</p>
<p style="padding-left:30px">&lt;/p&gt;<br />
	{% endif %}<br />
	&lt;form action=&#8221;/search/&#8221; method=&#8221;get&#8221;&gt;</p>
<p style="padding-left:60px">&lt;input type=&#8221;text&#8221; name=&#8221;q&#8221;&gt;<br />
		&lt;input type=&#8221;submit&#8221; value=&#8221;Search&#8221;&gt;</p>
<p style="padding-left:30px">&lt;/form&gt;</p>
<p>&lt;/body&gt;<br />
&lt;/html&gt;</p></blockquote>
<p>Hay algo mal en esto. Nuestro único mensaje de error es potencialmente confuso. ¿Por qué el mensaje de error para un valor vacío menciona nada sobre un límite de 20 caracteres? Los mensajes de error deben ser específicos y claros.</p>
<p>El problema es que estamos utilizando un solo valor boolean para el error, cuando habría que utilizar una lista de cadenas de mensajes de error. He aquí cómo podemos solucionarlo:</p>
<blockquote><p>def search(request):</p>
<p style="padding-left:30px">errors = []<br />
	if &#8216;q&#8217; in request.GET:</p>
<p style="padding-left:60px">q = request.GET['q']<br />
		if not q:</p>
<p style="padding-left:90px">errors.append(&#8216;Enter a search term.&#8217;)</p>
<p style="padding-left:60px">elif len(q) > 20:</p>
<p style="padding-left:90px">errors.append(&#8216;Please enter at most 20 characters.&#8217;)</p>
<p style="padding-left:60px">else:</p>
<p style="padding-left:90px">books = Book.objects.filter(title__icontains=q)<br />
			return render_to_response(&#8216;search_results.html&#8217;, {&#8216;books&#8217;: books, &#8216;query&#8217;: q})</p>
<p style="padding-left:30px">return render_to_response(&#8216;search_form.html&#8217;, {&#8216;errors&#8217;: errors})</p>
</blockquote>
<p>Entonces tenemos que hacer un pequeño ajuste en la plantilla <em>search_form.html</em> para reflejar que se pasó una lista de errores, en lugar de un error boolean: </p>
<blockquote><p>
&lt;html&gt;<br />
&lt;head&gt;</p>
<p style="padding-left:30px">&lt;title&gt;Search&lt;/title&gt;<br />
&lt;/head&gt;<br />
&lt;body&gt;</p>
<p style="padding-left:30px">{% if errors %}<br />
	&lt;ul&gt;</p>
<p style="padding-left:60px">{% for error in errors %}</p>
<p style="padding-left:90px">&lt;li&gt;{{ error }}&lt;/li&gt;</p>
<p style="padding-left:60px">{% endfor %}</p>
<p style="padding-left:30px">&lt;/ul&gt;<br />
	{% endif %}<br />
	&lt;form action=&#8221;/search/&#8221; method=&#8221;get&#8221;&gt;</p>
<p style="padding-left:60px">&lt;input type=&#8221;text&#8221; name=&#8221;q&#8221;&gt;<br />
		&lt;input type=&#8221;submit&#8221; value=&#8221;Search&#8221;&gt;</p>
<p style="padding-left:30px">&lt;/form&gt;</p>
<p>&lt;/body&gt;<br />
&lt;/html&gt;</p></blockquote>
<h3>Hacer un formulario de contacto</h3>
<p>Aunque hemos reiterado en el ejemplo del formulario de búsqueda de libros varias veces y lo hemos mejorado, sigue siendo muy sencillo: basta con un solo campo, &#8216;q&#8217;. Al ser tan simple, ni siquiera usamos la librería de formularios de Django para tratar con él. Pero las formas más complejas requieren tratamientos más complejos, y ahora vamos a desarrollar algo más complejo: un formulario de contacto de la web que permite a los usuarios del sitio envíar comentarios, junto con un e-mail de retorno. Después que el formulario es emitido y los datos son validados, automáticamente le enviaremos un mensaje por correo electrónico al personal del sitio.</p>
<p>Empezaremos con nuestra plantilla, <em>contact_form.html</em>:</p>
<blockquote><p>
&lt;html&gt;<br />
&lt;head&gt;</p>
<p style="padding-left:30px">&lt;title&gt;Contact us&lt;/title&gt;</p>
<p>&lt;/head&gt;<br />
&lt;body&gt;</p>
<p style="padding-left:30px">&lt;h1&gt;Contact us&lt;/h1&gt;<br />
	{% if errors %}<br />
	&lt;ul&gt;</p>
<p style="padding-left:60px">{% for error in errors %}<br />
		&lt;li&gt;{{ error }}&lt;/li&gt;<br />
		{% endfor %}</p>
<p style="padding-left:30px">&lt;/ul&gt;<br />
	{% endif %}</p>
<p>	&lt;form action=&#8221;/contact/&#8221; method=&#8221;post&#8221;&gt;</p>
<p style="padding-left:60px">&lt;p&gt;Subject: &lt;input type=&#8221;text&#8221; name=&#8221;subject&#8221;&gt;&lt;/p&gt;<br />
		&lt;p&gt;Your e-mail (optional): &lt;input type=&#8221;text&#8221; name=&#8221;e-mail&#8221;&gt;&lt;/p&gt;<br />
		&lt;p&gt;Message: &lt;textarea name=&#8221;message&#8221; rows=&#8221;10&#8243; cols=&#8221;50&#8243;&gt;&lt;/textarea&gt;&lt;/p&gt;<br />
		&lt;input type=&#8221;submit&#8221; value=&#8221;Submit&#8221;&gt;</p>
<p style="padding-left:30px">&lt;/form&gt;</p>
<p>&lt;/body&gt;<br />
&lt;/html&gt;
</p></blockquote>
<p>Hemos definido tres campos: el asunto, la dirección de correo electrónico y el mensaje. El segundo es opcional, pero los otros dos campos son obligatorios. Tenga en cuenta que estamos usando method = &#8220;post&#8221; aquí en lugar de method = &#8220;get&#8221; ya que este formulario de emisión tiene un efecto secundario &#8211; que envía un e-mail. Si seguimos el camino establecido por nuestra vista search() de la sección anterior, una versión de nuestra vista contact() podría tener este aspecto:</p>
<blockquote><p>from django.core.mail import send_mail<br />
from django.http import HttpResponseRedirect<br />
from django.shortcuts import render_to_response</p>
<p>def contact(request):</p>
<p style="padding-left:30px">errors = []<br />
	if request.method == &#8216;POST&#8217;:</p>
<p style="padding-left:60px">if not request.POST.get(&#8216;subject&#8217;, &#8221;):</p>
<p style="padding-left:90px">errors.append(&#8216;Enter a subject.&#8217;)</p>
<p style="padding-left:60px">if not request.POST.get(&#8216;message&#8217;, &#8221;):</p>
<p style="padding-left:90px">errors.append(&#8216;Enter a message.&#8217;)</p>
<p style="padding-left:60px">if request.POST.get(&#8216;e-mail&#8217;) and &#8216;@&#8217; not in request.POST['e-mail']:</p>
<p style="padding-left:90px">errors.append(&#8216;Enter a valid e-mail address.&#8217;)</p>
<p style="padding-left:60px">if not errors:</p>
<p style="padding-left:90px">send_mail(request.POST['subject'], request.POST['message'],<br />
					request.POST.get(&#8216;e-mail&#8217;, &#8216;noreply@example.com&#8217;),<br />
					['siteowner@example.com'],</p>
<p style="padding-left:60px">)<br />
			return HttpResponseRedirect(&#8216;/contact/thanks/&#8217;)</p>
<p style="padding-left:30px">return render_to_response(&#8216;contact_form.html&#8217;,{&#8216;errors&#8217;: errors})</p>
</blockquote>
<p>Varias cosas nuevas están sucediendo aquí:</p>
<ul>
<li>Comprobamos que request.method es &#8216;POST&#8217;. Esto será cierto sólo en el caso de una emisión del formulario, no será cierto si alguien está solamente viendo el formulario de contacto. Esto hace que sea una buena forma de aislar el caso de &#8220;pantalla del formulario&#8221; del caso de&#8221;transformación del formulario&#8221;.</li>
<li>En lugar de request.GET, estamos usando request.POST para acceder a los datos del formulario emitido. Esto es necesario porque el código de contact_form.html usa method = &#8220;post&#8221;.</li>
<li>Contamos con dos campos obligatorios, asunto y mensaje, así que tenemos que validar ambos. Notar que estamos utilizando request.POST.get() y proporcionando una cadena en blanco como el valor por defecto.</li>
<li>Aunque el campo de correo electrónico no es obligatorio, debemos aún validarlo si es emitido. Nuestro algoritmo de validación aquí es frágil &#8211; estamos comprobando que la cadena contiene un carácter @. En el mundo real, necesitaríamos una validación más robusta.</li>
<li>Estamos usando la función django.core.mail.send_mail para enviar un e-mail. Esta función tiene cuatro argumentos necesarios: el asunto del e-mail, el cuerpo del correo electrónico, la dirección del emisor, y una lista de direcciones de los destinatarios. send_mail está contenida en la clase de Django E-mailMessage, que proporciona características avanzadas tales como archivos adjuntos, emails multiplart, y el control total de los encabezados del correo electrónico. </li>
<li>Después de enviar el e-mail, redirigimos a una página de &#8220;éxito&#8221; devolviendo un objeto HttpResponseRedirect. Usted siempre debe enviar una redirección para el éxito de las peticiones POST. Es una de las mejores prácticas del desarrollo web.</li>
</ul>
<p>Esto vista funciona, pero las funciones de validación son enrevesadas. Imagine la tramitación de un formulario con una docena de campos, ¿de verdad quieres tener que escribir todas esas sentencias if?</p>
<p>Otro problema es volver a mostrar el formulario. En el caso de errores de validación, es mejor práctica volver a mostrar el formulario con los datos presentados anteriormente ya rellenados para que el usuario puede ver lo que hizo mal (y no tener que volver a introducir los datos en los campos que ha emitido correctamente). Nosotros manualmente podríamos pasar los datos POST de nuevo a la plantilla, pero habría que editar cada campo HTML para insertar el valor adecuado en el lugar adecuado: </p>
<blockquote><p># views.py<br />
def contact(request):</p>
<p style="padding-left:30px">errors = []<br />
	if request.method == &#8216;POST&#8217;:</p>
<p style="padding-left:60px">if not request.POST.get(&#8216;subject&#8217;, &#8221;):</p>
<p style="padding-left:90px">errors.append(&#8216;Enter a subject.&#8217;)</p>
<p style="padding-left:60px">if not request.POST.get(&#8216;message&#8217;, &#8221;):</p>
<p style="padding-left:90px">errors.append(&#8216;Enter a message.&#8217;)</p>
<p style="padding-left:60px">if request.POST.get(&#8216;e-mail&#8217;) and &#8216;@&#8217; not in request.POST['e-mail']:</p>
<p style="padding-left:90px">errors.append(&#8216;Enter a valid e-mail address.&#8217;)</p>
<p style="padding-left:60px">if not errors:</p>
<p style="padding-left:90px">send_mail(<br />
				request.POST['subject'],<br />
				request.POST['message'],<br />
				request.POST.get(&#8216;e-mail&#8217;, &#8216;noreply@example.com&#8217;),<br />
				['siteowner@example.com'],<br />
			)</p>
<p style="padding-left:60px">return HttpResponseRedirect(&#8216;/contact/thanks/&#8217;)</p>
<p style="padding-left:30px">return render_to_response(&#8216;contact_form.html&#8217;, {&#8216;errors&#8217;: errors,&#8217;subject&#8217;: request.POST.get(&#8216;subject&#8217;, &#8221;),</p>
<p style="padding-left:90px">&#8216;message&#8217;: request.POST.get(&#8216;message&#8217;, &#8221;),&#8217;e-mail&#8217;: request.POST.get(&#8216;e-mail&#8217;, &#8221;),</p>
<p style="padding-left:30px">})</p>
</blockquote>
<blockquote><p>
# contact_form.html<br />
&lt;html&gt;<br />
&lt;head&gt;</p>
<p style="padding-left:30px">&lt;title&gt;Contact us&lt;/title&gt;</p>
<p>&lt;/head&gt;<br />
&lt;body&gt;</p>
<p style="padding-left:30px">&lt;h1&gt;Contact us&lt;/h1&gt;<br />
	{% if errors %}<br />
	&lt;ul&gt;</p>
<p style="padding-left:60px">{% for error in errors %}<br />
		&lt;li&gt;{{ error }}&lt;/li&gt;<br />
		{% endfor %}</p>
<p style="padding-left:30px">&lt;/ul&gt;<br />
	{% endif %}<br />
	&lt;form action=&#8221;/contact/&#8221; method=&#8221;post&#8221;&gt;</p>
<p style="padding-left:60px">&lt;p&gt;Subject: &lt;input type=&#8221;text&#8221; name=&#8221;subject&#8221; value=&#8221;{{ subject }}&#8221;>&lt;/p&gt;<br />
		&lt;p&gt;Your e-mail (optional):</p>
<p style="padding-left:90px">&lt;input type=&#8221;text&#8221; name=&#8221;e-mail&#8221; value=&#8221;{{ e-mail }}&#8221;&gt;</p>
<p style="padding-left:60px">&lt;/p&gt;<br />
		&lt;p&gt;Message:
<p style="padding-left:90px">&lt;textarea name=&#8221;message&#8221; rows=&#8221;10&#8243; cols=&#8221;50&#8243;&gt;<br />
			**{{ message }}**<br />
			&lt;/textarea&gt;</p>
<p style="padding-left:60px">&lt;/p&gt;<br />
		&lt;input type=&#8221;submit&#8221; value=&#8221;Submit&#8221;&gt;</p>
<p style="padding-left:30px">&lt;/form&gt;</p>
<p>&lt;/body&gt;<br />
&lt;/html&gt;
</p></blockquote>
<p>Se trata de una gran cantidad de código, e introduce un montón de posibilidades de error humano. Veremos alguna librería de alto nivel que gestione las tareas relacionadas con los formularios y la validación.</p>
<h3>Su primera clase de formulario</h3>
<p>Django viene con una librería de formularios, llamada django.forms, que se encarga de muchas de las cuestiones que hemos estado viendo en este capítulo – desde la muestra de formularios HTML a la validación. Volvamos a hacer nuestro formulario de contacto utilizando el marco de formularios de Django.</p>
<p>La principal manera de utilizar el marco de formularios es definir una clase Form por cada<br />
<form> HTML. En nuestro caso, sólo tenemos una<br />
<form>, así que tendremos una clase Form. Esta clase puede residir en cualquier lugar, incluyendo directamente en el archivo views.py, pero la convención es mantener las clases Form en un archivo llamado <em>forms.py</em>. Cree este archivo en el mismo directorio que el <em>views.py</em>, y escriba lo siguiente:</p>
<blockquote><p>from django import forms</p>
<p>class ContactForm(forms.Form):</p>
<p style="padding-left:30px">subject = forms.CharField()<br />
	e-mail = forms.EmailField(required=False)<br />
	message = forms.CharField()</p>
</blockquote>
<p>Esto es bastante intuitivo, y es similar a la sintaxis de modelo de Django. Cada campo en el formulario está representado por un tipo de clase Field &#8211; Charfield y EmailField son los únicos tipos Field utilizados aquí &#8211; como atributos de una clase Form. Cada campo es obligatorio por defecto, así que para hacer e-mail opcional, especificamos required = False.</p>
<p>Vayamos al intérprete interactivo de Python y veamos lo que esta clase puede hacer. Lo primero que puede hacer es mostrarse como HTML:</p>
<blockquote><p>
&lt;&lt;&lt; from contact.forms import ContactForm<br />
&lt;&lt;&lt; f = ContactForm()<br />
&lt;&lt;&lt; print f<br />
&lt;tr&gt;&lt;th&gt;&lt;label for=&#8221;id_subject&#8221;&gt;Subject:&lt;/label&gt;&lt;/th&gt;&lt;td&gt;<br />
&lt;input type=&#8221;text&#8221; name=&#8221;subject&#8221; id=&#8221;id_subject&#8221; /&gt;&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;th&gt;&lt;label for=&#8221;id_e-mail&#8221;&gt;E-mail:&lt;/label&gt;&lt;/th&gt;&lt;td&gt;<br />
&lt;input type=&#8221;text&#8221; name=&#8221;e-mail&#8221; id=&#8221;id_e-mail&#8221; /&gt;&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;th&gt;&lt;label for=&#8221;id_message&#8221;&gt;Message:&lt;/label&gt;&lt;/th&gt;&lt;td&gt;<br />
&lt;input type=&#8221;text&#8221; name=&#8221;message&#8221; id=&#8221;id_message&#8221; /&gt;&lt;/td&gt;&lt;/tr&gt;
</p></blockquote>
<p>Django añade una etiqueta a cada campo, junto con las etiquetas <label> para accesibilidad. La idea es hacer que el comportamiento por defecto sea tan satisfactorio como sea posible.</p>
<p>Esta es la salida por defecto en el formato de un &lt;table&gt; HTML, pero hay otras salidas preconstruidas:</p>
<blockquote><p>
&lt;&lt;&lt; print f.as_ul()<br />
&lt;li&gt;&lt;label for=&#8221;id_subject&#8221;&gt;Subject:&lt;/label&gt;<br />
&lt;input type=&#8221;text&#8221; name=&#8221;subject&#8221; id=&#8221;id_subject&#8221; /&gt;&lt;/li&gt;<br />
&lt;li&gt;&lt;label for=&#8221;id_e-mail&#8221;&gt;E-mail:&lt;/label&gt;<br />
&lt;input type=&#8221;text&#8221; name=&#8221;e-mail&#8221; id=&#8221;id_e-mail&#8221; /&gt;&lt;/li&gt;<br />
&lt;li&gt;&lt;label for=&#8221;id_message&#8221;&gt;Message:&lt;/label&gt;<br />
&lt;input type=&#8221;text&#8221; name=&#8221;message&#8221; id=&#8221;id_message&#8221; /&gt;&lt;/li&gt;
</p></blockquote>
<blockquote><p>
&lt;&lt;&lt; print f.as_p()<br />
&#038;ltp>&#038;ltlabel for=&#8221;id_subject&#8221;&gt;Subject:&#038;lt/label&gt;<br />
&#038;ltinput type=&#8221;text&#8221; name=&#8221;subject&#8221; id=&#8221;id_subject&#8221; /&gt;&#038;lt/p&gt;<br />
&#038;ltp>&#038;ltlabel for=&#8221;id_e-mail&#8221;&gt;E-mail:&#038;lt/label&gt;<br />
&#038;ltinput type=&#8221;text&#8221; name=&#8221;e-mail&#8221; id=&#8221;id_e-mail&#8221; /&gt;&#038;lt/p&gt;<br />
&#038;ltp>&#038;ltlabel for=&#8221;id_message&#8221;&gt;Message:&#038;lt/label&gt;<br />
&#038;ltinput type=&#8221;text&#8221; name=&#8221;message&#8221; id=&#8221;id_message&#8221; /&gt;&#038;lt/p&gt;
</p></blockquote>
<p>Tenga en cuenta que la etiquetas de apertura y cierre &lt;table&gt;, &lt;ul&gt;, y &lt;form&gt; no son incluidas en la salida, de forma que usted puede agregar las filas adicionales si es necesario.</p>
<p>Estos métodos son métodos abreviados para el caso común de &#8220;mostrar todo el formulario.&#8221; Usted también puede mostrar el código HTML de un campo particular:</p>
<blockquote><p>
&lt;&lt;&lt; print f['subject']<br />
&lt;input type=&#8221;text&#8221; name=&#8221;subject&#8221; id=&#8221;id_subject&#8221; /&gt;<br />
&lt;&lt;&lt; print f['message']<br />
&lt;input type=&#8221;text&#8221; name=&#8221;message&#8221; id=&#8221;id_message&#8221; /&gt;
</p></blockquote>
<p>La segunda cosa que podemos hacer con los objetos Form es validar los datos. Para ello, crear un nuevo objeto Form y pasarle un diccionario de datos que asigne los nombres de campo a los datos:</p>
<blockquote><p>
&lt;&lt;&lt; f = ContactForm({&#8216;subject&#8217;: &#8216;Hello&#8217;, &#8216;e-mail&#8217;: &#8216;adrian@example.com&#8217;,<br />
… &#8216;message&#8217;: &#8216;Nice site!&#8217;})</p></blockquote>
<p>Una vez ha asociado los datos con una instancia Form, ha creado un Form bound (ligado):</p>
<blockquote><p>
&lt;&lt;&lt; f.is_bound<br />
True</p></blockquote>
<p>Llame al método is_valid() de cualquier Form ligado para averiguar si sus datos son válidos. Hemos pasado un valor válido para cada campo, por lo que el formulario en su totalidad es válido:</p>
<blockquote><p>
&lt;&lt;&lt; f.is_valid()<br />
True</p></blockquote>
<p>Si no se pasa el campo de correo electrónico, sigue siendo válido, porque hemos especificado required = False para ese campo: </p>
<blockquote><p>
&lt;&lt;&lt; f = ContactForm({&#8216;subject&#8217;: &#8216;Hello&#8217;, &#8216;message&#8217;: &#8216;Nice site!&#8217;})<br />
&lt;&lt;&lt; f.is_valid()<br />
True
</p></blockquote>
<p>Pero si dejamos fuera el asunto o el mensaje, el formulario ya no es válido:</p>
<blockquote><p>
&lt;&lt;&lt; f = ContactForm({&#8216;subject&#8217;: &#8216;Hello&#8217;})<br />
&lt;&lt;&lt; f.is_valid()<br />
False<br />
&lt;&lt;&lt; f = ContactForm({&#8216;subject&#8217;: &#8216;Hello&#8217;, &#8216;message&#8217;: &#8221;})<br />
&lt;&lt;&lt; f.is_valid()<br />
False
</p></blockquote>
<p>Usted puede ver los detalles obteniendo mensajes de error específicos por campo:</p>
<blockquote><p>
&lt;&lt;&lt; f = ContactForm({&#8216;subject&#8217;: &#8216;Hello&#8217;, &#8216;message&#8217;: &#8221;})<br />
&lt;&lt;&lt; f['message'].errors<br />
[u'This field is required.']<br />
&lt;&lt;&lt; f['subject'].errors<br />
[]<br />
&lt;&lt;&lt; f['e-mail'].errors<br />
[]
</p></blockquote>
<p>Cada instancia Form ligada tiene un atributo errors que proporciona un diccionario que asigna nombres de campos a listas de mensajes de error:</p>
<blockquote><p>
&lt;&lt;&lt; f = ContactForm({&#8216;subject&#8217;: &#8216;Hello&#8217;, &#8216;message&#8217;: &#8221;})<br />
&lt;&lt;&lt; f.errors<br />
{&#8216;message&#8217;: [u'This field is required.']}</p></blockquote>
<p>Por último, para los casos de instancias de formulario cuyos datos se ha encontrado ser válidos, está disponible el atributo cleaned_data. Este es un diccionario de los datos emitidos, &#8220;limpiado&#8221;. El marco de formularios de Django, no sólo valida los datos, sino que los limpia para convertir de valores a los tipos de Python adecuados, como se muestra aquí:</p>
<blockquote><p>
&lt;&lt;&lt; f = ContactForm({&#8216;subject&#8217;: &#8216;Hello&#8217;, &#8216;e-mail&#8217;: &#8216;adrian@example.com&#8217;,<br />
… &#8216;message&#8217;: &#8216;Nice site!&#8217;})<br />
&lt;&lt;&lt; f.is_valid()<br />
True<br />
&lt;&lt;&lt; f.cleaned_data<br />
{&#8216;message&#8217;: u&#8217;Nice site!&#8217;, &#8216;e-mail&#8217;: u&#8217;adrian@example.com&#8217;, &#8216;subject&#8217;: u&#8217;Hello&#8217;}
</p></blockquote>
<p>Nuestro formulario de contacto trata sólo con cadenas, que son &#8220;limpiadas&#8221; a objetos Unicode, pero si tuviéramos que utilizar un IntegerField o un DateField, el marco de formularios garantizaría que cleaned_data utiliza enteros Python adecuados u objetos datetime.date para los campos dados.</p>
<h3>Vincular objetos Form en vistas</h3>
<p>Ahora que tiene algunos conocimientos básicos sobre las clases Form, veremos cómo podemos utilizar esta infraestructura para sustituir algo en nuestra vista contact(). He aquí cómo podemos reescribir contacto() para utilizar el marco de formularios:</p>
<blockquote><p># views.py</p>
<p>from django.shortcuts import render_to_response<br />
from mysite.contact.forms import ContactForm</p>
<p>def contact(request):</p>
<p style="padding-left:30px">if request.method == &#8216;POST&#8217;:</p>
<p style="padding-left:60px">form = ContactForm(request.POST)<br />
		if form.is_valid():</p>
<p style="padding-left:90px">cd = form.cleaned_data<br />
			send_mail(</p>
<p style="padding-left:120px">cd['subject'],<br />
				cd['message'],<br />
				cd.get(&#8216;e-mail&#8217;, &#8216;noreply@example.com&#8217;),<br />
				['siteowner@example.com'],</p>
<p style="padding-left:90px">)<br />
			return HttpResponseRedirect(&#8216;/contact/thanks/&#8217;)</p>
<p style="padding-left:30px">else:</p>
<p style="padding-left:60px">form = ContactForm()<br />
		return render_to_response(&#8216;contact_form.html&#8217;, {&#8216;form&#8217;: form})</p>
</blockquote>
<blockquote><p>
# contact_form.html</p>
<p>&lt;html&gt;<br />
&lt;head&gt;</p>
<p style="padding-left:30px">&lt;title&gt;Contact us&lt;/title&gt;</p>
<p>&lt;/head&gt;<br />
&lt;body&gt;</p>
<p style="padding-left:30px">&lt;h1&gt;Contact us&lt;/h1&gt;<br />
	{% if form.errors %}</p>
<p style="padding-left:60px">&lt;p style=&#8221;color: red;&#8221;&gt;</p>
<p style="padding-left:90px">Please correct the error{{ form.errors|pluralize }} below.</p>
<p style="padding-left:60px">&lt;/p&gt;</p>
<p style="padding-left:30px">{% endif %}<br />
	&lt;form action=&#8221;" method=&#8221;post&#8221;&gt;</p>
<p style="padding-left:60px">&lt;table&gt;</p>
<p style="padding-left:90px">{{ form.as_table }}</p>
<p style="padding-left:60px">&lt;/table&gt;<br />
		&lt;input type=&#8221;submit&#8221; value=&#8221;Submit&#8221;&gt;</p>
<p style="padding-left:30px">&lt;/form&gt;</p>
<p>&lt;/body&gt;<br />
&lt;/html&gt;
</p></blockquote>
<p>El marco de formularios de Django gestiona la pantalla del HTML, la validación, la limpieza de los datos, y el volver a mostrar el formulario con errores.</p>
<p>Trate de ejecutar esto en local. Cargue el formulario, emítalo sin rellenar ningun campo, emítalo con una dirección inválida de correo electrónico, y finalmente emítalo con los datos válidos.</p>
<h3>Cambiar como se renderizan los campos</h3>
<p>Probablemente lo primero que notará cuando renderiza el formulario localmente es que el campo mensaje se muestra como un &lt;input type=&#8221;text&#8221;&gt;, y debería ser un &lt;textarea&gt;. Podemos arreglar esto mediante el establecimiento del widget del campo:</p>
<blockquote><p>from django import forms</p>
<p>class ContactForm(forms.Form):</p>
<p style="padding-left:30px">subject = forms.CharField()<br />
	e-mail = forms.EmailField(required=False)<br />
	message = forms.CharField(widget=forms.Textarea</p>
</blockquote>
<p>El marco de formularios separa la lógica de presentación de cada campo en un conjunto de widgets. Cada tipo de campo tiene un widget por defecto, pero se puede reemplazar la configuración predeterminada o proporcionar un widget personalizado.</p>
<p>Piense en las clases Field como la representación de la lógica de validación, mientras que los widgets representan la lógica de presentación.</p>
<h3>Establecer una longitud máxima</h3>
<p>Una de las necesidades de validación más común es comprobar que un campo es de un tamaño determinado.Mejoremos nuestro formulario de contacto limitando el asunto a 100 caracteres. Para hacer eso, proporcionar un max_length al Charfield, de esta forma:</p>
<blockquote><p>from django import forms</p>
<p>class ContactForm(forms.Form):</p>
<p style="padding-left:30px">subject = forms.CharField(max_length=100)<br />
	e-mail = forms.EmailField(required=False)<br />
	message = forms.CharField(widget=forms.Textarea)</p>
</blockquote>
<p>Un argumento opcional min_length también está disponible.</p>
<h3>Establecer valores iniciales</h3>
<p>Como una mejora a este formulario, vamos a añadir un valor inicial para el campo Asunto: &#8220;I love your site! &#8220;.  Para hacer esto, podemos utilizar el argumento initial cuando creamos una instancia Form:</p>
<blockquote><p>
def contact(request):</p>
<p style="padding-left:30px">if request.method == &#8216;POST&#8217;:</p>
<p style="padding-left:60px">form = ContactForm(request.POST)<br />
		if form.is_valid():</p>
<p style="padding-left:90px">cd = form.cleaned_data<br />
			send_mail(</p>
<p style="padding-left:120px">cd['subject'],<br />
				cd['message'],<br />
				cd.get(&#8216;e-mail&#8217;, &#8216;noreply@example.com&#8217;),<br />
				['siteowner@example.com'],</p>
<p style="padding-left:90px">)<br />
			return HttpResponseRedirect(&#8216;/contact/thanks/&#8217;)</p>
<p style="padding-left:30px">else:</p>
<p style="padding-left:60px">form = ContactForm(initial={&#8216;subject&#8217;: &#8216;I love your site!&#8217;})<br />
		return render_to_response(&#8216;contact_form.html&#8217;, {&#8216;form&#8217;: form})</p>
</blockquote>
<p>Tenga en cuenta que hay una diferencia entre pasar datos inicialmente y pasar datos que se ligan al formulario. Si sólo pasa los datos iniciales, el formulario será independiente, lo que significa que no tendrá ningún mensaje de error.</p>
<h3>Añadir reglas de validación personalizadas</h3>
<p>Decidimos adoptar una nueva política de validación: cuatro palabras o más, por favor.</p>
<p>Hay varias maneras de conectar la validación personalizada a un formulario Django. Si nuestra regla es algo que volverá a utilizar una y otra vez, podemos crear un tipo de campo personalizado. La mayoría de las validaciones personalizadas son asuntos de una sola vez, sin embargo, y puede vincularse directamente a la clase Form.</p>
<p>Queremos validación adicional en el campo del mensaje, por lo que añadimos un método clean_message() a nuestra clase Form: </p>
<blockquote><p>from django import forms</p>
<p>class ContactForm(forms.Form):</p>
<p style="padding-left:30px">subject = forms.CharField(max_length=100)<br />
	e-mail = forms.EmailField(required=False)<br />
	message = forms.CharField(widget=forms.Textarea)</p>
<p>	def clean_message(self):</p>
<p style="padding-left:60px">message = self.cleaned_data['message']<br />
		num_words = len(message.split())<br />
		if num_words < 4:</p>
<p style="padding-left:90px">raise forms.ValidationError(&#8220;Not enough words!&#8221;)</p>
<p style="padding-left:60px">return message</p>
</blockquote>
<p>El sistema de formularios de Django busca automáticamente cualquier método cuyo nombre empieza con clean_ y termina con el nombre de un campo. Si existe alguno, se llama durante la validación.</p>
<p>En concreto, el método clean_message() será llamado después de la lógica de validación por defecto para un campo determinado (en este caso, la lógica de validación para un CharField obligatorio).Debido a que los datos del campo ya han sido parcialmente procesados, hay que sacarlos de self.cleaned_data. Además, no tiene que preocuparse de comprobar que el valor existe y no es vacío, el validador lo hace de forma predeterminada.</p>
<p>Nosotros, utilizamos una combinación de len() y split() para contar el número de palabras. Si el usuario ha introducido muy pocas palabras, lanzamos un forms.ValidationError. La cadena adjunta a la excepción se muestra al usuario como un elemento de la lista de errores.</p>
<p>Es importante que devolvamos explícitamente el valor limpiado para el campo al final del método. Esto nos permite modificar el valor (o convertirlo a un tipo diferente de Python) dentro de nuestro método de validación personalizado. Si olvidamos de la instrucción de retorno, entonces será devuelto None y  el valor original se perderá.</p>
<h3>Especificar etiquetas</h3>
<p>Por defecto, las etiquetas del formulario HTML autogenerado por Django se crean mediante la sustitución de los guiones bajos por espacios y capitalizando la primera letra, por lo que la etiqueta para el campo e-mail es &#8220;E-mail&#8221;. ¿Suena familiar? Es el mismo algoritmo simple que los modelos Django utilizan para calcular los valores verbose_name de los campos por defecto.</p>
<p>Pero, como con los modelos Django, podemos personalizar la etiqueta de un campo determinado. Sólo tiene que utilizar la etiqueta, de este modo:</p>
<blockquote><p>
class ContactForm(forms.Form):</p>
<p style="padding-left:30px">subject = forms.CharField(max_length=100)<br />
	e-mail = forms.EmailField(required=False, label=&#8217;Your e-mail address&#8217;)<br />
	message = forms.CharField(widget=forms.Textarea)</p>
</blockquote>
<h3>Personalizar el diseño de los formularios</h3>
<p>Nuestra plantilla <em>contact_form.html</em> usa {{ form.as_table }} para mostrar el formulario, pero podemos visualizarlo de otras formas para conseguir un control más detallado sobre la pantalla.</p>
<p>La forma más rápida para personalizar la presentación de los formularios es con CSS. Las listas de error, en particular, podían realizarse con algunas mejoras visuales, y las listas de error autogeneradas usan &lt;ul class =  &#8220;errorlist&#8221;&gt; precisamente para que se pueda apuntar a ellas con CSS. El siguiente CSS hace realmente que nuestros errores destaquen:</p>
<blockquote><p>
&lt;style type=&#8221;text/css&#8221;&gt;</p>
<p>ul.errorlist {</p>
<p style="padding-left:30px">margin: 0;<br />
	padding: 0;</p>
<p>}</p>
<p>.errorlist li {</p>
<p style="padding-left:30px">background-color: red;<br />
	color: white;<br />
	display: block;<br />
	font-size: 10px;<br />
	margin: 0 0 3px;<br />
	padding: 4px 5px;</p>
<p>}</p>
<p>&lt;/style&gt;
</p></blockquote>
<p>Aunque es conveniente disponer de nuestro HTML de formulario generado para nosotros, en muchos casos, usted deseará reemplazar la representación por defecto.</p>
<p>Cada widget de campo (&lt;input type=&#8221;text&#8221;&gt;, &lt;select&gt;, &lt;textarea&gt;, etc) pueden ser renderizado individualmente mediante el acceso a {{ form.fieldname }} en la plantilla, y los errores asociados con un campo están disponibles como {{ form.fieldname.errors }}. Con esto en mente, podemos construir una plantilla personalizada para nuestro formulario de contacto con el siguiente código de plantilla:</p>
<blockquote><p>
&lt;html&gt;<br />
&lt;head&gt;</p>
<p style="padding-left:30px">&lt;title&gt;Contact us&lt;/title&gt;</p>
<p>&lt;/head&gt;<br />
&lt;body&gt;</p>
<p style="padding-left:30px">&lt;h1&gt;Contact us&lt;/h1&gt;<br />
	{% if form.errors %}</p>
<p style="padding-left:60px">&lt;p style=&#8221;color: red;&#8221;&gt;</p>
<p style="padding-left:90px">Please correct the error{{ form.errors|pluralize }} below.</p>
<p style="padding-left:60px">&lt;/p&gt;</p>
<p style="padding-left:30px">{% endif %}<br />
	&lt;form action=&#8221;" method=&#8221;post&#8221;&gt;</p>
<p style="padding-left:60px">&lt;div class=&#8221;field&#8221;&gt;</p>
<p style="padding-left:90px">{{ form.subject.errors }}<br />
			&lt;label for=&#8221;id_subject&#8221;&gt;Subject:&lt;/label&gt;<br />
			{{ form.subject }}</p>
<p style="padding-left:60px">&lt;/div&gt;</p>
<p>		&lt;div class=&#8221;field&#8221;&gt;</p>
<p style="padding-left:90px">{{ form.e-mail.errors }}<br />
			&lt;label for=&#8221;id_e-mail&#8221;&gt;Your e-mail address:&lt;/label&gt;<br />
			{{ form.e-mail }}</p>
<p style="padding-left:60px">&lt;/div&gt;</p>
<p>		&lt;div class=&#8221;field&#8221;&gt;</p>
<p style="padding-left:90px">{{ form.message.errors }}<br />
			&lt;label for=&#8221;id_message&#8221;>Message:&lt;/label&gt;<br />
			{{ form.message }}</p>
<p style="padding-left:60px">&lt;/div&gt;</p>
<p>		&lt;input type=&#8221;submit&#8221; value=&#8221;Submit&#8221;&gt;</p>
<p style="padding-left:30px">&lt;/form&gt;</p>
<p>&lt;/body&gt;<br />
&lt;/html&gt;
</p></blockquote>
<p>{{ form.message.errors }} muestra una &lt;ul class=&#8221;errorlist&#8221;&gt; si hay errores y una cadena en blanco si el campo es válido (o el formulario no está ligado). También puede tratar form.message.errors como un valor booleano o incluso iterar sobre él como una lista. Considere este ejemplo:</p>
<blockquote><p>
&lt;div class=&#8221;field{% if form.message.errors %} errors{% endif %}&#8221;&gt;</p>
<p style="padding-left:30px">{% if form.message.errors %}</p>
<p style="padding-left:60px">&lt;ul&gt;<br />
		{% for error in form.message.errors %}</p>
<p style="padding-left:90px">&lt;li>&lt;strong&gt;{{ error }}&lt;/strong&gt;&lt;/li&gt;</p>
<p style="padding-left:60px">{% endfor %}<br />
		&lt;/ul&gt;</p>
<p style="padding-left:30px">{% endif %}</p>
<p>	&lt;label for=&#8221;id_message&#8221;&gt;Message:&lt;/label&gt;<br />
	{{ form.message }}</p>
<p>&lt;/div&gt;
</p></blockquote>
<p>En el caso de errores de validación, esto añadirá una clase errors al &lt;div&gt; y muestra la lista de errores en una lista desordenada.</p>
<h3>Enlaces Relacionados:</h3>
<ul>
<li><a href="http://www.cibernatural.com/tutorial-de-django-i">Tutorial de Django I</a></li>
<li><a href="http://www.cibernatural.com/tutorial-de-django-ii">Tutorial de Django II</a></li>
<li><a href="http://www.cibernatural.com/tutorial-de-django-iii">Tutorial de Django III</a></li>
<li><a href="http://www.cibernatural.com/tutorial-de-django-iv">Tutorial de Django IV</a></li>
<li><a href="http://www.cibernatural.com/tutorial-de-django-v">Tutorial de Django V</a></li>
<li>Tutorial de Django VI</li>
<li><a href="http://www.cibernatural.com/tutorial-de-django-vii">Tutorial de Django VII</a></li>
</ul>

                            <div id="aspdf">
                                <a href="http://www.cibernatural.com/wp-content/plugins/as-pdf/generate.php?post=640">
                                    <span>Descargar en PDF</span>
                                </a>
                            </div>
                        ]]></content:encoded>
			<wfw:commentRss>http://www.cibernatural.com/tutorial-de-django-vi/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Tutorial de Django – V</title>
		<link>http://www.cibernatural.com/tutorial-de-django-v/</link>
		<comments>http://www.cibernatural.com/tutorial-de-django-v/#comments</comments>
		<pubDate>Wed, 12 May 2010 12:19:56 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Guía Django]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://www.cibernatural.com/?p=602</guid>
		<description><![CDATA[El sitio de administración de Django Para una cierta clase de sitios Web, una interfaz de administración es una parte esencial de la infraestructura. Se trata de una interfaz basada en Web, limitada a los administradores del sitio de confianza, que permite la adición, la edición, y la eliminación de contenido del sitio. Los paquetes [...]]]></description>
			<content:encoded><![CDATA[<h2><strong><span style="text-decoration: underline;">El sitio de administración de Django</span></strong></h2>
<p>Para una cierta clase de sitios Web, una interfaz de administración es una parte esencial de la infraestructura. Se trata de una interfaz basada en Web, limitada a los administradores del sitio de confianza, que permite la adición, la edición, y la eliminación de contenido del sitio.</p>
<h3>Los paquetes django.contrib</h3>
<p>La administración automática de Django es parte de una gran suite de funcionalidad de Django llamada django.contrib &#8211; la parte de código de Django que contiene diversas utilidades para el núcleo. Usted puede pensar en django.contrib como el equivalente de Django de la librería estándar de Python. Está integrado con Django de modo que no tenemos que reinventar la rueda en nuestras propias aplicaciones.</p>
<p>El sitio de administración se llama django.contrib.admin. Otras características disponibles en django.contrib incluyen un sistema de autenticación de usuarios (django.contrib.auth), soporte para sesiones anónimas (django.contrib.sessions), e incluso un sistema de comentarios de usuarios (django.contrib.comments).<br />
<span id="more-602"></span></p>
<h3>Activar la interfaz de administración</h3>
<p>El sitio de administración de Django es totalmente opcional, ya que sólo ciertos tipos de sitios necesitan esta funcionalidad. Eso significa que usted tendrá que dar unos pasos para activarlo en su proyecto.</p>
<p>En primer lugar, hacer unos cuantos cambios a su archivo de configuración: </p>
<ol>
<li>Añadir &#8216;django.contrib.admin&#8217; a la propiedad INSTALLED_APPS.</li>
<li>Asegúrese de que INSTALLED_APPS contiene &#8216;django.contrib.auth&#8217;, &#8216;django.contrib.contenttypes&#8217;, y &#8216;django.contrib.sessions&#8217;. El sitio de administración de Django requiere de estos tres paquetes.</li>
<li>Asegúrese de que MIDDLEWARE_CLASSES contiene los valores &#8216;django.middleware.common.CommonMiddleware&#8217;,<br />
&#8216;django.contrib.sessions.middleware.SessionMiddleware&#8217;, y &#8216;django.contrib.auth.middleware.AuthenticationMiddleware.</li>
</ol>
<p>En segundo lugar, ejecutar <strong>python manage.py syncdb</strong>. Este paso permitirá instalar las tablas extra de base de datos que utiliza el interfaz de administración. La primera vez que ejecute syncdb con &#8216;django.contrib.auth&#8217; en INSTALLED_APPS, se le preguntará sobre la creación de un super-usuario. Si usted no hace esto, tendrá que para ejecutar python manage.py createsuperuser por separado para crear una cuenta de usuario administrador, de lo contrario usted no será capaz de entrar en el sitio de administración.</p>
<p>En tercer lugar, agregue el sitio de administración a su URLconf (en <em>urls.py</em>, recuerde). Por defecto, el <em>urls.py</em> generado por <strong>django-admin.py startproject</strong> contiene el código comentado para la administración de Django, y todo lo que tiene que hacer es quitar los comentarios.</p>
<blockquote><p># Include these import statements&#8230;<br />
from django.contrib import admin<br />
admin.autodiscover()</p>
<p># And include this URLpattern&#8230;<br />
urlpatterns = patterns(&#8221;,</p>
<p style="padding-left:30px;"># &#8230;<br />
	(r&#8217;^admin/&#8217;, include(admin.site.urls)),<br />
	# &#8230;
</p>
<p>)</p></blockquote>
<p>Con esa poca configuración, ahora usted puede ver el sitio de administración de Django en acción.  Simplemente ejecute el servidor de desarrollo (<strong>python manage.py runserver</strong>) y visite <strong>http://127.0.0.1:8000/admin/</strong> en su navegador Web.</p>
<h3>Usar el sitio de administración</h3>
<p>Inicie sesión con el nombre de usuario y contraseña que agregó cuando creó el superusuario. Si usted no puede abrir una sesión, asegúrese de que ha creado realmente un super-usuario ejecutando <strong>python manage.py createsuperuser</strong>.</p>
<p>Una vez que esté conectado, lo primero que verá será la página de inicio de administración. Esta página muestra todos los tipos de datos disponibles que se pueden editar en el sitio de administración. En este punto, ya que no ha activado ninguno de nuestros modelos, la lista es escasa: sólo incluye Grupos y Usuarios, que son los dos modelos de administración por defecto editables.</p>
<p>Cada tipo de datos en el sitio de administración de Django tiene una lista de cambios y un formulario de edición. Las listas de cambios muestran todos los objetos disponibles en la base de datos, y los formularios de edición le permiten añadir, cambiar o eliminar registros particulares en su base de datos.</p>
<p>Haga clic en el vínculo Cambiar en la fila de los usuarios para cargar la página de lista de cambios de los usuarios. Esta página muestra todos los usuarios de la base de datos.</p>
<p>Pulse un nombre de usuario, y verá el formulario de edición de ese usuario. Esta página le permite cambiar los atributos del usuario.</p>
<h3>Añadir modelos al sitio de administración</h3>
<p>Vamos a añadir nuestros propios modelos a la página de administración a fin de que podemos agregar, modificar y eliminar objetos en nuestras tablas de bases de datos personalizadas utilizando esta interfaz agradable.</p>
<p>Vamos a seguir el ejemplo de los libros, donde definimos tres modelos: Publisher, Author, y Book.</p>
<p>En el directorio de libros (mysite/books), cree un archivo llamado <em>admin.py</em>, y escriba las siguientes líneas de código:</p>
<blockquote><p>from django.contrib import admin<br />
from mysite.books.models import Publisher, Author, Book</p>
<p>admin.site.register(Publisher)<br />
admin.site.register(Author)<br />
admin.site.register(Book)</p></blockquote>
<p>Este código le indica al sitio de administración de Django que ofrezca una interfaz para cada uno de estos modelos.</p>
<p>Una vez que haya hecho esto, vaya a la página de inicio de administración en su explorador Web (<strong>http://127.0.0.1:8000/admin/</strong>). Usted debe ver una sección de Libros con enlaces a los autores, libros y editores. Tendrá que reiniciar runserver para que los cambios tengan efecto.</p>
<p>Un aspecto digno de mencionar aquí es el manejo de las claves ajenas y las relaciones muchos-a-muchos por el sitio de administración, las cuales aparecen en el modelo Book.</p>
<p>En la página Add Book  del sitio de administración de Django (http://127.0.0.1:8000/admin/books/book/add/), el editor (una ForeignKey) es representado por una caja de selección, y el campo de los autores (un ManyToManyField) es representado por un cuadro de selección múltiple. Ambos campos están al lado de un signo más verde que te permite añadir los registros relacionados de ese tipo. Por ejemplo, si hace clic en el signo más verde junto al campo Publisher, obtendrá una ventana emergente que le permite añadir un editor.</p>
<h3>Cómo trabaja el sitio de administración</h3>
<p>Cuando Django carga su URLconf de <em>urls.py</em> al arrancar el servidor, se ejecuta la setencia admin.autodiscover() que añadimos como parte de la activación de la administración. Esta función itera sobre la configuración de INSTALLED_APPS y busca un archivo llamado <em>admin.py</em> en cada aplicación instalada. Si un <em>admin.py</em> existe en una aplicación dada, se ejecuta el código de ese fichero.</p>
<p>En el <em>admin.py</em> de nuestra aplicación books, cada llamada a admin.site.register() simplemente registra el modelo dado con la administración. El sitio de administración mostrará una interfaz de edición/modificación para cada modelo que se haya registrado de forma explícita.</p>
<p>La aplicación django.contrib.auth incluye su propio <em>admin.py</em>, por lo que usuarios y grupos se mostraron de forma automática en la administración.</p>
<p>El sitio de administración de Django es sólo una aplicación Django, con sus propios modelos, plantillas, vistas, y patrones URL. Usted puede examinar sus plantillas, vistas, y patrones URL hurgando en django / contrib / admin en su copia del código base de Django.</p>
<h3>Hacer campos opcionales</h3>
<p>Usted notará probablemente una limitación &#8211; los formularios de edición requieren que se rellenen todos los campos, mientras que en muchos casos le gustaría que determinados campos fuesen opcionales. Digamos, por ejemplo, que queremos que nuestro campo email del modelo Author sea opcional, es decir, que se permita una cadena en blanco. En el mundo real, usted no podría tener una dirección de correo electrónico en archivo para cada autor.</p>
<p>Para especificar que el campo de correo electrónico es opcional, modificar el modelo Author. Basta con añadir <strong>blank = True</strong> para el campo email, así:</p>
<blockquote><p>class Author(models.Model):</p>
<p style="padding-left:30px;">first_name = models.CharField(max_length=30)<br />
	last_name = models.CharField(max_length=40)<br />
	email = models.EmailField(blank=True)</p>
</blockquote>
<p>Al añadir blank = True, hemos comenzado la expansión de nuestro modelo más allá de una simple definición de la tabla de base de datos. Ahora, nuestra clase de modelo está empezando a convertirse en una rica colección de conocimiento sobre lo que los objetos Author son y qué pueden hacer. No sólo está el campo email representado por una columna VARCHAR en la base de datos, sino que es también un campo opcional en contextos como el sitio de administración de Django.</p>
<h3>Hacer a fechas y campos numéricos opcionales</h3>
<p>SQL tiene su propia forma de especificar los valores en blanco, un valor especial llamado NULL. NULL puede significar &#8220;desconocido&#8221; o &#8220;inválido&#8221;, o algún  otro significado específico de la aplicación. En SQL, un valor de NULL es diferente de una cadena vacía, al igual que el objeto especial de Python None es diferente de la una cadena vacía (&#8220;&#8221;).</p>
<p>Esto puede causar confusión y ambigüedad no deseados: ¿Por qué este disco tiene un valor NULL, pero este otro tiene una cadena vacía? ¿Hay una diferencia, o se introdujeron los datos de manera distinta?. Y ¿Cómo puedo obtener todos los registros que tienen un valor en blanco, debería buscar tanto los registros NULL como las cadenas vacías, o debo elegir sólo los que tienen cadenas vacías?</p>
<p>Para evitar esa ambigüedad, Django genera automáticamente sentencias CREATE TABLE añadiendo un valor explícito  NOT NULL a cada definición de columna.</p>
<p>En la mayoría de los casos, este comportamiento predeterminado es óptimo para su aplicación y le ahorrará dolores de cabeza por inconsistencia de los datos. Y funciona muy bien con el resto de Django, tales como el sitio de administración de Django, que inserta una cadena vacía (no un valor NULL) cuando se deja un campo de carácter en blanco.</p>
<p>Pero hay una excepción con los tipos de columna de base de datos que no aceptan cadenas vacías como valores válidos, tales como fechas, horas y números. Si intenta insertar una cadena vacía en una columna de fecha o número entero, lo más probable es obtener un error de base la de datos. En este caso, NULL es la única manera de especificar un valor vacío. En los modelos Django, usted puede especificar que se permite NULL añadiendo null = True a un campo.</p>
<p>En resumen, si desea permitir valores en blanco en un campo de fecha (por ejemplo, DateField, TimeField, DateTimeField) o campo numérico (por ejemplo, IntegerField, DecimalField, FloatField), tendrá que utilizar tanto <strong>null = True</strong> como <strong>blank = True</strong>.</p>
<p>Cambiemos nuestro modelo Book para permitir una fecha de publicación en blanco:</p>
<blockquote><p>class Book(models.Model):</p>
<p style="padding-left:30px;">title = models.CharField(max_length=100)<br />
	authors = models.ManyToManyField(Author)<br />
	publisher = models.ForeignKey(Publisher)<br />
	publication_date = models.DateField(blank=True, null=True)</p>
</blockquote>
<p>Agregar null = True es más complicado que añadir blank = True, porque null = True cambia la semántica de la base de datos, es decir, cambia la sentencia CREATE TABLE para eliminar el NOT NULL del campo publication_date. Para completar este cambio, <strong>necesitaremos actualizar la base de datos</strong>.</p>
<p>Por varias razones, Django no trata de automatizar los cambios en los esquemas de base de datos, por lo que es su propia responsabilidad ejecutar el ALTER TABLE adecuado siempre que se realice un cambio a un modelo. Recuerde que puede utilizar python manage.py dbshell para entrar en la shell de su servidor de base de datos. He aquí cómo quitar el NOT NULL en este caso en particular:</p>
<blockquote><p>ALTER TABLE books_book ALTER COLUMN publication_date DROP NOT NULL;</p></blockquote>
<p>Ahora el formulario de edición Add Book debería permitir valores de fecha de publicación vacíos.</p>
<h3>Personalizar etiquetas de campo</h3>
<p>En los formularios de edición del sitio de administración, la etiqueta de cada campo se genera a partir del nombre de campo del modelo. El algoritmo es simple: Django simplemente reemplaza los guiones bajos con espacios y coloca en mayúsculas el primer carácter. Así, por ejemplo, el campo publication_date del modelo Book tiene la fecha Publicación Date.</p>
<p>Sin embargo, los nombres de campo no siempre se prestan a etiquetas de campo agradables en administración, así que en algunos casos es posible que desee personalizar una etiqueta. Usted puede hacer esto especificando <strong>verbose_name</strong> en el campo del modelo adecuado. Por ejemplo, así es cómo podemos cambiar la etiqueta del campo Author.email a &#8220;e-mail&#8221;, con guión:</p>
<blockquote><p>class Author(models.Model):</p>
<p style="padding-left:30px;">first_name = models.CharField(max_length=30)<br />
	last_name = models.CharField(max_length=40)<br />
	email = models.EmailField(blank=True, verbose_name=&#8217;e-mail&#8217;)
</p>
</blockquote>
<p>Por último, tenga en cuenta que puede pasar el verbose_name como un argumento de posición, para una sintaxis más compacta. Este ejemplo es equivalente al anterior:</p>
<blockquote><p>class Author(models.Model):</p>
<p style="padding-left:30px;">first_name = models.CharField(max_length=30)<br />
	last_name = models.CharField(max_length=40)<br />
	email = models.EmailField(&#8216;e-mail&#8217;, blank=True)
</p>
</blockquote>
<p>Esto no funcionará con campos <em>ManyToManyField</em> o <em>ForeignKey</em>, debido a que requieren que el primer argumento sea una clase modelo. En esos casos, especificar verbose_name explícitamente. </p>
<h3>Personalizar clases ModelAdmin</h3>
<p>Los cambios que hemos hecho hasta ahora &#8211; blank = True, null = True, y verbose_name- son realmente cambios de nivel de modelo, no cambios de nivel de administración. Es decir, estos cambios son, fundamentalmente, una parte del modelo y sólo para ser utilizados por el sitio de administración, no hay nada específico de administración en ellos.</p>
<p>Más allá de estos, el sitio de administración de Django ofrece una gran cantidad de opciones que permiten personalizar la forma en que el sitio de administración trabaja para un modelo en particular. Tales opciones residen en clases <em>ModelAdmin</em>, que son clases que contienen la configuración de un modelo específico en una instancia  del sitio de administración específica.</p>
<h3>Personalizar listas de cambios</h3>
<p>Entremos en la personalización de administración, especificando los campos que se muestran en la lista de cambios para el modelo Author. De forma predeterminada, la lista de cambios muestra el resultado de <strong>__unicode__()</strong> para cada objeto.</p>
<p>Podemos mejorar este comportamiento predeterminado, añadiendo algunos campos más a la muestra de la lista de cambios. Sería útil, por ejemplo, ver cada e-mail del autor en esta lista, y sería bueno poder ordenarla por nombre y apellido.</p>
<p>Para que esto ocurra, vamos a definir una clase <em>ModelAdmin</em> para el modelo de Autor. Esta clase es la clave para personalizar la administración, y una de las cosas más básicas que le permite hacer es especificar la lista de campos a mostrar en las páginas de lista de cambios. Editar <em>admin.py</em> para realizar estos cambios:</p>
<blockquote><p>from django.contrib import admin<br />
from mysite.books.models import Publisher, Author, Book</p>
<p>class AuthorAdmin(admin.ModelAdmin):</p>
<p style="padding-left:30px;">list_display = (&#8216;first_name&#8217;, &#8216;last_name&#8217;, &#8216;email&#8217;)</p>
<p>admin.site.register(Publisher)<br />
admin.site.register(Author, AuthorAdmin)<br />
admin.site.register(Book)
</p></blockquote>
<p>Volver a cargar la página de lista de cambios del autor, y verá que ahora se muestran tres columnas: el nombre, el apellido y la dirección de correo electrónico. Además, cada una de esas columnas es ordenable haciendo clic en el encabezado de la columna.</p>
<p>Ahora agreguemos una barra de búsqueda simple. Añadir a <strong>search_fields</strong> a AuthorAdmin, así: </p>
<blockquote><p>class AuthorAdmin(admin.ModelAdmin):</p>
<p style="padding-left:30px;">list_display = (&#8216;first_name&#8217;, &#8216;last_name&#8217;, &#8216;email&#8217;)<br />
	search_fields = (&#8216;first_name&#8217;, &#8216;last_name&#8217;)
</p>
</blockquote>
<p>Actualice la página en su navegador, y debería ver una barra de búsqueda en la parte superior. Hemos incluido una barra de búsqueda que busca en los campos first_name y last_name. Ahora agreguemos algunos filtros de fecha para nuestra página de lista de cambios del modelo Book:</p>
<blockquote><p>from django.contrib import admin<br />
from mysite.books.models import Publisher, Author, Book</p>
<p>class AuthorAdmin(admin.ModelAdmin):</p>
<p style="padding-left:30px;">list_display = (&#8216;first_name&#8217;, &#8216;last_name&#8217;, &#8216;email&#8217;)<br />
	search_fields = (&#8216;first_name&#8217;, &#8216;last_name&#8217;)</p>
<p>class BookAdmin(admin.ModelAdmin):</p>
<p style="padding-left:30px;">list_display = (&#8216;title&#8217;, &#8216;publisher&#8217;, &#8216;publication_date&#8217;)<br />
	list_filter = (&#8216;publication_date&#8217;,)</p>
<p>admin.site.register(Publisher)<br />
admin.site.register(Author, AuthorAdmin)<br />
admin.site.register(Book, BookAdmin)
</p></blockquote>
<p>Hemos utilizado <strong>list_filter</strong>, que fija en una tupla los campos a utilizar para crear filtros en el lado derecho de la página de lista de cambios. Para los campos fecha, Django proporciona accesos directos para filtrar la lista por &#8220;Hoy&#8221;, &#8220;Últimos 7 días&#8221;, &#8220;Este mes&#8221;, y &#8220;Este año&#8221;.</p>
<p>list_filter también trabaja en campos de otros tipos, no sólo DateField. (Pruebe con los campos BooleanField y ForeignKey, por ejemplo.) Los filtros se muestran siempre que haya por lo menos dos valores a elegir.</p>
<p>Otra manera de ofrecer filtros de fecha es utilizar la opción de administración <strong>date_hierarchy</strong>, así: </p>
<blockquote><p>class BookAdmin(admin.ModelAdmin):</p>
<p style="padding-left:30px;">list_display = (&#8216;title&#8217;, &#8216;publisher&#8217;, &#8216;publication_date&#8217;)<br />
	list_filter = (&#8216;publication_date&#8217;,)<br />
	date_hierarchy = &#8216;publication_date&#8217;
</p>
</blockquote>
<p>Tenga en cuenta que date_hierarchy toma una cadena, no una tupla, porque sólo un campo de fecha puede utilizarse para la jerarquía.</p>
<p>Por último, vamos a cambiar el orden por defecto en que se muestran los libros en la página de lista de cambios a siempre ordenado descendente por la fecha de su publicación.</p>
<blockquote><p>class BookAdmin(admin.ModelAdmin):</p>
<p style="padding-left:30px;">list_display = (&#8216;title&#8217;, &#8216;publisher&#8217;, &#8216;publication_date&#8217;)<br />
	list_filter = (&#8216;publication_date&#8217;,)<br />
	date_hierarchy = &#8216;publication_date&#8217;<br />
	ordering = (&#8216;-publication_date&#8217;,)
</p>
</blockquote>
<p>Usando estas opciones, usted puede hacer una interfaz de edición de datos muy potente, lista para producción, con sólo unas pocas líneas de código.</p>
<h3>Personalizar los formularios de edición</h3>
<p>En primer lugar, vamos a personalizar la manera en que se ordenan los campos. De forma predeterminada, el orden de los campos en un formulario de edición corresponde al orden en que están definidas en el modelo. Nosotros podemos cambiar eso utilizando la opción <strong>fields</strong> en nuestra subclase <em>ModelAdmin</em>:</p>
<blockquote><p>class BookAdmin(admin.ModelAdmin):</p>
<p style="padding-left:30px;">list_display = (&#8216;title&#8217;, &#8216;publisher&#8217;, &#8216;publication_date&#8217;)<br />
	list_filter = (&#8216;publication_date&#8217;,)<br />
	date_hierarchy = &#8216;publication_date&#8217;<br />
	ordering = (&#8216;-publication_date&#8217;,)<br />
	fields = (&#8216;title&#8217;, &#8216;authors&#8217;, &#8216;publisher&#8217;, &#8216;publication_date&#8217;)
</p>
</blockquote>
<p>Otra cosa útil de la opción fields es que permite excluir a ciertos campos de la edición. Sólo dejando fuera los campo(s) que desea excluir. Por ejemplo, en nuestra base de datos de libros, se podría impedir que el campo publication_date fuese editable:</p>
<blockquote><p>class BookAdmin(admin.ModelAdmin):</p>
<p style="padding-left:30px;">list_display = (&#8216;title&#8217;, &#8216;publisher&#8217;, &#8216;publication_date&#8217;)<br />
	list_filter = (&#8216;publication_date&#8217;,)<br />
	date_hierarchy = &#8216;publication_date&#8217;<br />
	ordering = (&#8216;-publication_date&#8217;,)<br />
	fields = (&#8216;title&#8217;, &#8216;authors&#8217;, &#8216;publisher&#8217;)
</p>
</blockquote>
<p>Otro uso común de personalizar los formularios de edición tiene que ver con los campos muchos a muchos. El sitio de administración representa cada <em>ManyToManyField</em> como una caja de selección múltiple. Si desea seleccionar varios elementos, hay que mantener pulsada la tecla Control. El sitio de administración amablemente inserta un fragmento de texto que explica esto, pero, aún así, se hace difícil de manejar cuando su campo contiene cientos de opciones. La solución del sitio de administración es <strong>filter_horizontal</strong>.</p>
<blockquote><p>class BookAdmin(admin.ModelAdmin):</p>
<p style="padding-left:30px;">list_display = (&#8216;title&#8217;, &#8216;publisher&#8217;, &#8216;publication_date&#8217;)<br />
	list_filter = (&#8216;publication_date&#8217;,)<br />
	date_hierarchy = &#8216;publication_date&#8217;<br />
	ordering = (&#8216;-publication_date&#8217;,)<br />
	filter_horizontal = (&#8216;authors&#8217;,)
</p>
</blockquote>
<p>Recomendamos el uso filter_horizontal para cualquier ManyToManyField que tenga más de diez elementos. Es mucho más fácil de utilizar.También, recuerde que puede usar filter_horizontal en múltiples campos, especificando solamente cada nombre en la tupla. Las clases <em>ModelAdmin</em> también tienen una opción <strong>filter_vertical</strong>. Funciona exactamente como filter_horizontal, pero la interfaz coloca las dos casillas verticalmente en vez de horizontalmente. Es una cuestión de gusto personal.</p>
<p>filter_horizontal y filter_vertical funcionan sólo en los campos <em>ManyToManyField</em>, no en campos <em>ForeignKey</em>. Por defecto, el sitio de administración usa &lt;select&gt; simples para los campos <em>ForeignKey</em>, pero, como para <em>ManyToManyField</em>, a veces usted no quiere incurrir en la sobrecarga de tener que seleccionar todos los objetos relacionados con la pantalla en el menú desplegable. Por ejemplo, si nuestra base de datos de libros crece para incluir a miles de editores, el formulario Add Book podría tardar bastante en cargar, ya que tiene que cargar cada editor a mostrar en el cuadro &lt;select&gt;.</p>
<p>Puedes solucionar este problema con una opción llamada <strong>raw_id_fields</strong>. Ponga esto en una tupla de nombres de campo <em>ForeignKey</em>, y los campos se mostrarán en el administrador con una caja de entrada de texto simple (&lt;input type = &#8220;text&#8221;&gt;) en lugar de un &lt;select&gt;.</p>
<blockquote><p>class BookAdmin(admin.ModelAdmin):</p>
<p style="padding-left:30px;">list_display = (&#8216;title&#8217;, &#8216;publisher&#8217;, &#8216;publication_date&#8217;)<br />
	list_filter = (&#8216;publication_date&#8217;,)<br />
	date_hierarchy = &#8216;publication_date&#8217;<br />
	ordering = (&#8216;-publication_date&#8217;,)<br />
	filter_horizontal = (&#8216;authors&#8217;,)<br />
	raw_id_fields = (&#8216;publisher&#8217;,)
</p>
</blockquote>
<p>¿Qué introduciría en este cuadro de entrada? El identificador de la base de datos del editor.Teniendo en cuenta que los seres humanos normalmente no memorizan identificadores base de datos, hay un icono en el que puede hacer clic para iniciar una ventana desde la que puede seleccionar el editor.</p>
<h3>Usuarios, grupos y permisos</h3>
<p>Ya que está conectado como super-usuario, tiene acceso a crear, editar y eliminar cualquier objeto. Naturalmente, los diferentes entornos requieren de sistemas de autorización diferentes, no todos pueden o deben ser un superusuario. El sitio de administración de Django utiliza un sistema de permisos que se puede utilizar para dar acceso específico a los usuarios a las partes de la interfaz que necesitan.</p>
<p>Estas cuentas de usuario están destinadas a ser lo suficientemente generales como para utilizarse fuera de la interfaz de administración, pero las trataremos como cuentas de usuario de administración por ahora.</p>
<p>Puede editar los usuarios y los permisos a través de la interfaz de administración al igual que cualquier otro objeto. Los objetos de usuario tiene los campos nombre de usuario estándar, contraseña, e-mail, y nombre real, junto con un conjunto de campos que definen lo que el usuario puede hacer en la interfaz de administración. En primer lugar, hay un conjunto de 3 banderas boolean:</p>
<ul>
<li>El flag &#8220;activo&#8221; controla si el usuario está activo.</li>
<li>El flag &#8220;staff&#8221; controla si el usuario tiene permiso para acceder a la interfaz de administración.</li>
<li>El flag &#8220;superusuario&#8221; proporciona al usuario acceso completo a agregar, crear y eliminar cualquier elemento de la interfaz de administración.</li>
</ul>
<p>Los usuarios de administración &#8220;normales&#8221; &#8211; es decir, los miembros activos, no superusuarios &#8211; se les concede acceso de administración a través de los permisos asignados. Cada objeto editable a través de la interfaz de administración (por ejemplo, libros, autores, editores) tiene tres permisos: crear, editar y eliminar. La asignación de permisos a un usuario concede al usuario el correspondiente nivel de acceso. </p>
<p>Al crear un usuario, dicho usuario no tiene permisos. Por ejemplo, usted puede dar a un usuario permiso para agregar y cambiar los editores, pero no para eliminarlos. Tenga en cuenta que estos permisos se definen por el modelo, no por objeto, de forma que usted diga, &#8220;Juan puede hacer cambios en cualquier libro,&#8221; pero no le permite decir, &#8220;Juan puede hacer los cambios de cualquier libro publicado por Apress. &#8221;</p>
<p>También puede asignar usuarios a grupos. Un grupo es simplemente un conjunto de permisos que se aplican a todos los miembros de ese grupo. Los grupos son útiles para la concesión de permisos idénticos a un subconjunto de usuarios.</p>
<h3>Enlaces Relacionados:</h3>
<ul>
<li><a href="http://www.cibernatural.com/tutorial-de-django-i">Tutorial de Django I</a></li>
<li><a href="http://www.cibernatural.com/tutorial-de-django-ii">Tutorial de Django II</a></li>
<li><a href="http://www.cibernatural.com/tutorial-de-django-iii">Tutorial de Django III</a></li>
<li><a href="http://www.cibernatural.com/tutorial-de-django-iv">Tutorial de Django IV</a></li>
<li>Tutorial de Django V</li>
<li><a href="http://www.cibernatural.com/tutorial-de-django-vi">Tutorial de Django VI</a></li>
<li><a href="http://www.cibernatural.com/tutorial-de-django-vii">Tutorial de Django VII</a></li>
</ul>

                            <div id="aspdf">
                                <a href="http://www.cibernatural.com/wp-content/plugins/as-pdf/generate.php?post=602">
                                    <span>Descargar en PDF</span>
                                </a>
                            </div>
                        ]]></content:encoded>
			<wfw:commentRss>http://www.cibernatural.com/tutorial-de-django-v/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Tutorial de Django – IV</title>
		<link>http://www.cibernatural.com/tutorial-de-django-iv/</link>
		<comments>http://www.cibernatural.com/tutorial-de-django-iv/#comments</comments>
		<pubDate>Fri, 09 Apr 2010 17:50:11 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Guía Django]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://www.cibernatural.com/?p=560</guid>
		<description><![CDATA[Modelos Hemos visto los fundamentos de la construcción de sitios Web dinámicos con Django: la configuración de vistas y URLconfs. Como hemos explicado, una vista es responsable de hacer alguna lógica arbitraria, y luego devolver una respuesta. En uno de los ejemplos, nuestra lógica arbitraria fue calcular la fecha y hora actuales. En las modernas aplicaciones Web, [...]]]></description>
			<content:encoded><![CDATA[<h2><strong><span style="text-decoration: underline;">Modelos</span></strong></h2>
<p>Hemos visto los fundamentos de la construcción de sitios Web dinámicos con Django: la configuración de vistas y URLconfs. Como hemos explicado, una vista es responsable de hacer alguna lógica arbitraria, y luego devolver una respuesta. En uno de los ejemplos, nuestra lógica arbitraria fue calcular la fecha y hora actuales.</p>
<p>En las modernas aplicaciones Web, la lógica arbitraria implica a menudo interactúar con una base de datos. Un sitio web controlado por base de datos se conecta a un servidor de base de datos, recupera algunos de los datos, y muestra esos datos en una página Web. El sitio también puede proporcionar medios para que los visitantes rellenen la base de datos por su cuenta. </p>
<p>Django es muy adecuado para hacer sitios web controlados por base de datos porque viene con poderosas herramientas para la realización de consultas de base de datos usando Python. Este capítulo explica esta funcionalidad: <strong>la capa de base de datos de Django</strong>.<br />
<span id="more-560"></span></p>
<h3>La forma &#8220;Tonta&#8221; de hacer consultas de base de datos en Vistas</h3>
<p>Hay una manera &#8220;tonta&#8221; de recuperar datos de una base de datos en una vista. Es muy sencillo: sólo tiene que utilizar cualquier librería de Python existente para ejecutar una consulta SQL y hacer algo que con los resultados.</p>
<p>En esta vista de ejemplo, usamos la librería MySQLdb para conectarse a una base de datos MySQL, recuperar algunos registros, y pasarlos a una plantilla para mostrar como una página Web: </p>
<blockquote><p>from django.shortcuts import render_to_response<br />
import MySQLdb</p>
<p>def book_list(request):</p>
<p style="padding-left:30px;">db = MySQLdb.connect(user=&#8217;me&#8217;, db=&#8217;mydb&#8217;, passwd=&#8217;secret&#8217;, host=&#8217;localhost&#8217;)<br />
cursor = db.cursor()<br />
cursor.execute(&#8216;SELECT name FROM books ORDER BY name&#8217;)<br />
names = [row[0] for row in cursor.fetchall()]<br />
db.close()<br />
return render_to_response(&#8216;book_list.html&#8217;, {&#8216;names&#8217;: names})</p>
</blockquote>
<p>Este enfoque funciona, pero algunos problemas saltan a la vista de inmediato:</p>
<ul>
<li>Estamos codificando a pelo los parámetros de conexión a la base de datos. Idealmente, esos parámetros deberían almacenarse en la configuración de Django.</li>
<li>Estamos escribiendo una gran cantidad de código redundante: la creación de una conexión, la creación de un cursor, la ejecución de una sentencia, y el cierre de la conexión. Idealmente, todo lo que tendríamos que hacer es especificar que resultados queremos.</li>
<li>Esto está ligado a MySQL. Si, cambiamos de MySQL a PostgreSQL, vamos a tener que utilizar un adaptador de base de datos diferente, modificar los parámetros de la conexión, y dependiendo de la naturaleza de la instrucción SQL, posiblemente reescribir el código SQL. Idealmente, el servidor de base de datos que estamos utilizando debería abstraerse, de modo que un cambio de servidor de base de datos podría hacerse en un solo lugar. (Esta característica es especialmente útil si usted está construyendo una aplicación Django de fuente abierta que usted desea que sea usada por tanta gente como sea posible.)</li>
</ul>
<p>Como es de esperar, la capa de base de datos de Django tiene por objeto resolver estos problemas. He aquí una vista previa de cómo la vista anterior se puede reescribir utilizando la <strong>API de base de datos de Django</strong>:</p>
<blockquote><p>from django.shortcuts import render_to_response<br />
from mysite.books.models import Book</p>
<p>def book_list(request):</p>
<p style="padding-left:30px;">books = Book.objects.order_by(&#8216;name&#8217;)<br />
return render_to_response(&#8216;book_list.html&#8217;, {&#8216;books&#8217;: books})</p>
</blockquote>
<h3>El patrón de desarrollo MTV (o MVC)</h3>
<p>Antes de profundizar más en el código, vamos a considerar el diseño general de una aplicación web Django controlada por base de datos.</p>
<p>En las funciones de vista, por ejemplo, hablamos de la importancia de separar la lógica de negocio de la lógica de presentación mediante el uso de un sistema de plantillas. Con la capa de base de datos,  aplicaremos la misma filosofía para la lógica de acceso a datos.</p>
<p>Estas tres piezas juntas &#8211; lógica de acceso a datos, lógica de negocio, y la lógica de presentación &#8211; constituyen un concepto que a menudo se denomina <strong>patrón de arquitectura de software Modelo-Vista-Controlador (MVC)</strong>. En este patrón, &#8220;Modelo&#8221; hace referencia a la capa de acceso a datos, &#8220;Vista&#8221; hace referencia a la  parte del sistema que selecciona qué mostrar y cómo mostrarlo, y &#8220;controlador&#8221; hace referencia a la parte del sistema que decide qué vista usar, en función de la entrada del usuario, accediendo al modelo cuando sea necesario.</p>
<p>Django sigue este patrón MVC lo suficientemente cerca que puede ser denominado un marco MVC. Así es más o menos cómo M, V, y C se descomponen en Django:</p>
<ul>
<li>M, la parte de acceso a datos, está a cargo de la capa de base de datos de Django, que se describe en este capítulo.</li>
<li>V, la parte que selecciona los datos para mostrar y cómo mostrarlo, es manejado por las vistas y las plantillas.</li>
<li>C, la parte que delega a una vista en función de la entrada del usuario, es manejado por el marco en sí, siguiendo su URLconf y llamando a la función de Python adecuada para la dirección dada. </li>
</ul>
<p>Debido a que la &#8220;C&#8221; es manejada por el propio marco y la mayor parte de la emoción en Django se produce en los modelos, plantillas, y vistas, Django ha sido denominado como un marco MTV. En el patrón de desarrollo MTV:</p>
<ul>
<li>M significa &#8220;modelo&#8221;, la capa de acceso a datos. Esta capa todo lo relacionado con los datos: cómo acceder a ellos, cómo validarse, las relaciones entre los datos.</li>
<li>T representa &#8220;Plantilla&#8221;, la capa de presentación. Esta capa contiene las decisiones relacionadas con la presentación.</li>
<li>V significa &#8220;Vista&#8221;, la capa de lógica de negocio. Esta capa contiene la lógica que accede al modelo ylo remite a la plantilla adecuada(s). Usted puede verlo como el puente entre los modelos y plantillas.</li>
</ul>
<h3>Configuración de la base de datos</h3>
<p>En primer lugar, tenemos que realizar alguna configuración inicial, debemos decirle a Django qué servidor de base de datos utilizar y cómo conectarse a él.</p>
<p>Al igual que TEMPLATE_DIRS, la configuración de la base de datos reside en el archivo de configuración de Django, llamado <em>settings.py</em> por defecto. Editar el archivo y buscar la configuración de base de datos.</p>
<p>Una vez que haya introducido esa configuración y guarde <em>settings.py</em>, es bueno comprobar su configuración. Para ello, ejecute <strong>python manage.py shell</strong>, dentro del directorio del proyecto <em>mysite</em>.</p>
<blockquote><p>
&gt;&gt;&gt; from django.db import connection<br />
&gt;&gt;&gt; cursor = connection.cursor()
</p></blockquote>
<p>Si no ocurre nada, entonces la base de datos está configurada correctamente. De lo contrario, comprobar el mensaje de error en busca de pistas acerca de lo que está fallando. </p>
<h3>Su primera aplicación</h3>
<p>Ahora que ha verificado que la conexión funciona, es hora de crear una aplicación Django, un paquete de código Django, que incluya modelos y vistas, que residan juntos en un paquete Python único y que representan una aplicación Django completa.</p>
<p>Ya creamos un proyecto en el capítulo 2, ¿cuál es la diferencia entre un proyecto y una aplicación?</p>
<ul>
<li>Un proyecto es una instancia de un determinado conjunto de aplicaciones Django, más la configuración de esas aplicaciones.</li>
<li>Técnicamente, el único requisito de un proyecto es que suministra un archivo de configuración, que define la información de conexión de bases de datos, la lista de aplicaciones instaladas, el TEMPLATE_DIRS, y así sucesivamente.</li>
<li>Una aplicación es un conjunto portátil de funcionalidad Django, que generalmente incluye modelos y vistas, que residen juntos en un paquete único Python.</li>
<li>Por ejemplo, Django viene con una serie de aplicaciones, tales como un sistema de comentarios y una interfaz de administración automática. Un aspecto clave sobre estas aplicaciones es que son portables y reutilizables a través de múltiples proyectos.</li>
</ul>
<p>Si usted está utilizando la capa de base de datos de Django (modelos), debe crear una aplicación Django. Los modelos deben residir dentro de aplicaciones. Así que, para empezar a escribir nuestros modelos, tendremos que crear una aplicación nueva.</p>
<p>En el directorio del proyecto <em>mysite</em>, escriba este comando para <strong>crear una aplicación <em>books</em></strong>: </p>
<blockquote><p>python manage.py startapp books</p></blockquote>
<p>Este comando no produce ningún resultado, pero sí crea un directorio <em>books</em> en el directorio <em>mysite</em>. </p>
<blockquote><p>
books/</p>
<p style="padding-left:30px;">
	__init__.py<br />
	models.py<br />
	tests.py<br />
	views.py</p>
</blockquote>
<p>Esto es el estado en blanco de su aplicación Django.</p>
<h3>Definir modelos en Python</h3>
<p><strong>Un modelo de Django es una descripción de los datos en su base de datos, representada como código Python</strong>. Es su disposición de los datos &#8211; el equivalente de sus sentencias SQL CREATE TABLE, excepto que es en Python en lugar de SQL, y que incluye algo más que definiciones de columna de base de datos. Django usa un modelo para ejecutar código SQL y devolver estructuras de datos Python que representan las filas de las tablas de base de datos. Django también utiliza modelos para representar conceptos de alto nivel que SQL no necesariamente puede manejar. Si usted está familiarizado con bases de datos, su primer pensamiento podría ser: ¿No es redundante la definición de modelos de datos en Python en lugar de en SQL?  Django funciona de manera que lo hace por varias razones:</p>
<ul>
<li>A fin de proporcionar una API de acceso a datos conveniente, Django necesita saber el diseño de la bases de datos de alguna manera, y hay dos maneras de lograr esto. La primera es describir explícitamente los datos en Python, y la segunda es la introspección en la base de datos en tiempo de ejecución para determinar los modelos de datos.</li>
<li>Esta segunda vía parece más limpia, ya que los metadatos residen sólo en un lugar, pero introduce algunos problemas. En primer lugar, la introspección de una base de datos en tiempo de ejecución requiere sobrecarga. Si el marco ha de realizar la introspección cada vez que se procesa una solicitud, incurre en un nivel inaceptable de sobrecarga.  En segundo lugar, algunas bases de datos no guardan los suficientes metadatos para una introspección precisa y completa.</li>
<li>Escribir en Python es divertido, y mantener todo en Python limita el número de veces que su cerebro tiene que hacer un &#8220;cambio de contexto&#8221; lo que ayuda a la productividad.</li>
<li>Contar con modelos de datos almacenados como código en lugar de en su base de datos hace que sea más fácil de mantener sus modelos bajo control de versiones. De esta manera, usted puede fácilmente hacer un seguimiento de los cambios en sus diseños de datos.</li>
<li>SQL permite únicamente un grado determinado de metadatos acerca de un diseño de datos. La mayoría de los sistemas de base de datos, por ejemplo, no ofrecen un tipo de datos especializado para la representación de direcciones de e-mail o URL. Los modelos de Django lo hacen.</li>
<li>SQL es inconsistente a través de plataformas de base de datos. Si está distribuyendo una aplicación Web, por ejemplo, es mucho mejor distribuir un módulo Python que describa su diseño de datos que conjuntos distintos de sentencias CREATE TABLE para MySQL, PostgreSQL, y SQLite.</li>
</ul>
<h3>Su primer modelo</h3>
<p>Nos centraremos en un diseño de datos basado en libro/autor/editor. Usaremos esto como ejemplo, porque las relaciones conceptuales entre libros, autores y editores son bien conocidas.</p>
<p>Vamos a suponer los siguientes conceptos, campos, y relaciones:</p>
<ul>
<li>El autor tiene un nombre, un apellido y una dirección de correo electrónico.</li>
<li>Un editor tiene un nombre, una dirección, ciudad, estado o provincia, un país, y un sitio web.</li>
<li>Un libro tiene un título y una fecha de publicación. También tiene uno o más autores (relación de muchos a muchos con autores) y un solo editor (relación uno a muchos &#8211; clave ajena – con los editores).</li>
</ul>
<p>El primer paso del uso de este diseño de base de datos con Django es expresarlo como código Python. En <em>models.py</em>, el archivo que fue creado por el comando startapp, escriba lo siguiente:</p>
<blockquote><p>
from django.db import models</p>
<p>class Publisher(models.Model):</p>
<p style="padding-left:30px;">
	name = models.CharField(max_length=30)<br />
	address = models.CharField(max_length=50)<br />
	city = models.CharField(max_length=60)<br />
	state_province = models.CharField(max_length=30)<br />
	country = models.CharField(max_length=50)<br />
	website = models.URLField()
</p>
<p>class Author(models.Model):</p>
<p style="padding-left:30px;">
	first_name = models.CharField(max_length=30)<br />
	last_name = models.CharField(max_length=40)<br />
	email = models.EmailField()
</p>
<p>class Book(models.Model):</p>
<p style="padding-left:30px;">
	title = models.CharField(max_length=100)<br />
	authors = models.ManyToManyField(Author)<br />
	publisher = models.ForeignKey(Publisher)<br />
	publication_date = models.DateField()
</p>
</blockquote>
<p>La primera cosa a notar es que cada modelo está representado por una clase Python que es una <strong>subclase de django.db.models.Model</strong>. La clase padre, Model, contiene toda la maquinaria necesaria para hacer que estos objetos sean capaces de interactuar con una base de datos. Lo crea o no, esto es todo el código que tiene que escribir para tener acceso básico a los datos con Django.</p>
<p>Cada modelo corresponde generalmente a una tabla de base de datos única, y cada atributo del modelo generalmente corresponde a una columna de esa tabla de base de datos. El nombre del atributo corresponde al nombre de la columna, y el tipo de campo (por ejemplo, CharField) corresponde al tipo de la columna de base de datos (por ejemplo, varchar). </p>
<p>Django puede generar el comando CREATE TABLE automáticamente, como mostraremos después.</p>
<p>La excepción a la regla de una clase por cada tabla de base de datos es el caso de las relaciones muchos-a-muchos. En nuestro modelo de ejemplo, el libro tiene un campo <em>ManyToMany</em> llamado autores. Esto designa que un libro tiene uno o varios autores, pero la tabla de base de datos Libros no tiene una columna de autores. En lugar de ello, Django crea una tabla adicional, una tabla de referencias cruzadas de muchos-a-muchos , que se encarga del mapeo de los libros a los autores.</p>
<p>Por último, tenga en cuenta que no hemos definido explícitamente una clave primaria en ninguno de estos modelos. A menos que usted lo indique, Django automáticamente le da a cada modelo una clave primaria de entero autonumérico llamado id. <strong>Cada modelo de Django necesita tener una clave primaria de una sola columna</strong>.</p>
<h3>Instalar el modelo</h3>
<p>Ahora vamos a crear las tablas en nuestra base de datos. Con el fin de hacer eso, el primer paso es activar estos modelos en nuestro proyecto Django. Lo hacemos mediante la <strong>adición de la aplicación <em>books</em> a la lista de &#8220;aplicaciones instaladas&#8221; en el archivo de configuración</strong>.</p>
<p>Edite el archivo <em>settings.py</em> de nuevo, y busque la propiedad INSTALLED_APPS, que le dice a Django que aplicaciones están activas para un proyecto determinado. De forma predeterminada, se ve algo como esto:</p>
<blockquote><p>INSTALLED_APPS = (</p>
<p style="padding-left:30px;">&#8216;django.contrib.auth&#8217;,<br />
	&#8216;django.contrib.contenttypes&#8217;,<br />
	&#8216;django.contrib.sessions&#8217;,<br />
	&#8216;django.contrib.sites&#8217;,
</p>
<p>)</p></blockquote>
<p>Temporalmente comentemos las cuatro líneas poniendo una almohadilla (#) al principio de ellos. Comentenmos también la propiedad por defecto MIDDLEWARE_CLASSES.  A continuación, añadir: <em>mysite.books</em> a la lista INSTALLED_APPS, por lo que la propiedad finalmente podría parecerse a esto:</p>
<blockquote><p>MIDDLEWARE_CLASSES = (</p>
<p style="padding-left:30px;"># &#8216;django.middleware.common.CommonMiddleware&#8217;,<br />
	# &#8216;django.contrib.sessions.middleware.SessionMiddleware&#8217;,<br />
	# &#8216;django.contrib.auth.middleware.AuthenticationMiddleware&#8217;,
</p>
<p>)</p>
<p>INSTALLED_APPS = (</p>
<p style="padding-left:30px;"># &#8216;django.contrib.auth&#8217;,<br />
	# &#8216;django.contrib.contenttypes&#8217;,<br />
	# &#8216;django.contrib.sessions&#8217;,<br />
	# &#8216;django.contrib.sites&#8217;,<br />
	&#8216;mysite.books&#8217;,
</p>
<p>)</p></blockquote>
<p>Ahora que la aplicación Django se ha activado en el archivo de configuración, podemos crear las tablas de base de datos en nuestra base de datos. En primer lugar, vamos a <strong>validar los modelos</strong> con la ejecución de este comando:</p>
<blockquote><p>python manage.py validate</p></blockquote>
<p>Si sus modelos son válidos, ejecute el comando siguiente para que Django genere las declaraciones CREATE TABLE de los modelos de la aplicación books:</p>
<blockquote><p>python manage.py sqlall books</p></blockquote>
<p>El comando <em>sqlall</em> en realidad no crea las tablas en su base de datos &#8211; sólo imprime en pantalla la salida para que pueda ver el SQL que Django ejecutaría. Si quisiera, podría copiar y pegar este SQL en su cliente de base de datos. Sin embargo, Django proporciona una manera más fácil de llevar a cabo las sentencias SQL en la base de datos: el comando <em>syncdb</em>:</p>
<blockquote><p>python manage.py syncdb</p></blockquote>
<p>Ejecutando ese comando verá algo como esto:</p>
<blockquote><p>Creating table books_publisher<br />
Creating table books_author<br />
Creating table books_book<br />
Installing index for books.Book model
</p></blockquote>
<p>El comando <em>syncdb</em> es una simple &#8220;sincronización&#8221; de sus modelos a su base de datos. Busca en todos los modelos de cada aplicación en su propiedad INSTALLED_APPS, comprueba la base de datos para ver si las tablas apropiadas existen ya, y crea las tablas si no existen aún. Tenga en cuenta que <em>syncdb</em> no sincroniza los cambios en los modelos o las eliminaciones de los modelos; si usted hace un cambio a un modelo o elimina un modelo, y desea actualizar la base de datos, <em>syncdb</em> no gestionará eso.</p>
<h3>Acceso básico a datos</h3>
<p>Una vez que ha creado un modelo, Django proporciona automáticamente una API de alto nivel Python para trabajar con esos modelos. Pruébelo mediante la ejecución de <strong>python manage.py shell</strong> y escribiendo lo siguiente: </p>
<blockquote><p>>>> from books.models import Publisher<br />
>>> p1 = Publisher(name=&#8217;Apress&#8217;, address=&#8217;2855 Telegraph Avenue&#8217;,<br />
&#8230; 	city=&#8217;Berkeley&#8217;, state_province=&#8217;CA&#8217;, country=&#8217;U.S.A.&#8217;,<br />
&#8230; 	website=&#8217;http://www.apress.com/&#8217;)<br />
>>> p1.save()<br />
>>> p2 = Publisher(name=&#8221;O&#8217;Reilly&#8221;, address=&#8217;10 Fawcett St.&#8217;,<br />
&#8230; 	city=&#8217;Cambridge&#8217;, state_province=&#8217;MA&#8217;, country=&#8217;U.S.A.&#8217;,<br />
&#8230; 	website=&#8217;http://www.oreilly.com/&#8217;)<br />
>>> p2.save()<br />
>>> publisher_list = Publisher.objects.all()<br />
>>> publisher_list<br />
[&lt;Publisher: Publisher object&gt;, &lt;Publisher: Publisher object&gt;]
</p></blockquote>
<p>Cuando crea objetos utilizando la API de modelos de Django, Django no guarda los objetos en la base de datos hasta que llama al <strong>método save()</strong>:</p>
<blockquote><p>p1 = Publisher(&#8230;)<br />
# At this point, p1 is not saved to the database yet!<br />
p1.save()<br />
# Now it is.</p></blockquote>
<p>Si desea crear un objeto y guardarlo en la base de datos en un solo paso, use el <strong>método objects.create()</strong>. Este ejemplo es equivalente al anterior:</p>
<blockquote><p>>>> p1 = Publisher.objects.create(name=&#8217;Apress&#8217;,<br />
&#8230; 	address=&#8217;2855 Telegraph Avenue&#8217;,<br />
&#8230; 	city=&#8217;Berkeley&#8217;, state_province=&#8217;CA&#8217;, country=&#8217;U.S.A.&#8217;,<br />
&#8230; 	website=&#8217;http://www.apress.com/&#8217;)<br />
>>> p2 = Publisher.objects.create(name=&#8221;O&#8217;Reilly&#8221;,<br />
&#8230; 	address=&#8217;10 Fawcett St.&#8217;, city=&#8217;Cambridge&#8217;,<br />
&#8230; 	state_province=&#8217;MA&#8217;, country=&#8217;U.S.A.&#8217;,<br />
&#8230; 	website=&#8217;http://www.oreilly.com/&#8217;)<br />
>>> publisher_list = Publisher.objects.all()<br />
>>> publisher_list</p></blockquote>
<h3>Añadir representaciones de cadena del Modelo</h3>
<p>Cuando mostramos la lista de editores, todo lo que obtuvimos en pantalla fue una vista inútil que hace difícil distinguir los objetos Publisher: </p>
<blockquote><p>[&lt;Publisher: Publisher object&gt;, &lt;Publisher: Publisher object&gt;]</p></blockquote>
<p>Podemos solucionar este problema fácilmente mediante la adición de un <strong>método</strong> llamado <strong>__unicode__()</strong> a nuestra clase Publisher. Un método __unicode__() le dice a Python cómo mostrar la representación &#8220;Unicode&#8221; de un objeto.</p>
<p>Puede ver esto en acción añadiendo un __unicode__()  para los tres modelos:</p>
<blockquote><p>from django.db import models</p>
<p>class Publisher(models.Model):</p>
<p style="padding-left:30px">	name = models.CharField(max_length=30)</p>
<p style="padding-left:30px">address = models.CharField(max_length=50)</p>
<p style="padding-left:30px">city = models.CharField(max_length=60)</p>
<p style="padding-left:30px">state_province = models.CharField(max_length=30)</p>
<p style="padding-left:30px">country = models.CharField(max_length=50)</p>
<p style="padding-left:30px">website = models.URLField()</p>
<p style="padding-left:30px">def __unicode__(self):</p>
<p style="padding-left:60px">	return self.name</p>
</p>
<p>class Author(models.Model):</p>
<p style="padding-left:30px">	first_name = models.CharField(max_length=30)</p>
<p style="padding-left:30px">last_name = models.CharField(max_length=40)</p>
<p style="padding-left:30px">email = models.EmailField()</p>
<p style="padding-left:30px">	def __unicode__(self):</p>
<p style="padding-left:60px">return u&#8217;%s %s&#8217; % (self.first_name, self.last_name)</p>
<p>class Book(models.Model):</p>
<p style="padding-left:30px">	title = models.CharField(max_length=100)</p>
<p style="padding-left:30px">authors = models.ManyToManyField(Author)</p>
<p style="padding-left:30px">publisher = models.ForeignKey(Publisher)</p>
<p style="padding-left:30px">publication_date = models.DateField()</p>
<p style="padding-left:30px">def __unicode__(self):</p>
<p style="padding-left:60px">return self.title</p>
</blockquote>
<p>Para que los cambios __unicode__() surtan efecto, salga de la shell de Python y entre de nuevo. (Esta es la forma más sencilla de hacer cambios en el código actual.) Ahora la lista de objetos Publisher es mucho más fácil de entender:</p>
<blockquote><p>>>> from books.models import Publisher<br />
>>> publisher_list = Publisher.objects.all()<br />
>>> publisher_list<br />
[&lt;Publisher: Apress&gt;, &lt;Publisher: O'Reilly&gt;]
</p></blockquote>
<p>Notar que __unicode__() es un buen ejemplo de añadir comportamiento a los modelos. Un modelo Django describe más que el diseño de la tabla de base de datos de un objeto, sino también cualquier funcionalidad de un objeto que sepa hacer.  __unicode__() es un ejemplo de funcionalidad de este tipo;  un modelo sabe cómo mostrarse a sí mismo.</p>
<h3>Insertar y actualizar datos</h3>
<p>Para insertar una fila en la base de datos, primero debe crear una instancia de su modelo con argumentos de clave, así:</p>
<blockquote><p>>>> p = Publisher(name=&#8217;Apress&#8217;,<br />
&#8230; 	address=&#8217;2855 Telegraph Ave.&#8217;,<br />
&#8230; 	city=&#8217;Berkeley&#8217;,<br />
&#8230; 	state_province=&#8217;CA&#8217;,<br />
&#8230; 	country=&#8217;U.S.A.&#8217;,<br />
&#8230; 	website=&#8217;http://www.apress.com/&#8217;)
 </p></blockquote>
<p>Este acto de crear instancias de un modelo de clase no afecta a la base de datos. El registro no se guarda en la base de datos hasta que llame a <strong>save()</strong>: </p>
<blockquote><p>>>> p.save()</p></blockquote>
<p>Debido a que el modelo utiliza un ID de clave primaria autonumérica, la llamada inicial a save() hace una cosa más: calcula el valor de clave principal para el registro y lo coloca en el  atributo id de la instancia: </p>
<blockquote><p>>>> p.id<br />
52 # this will differ based on your own data
</p></blockquote>
<p>Las llamadas posteriores a save() van a guardar el registro, sin crear un nuevo registro (es decir, realizar una instrucción SQL UPDATE en lugar de un INSERT).</p>
<blockquote><p>>>> p.name = &#8216;Apress Publishing&#8217;<br />
>>> p.save()
</p></blockquote>
<p>Tenga en cuenta que todos los campos serán actualizados, y no sólo los que han sido cambiados.</p>
<h3>Seleccionar objetos</h3>
<p>Saber cómo crear y actualizar los registros de base de datos es esencial, pero es probable que las aplicaciones web que usted construya serán de hacer más consultas de los objetos existentes que de crear nuevos. Ya ha visto una manera de recuperar todos los registros para un determinado modelo:</p>
<blockquote><p>>>> Publisher.objects.all()<br />
[&lt;Publisher: Apress&gt;, &lt;Publisher: O'Reilly&gt;]
</p></blockquote>
<p>Trasladado a SQL sería:</p>
<blockquote><p>SELECT id, name, address, city, state_province, country, website<br />
FROM books_publisher;
</p></blockquote>
<h3>Filtrar datos</h3>
<p>Naturalmente, es raro que desee seleccionar todo de una base de datos a la vez; en la mayoría de los casos, usted querrá tratar con un subconjunto de los datos. En la API de Django, puede filtrar los datos utilizando el <strong>método filter()</strong>: </p>
<blockquote><p>>>> Publisher.objects.filter(name=&#8217;Apress&#8217;)<br />
[&lt;Publisher: Apress&gt;]</p></blockquote>
<p>filter() toma los argumentos que se traducen en las cláusulas where de SQL apropiadas. El ejemplo anterior se traduciría en algo como:</p>
<blockquote><p>SELECT id, name, address, city, state_province, country, website<br />
FROM books_publisher<br />
WHERE name = &#8216;Apress&#8217;;
</p></blockquote>
<p>Se pueden pasar múltiples argumentos a filter() para reducir aún más las cosas:</p>
<blockquote><p>>>> Publisher.objects.filter(country=&#8221;U.S.A.&#8221;, state_province=&#8221;CA&#8221;)<br />
[&lt;Publisher: Apress&gt;]
</p></blockquote>
<p>Los múltiples argumentos se traducen en cláusulas AND de SQL. Así, el ejemplo se traduce en:</p>
<blockquote><p>SELECT id, name, address, city, state_province, country, website<br />
FROM books_publisher<br />
WHERE country = &#8216;U.S.A.&#8217;<br />
AND state_province = &#8216;CA&#8217;;
</p></blockquote>
<p>Tenga en cuenta que por defecto las búsquedas utilizan el operador = de SQL para hacer búsquedas de concordancia exacta. Otros tipos de búsqueda están disponibles:</p>
<blockquote><p>>>> Publisher.objects.filter(name__contains=&#8221;press&#8221;)<br />
[&lt;Publisher: Apress&gt;]
</p></blockquote>
<p>Hay un doble subrayado entre name y contains. Aquí, la parte<strong> __contains</strong> es traducida por Django en una sentencia LIKE de SQL: </p>
<blockquote><p>SELECT id, name, address, city, state_province, country, website<br />
FROM books_publisher<br />
WHERE name LIKE &#8216;%press%&#8217;;
</p></blockquote>
<p>Muchos otros tipos de búsquedas están disponibles, incluyendo icontains (LIKE insensible a mayúsculas/minúsculas), startswith y endswith, y range (consultas BETWEEN de SQL).</p>
<h3>Recuperar objetos individuales</h3>
<p>El ejemplos de filter() anteriores devolvían un <em>QuerySet</em>, que se puede tratar como una lista. A veces es más conveniente extraer solamente un objeto individual en lugar de una lista. Para eso está el <strong>método get()</strong>: </p>
<blockquote><p>>>> Publisher.objects.get(name=&#8221;Apress&#8221;)<br />
&lt;Publisher: Apress&gt;
</p></blockquote>
<p>Una consulta que devuelva varios objetos producirá una excepción:</p>
<blockquote><p>>>> Publisher.objects.get(country=&#8221;U.S.A.&#8221;)<br />
Traceback (most recent call last):<br />
	&#8230;<br />
MultipleObjectsReturned: get() returned more than one Publisher &#8211;<br />
	it returned 2! Lookup parameters were {&#8216;country&#8217;: &#8216;U.S.A.&#8217;}
</p></blockquote>
<p>Una consulta que no devuelva objetos también causará una excepción:</p>
<blockquote><p>>>> Publisher.objects.get(name=&#8221;Penguin&#8221;)<br />
Traceback (most recent call last):<br />
	&#8230;<br />
DoesNotExist: Publisher matching query does not exist.
</p></blockquote>
<p>La excepción <em>DoesNotExist</em> es un atributo de la clase del modelo: Publisher.DoesNotExist. En sus aplicaciones, usted querrá atrapar estas excepciones, de esta forma:</p>
<blockquote><p>
try:</p>
<p style="padding-left:30px;">p = Publisher.objects.get(name=&#8217;Apress&#8217;)</p>
<p>except Publisher.DoesNotExist:</p>
<p style="padding-left:30px;">print &#8220;Apress isn&#8217;t in the database yet.&#8221;</p>
<p>else:</p>
<p style="padding-left:30px;">print &#8220;Apress is in the database.&#8221;</p>
</blockquote>
<h3>Ordenar datos</h3>
<p>En los ejemplos anteriores, usted puede descubrir que los objetos se devuelven en un orden aparentemente al azar. Estamos simplemente devolviendo los datos en un orden arbitrario elegido por la base de datos. En sus aplicaciones Django, usted probablemente querrá pedir sus resultados de acuerdo a un cierto criterio &#8211; por ejemplo, por orden alfabético. Para ello, utilizar el método <strong>order_by()</strong>:</p>
<blockquote><p>>>> Publisher.objects.order_by(&#8220;name&#8221;)<br />
[&lt;Publisher: Apress&gt;, &lt;Publisher: O'Reilly&gt;]
</p></blockquote>
<p>Esto no parece muy diferente del all() del ejemplo anterior, pero el SQL ahora incluye un orden específico:</p>
<blockquote><p>SELECT id, name, address, city, state_province, country, website<br />
FROM books_publisher<br />
ORDER BY name;
</p></blockquote>
<p>Puede ordenar por el campo que quiera:</p>
<blockquote><p>>>> Publisher.objects.order_by(&#8220;address&#8221;)<br />
[&lt;Publisher: O'Reilly&gt;, &lt;Publisher: Apress&gt;]</p>
<p>>>> Publisher.objects.order_by(&#8220;state_province&#8221;)<br />
[&lt;Publisher: Apress&gt;, &lt;Publisher: O'Reilly&gt;]
</p></blockquote>
<p>Para ordenar por múltiples campos usar varios argumentos:</p>
<blockquote><p>>>> Publisher.objects.order_by(&#8220;state_province&#8221;, &#8220;address&#8221;)<br />
[&lt;Publisher: Apress&gt;, &lt;Publisher: O'Reilly&gt;]
</p></blockquote>
<p>También puede especificar orden inverso anteponiendo al nombre del campo un &#8211; (esto es un signo menos): </p>
<blockquote><p>>>> Publisher.objects.order_by(&#8220;-name&#8221;)<br />
[&lt;Publisher: O'Reilly&gt;, &lt;Publisher: Apress&gt;]
</p></blockquote>
<p>Si bien esta flexibilidad es útil, utilizar order_by() todo el tiempo puede ser bastante repetitivo. La mayoría de las veces tendrá un campo particular por el querrá ordenar. En estos casos, Django permite especificar una ordenación predeterminada en el modelo:</p>
<blockquote><p>
class Publisher(models.Model):</p>
<p style="padding-left:30px;">name = models.CharField(max_length=30)</p>
<p style="padding-left:30px;">address = models.CharField(max_length=50)</p>
<p style="padding-left:30px;">city = models.CharField(max_length=60)</p>
<p style="padding-left:30px;">state_province = models.CharField(max_length=30)</p>
<p style="padding-left:30px;">country = models.CharField(max_length=50)</p>
<p style="padding-left:30px;">website = models.URLField()</p>
<p style="padding-left:30px;">def __unicode__(self):</p>
<p style="padding-left:60px;">return self.name</p>
<p style="padding-left:30px;">class Meta:</p>
<p style="padding-left:60px;">ordering = ['name']</p>
</blockquote>
<p>En este caso, hemos introducido un nuevo concepto: la <strong>clase Meta</strong>, que es una clase que está incrustada dentro de la definición de la clase Publisher. Usted puede utilizar la clase Meta en cualquier modelo para especificar opciones específicas del modelo.</p>
<p>Si se especifica esto, le dice a Django que a menos que se indique un ordenamiento de forma explícita con order_by(), todos los objetos Publisher deben ser ordenados por el campo name cada vez que se  recuperen con la API de Base de Datos de Django.</p>
<h3>Encadenar búsquedas</h3>
<p>Hemos visto como filtrar datos y como ordenarlos. A menudo necesitaremos ambos. En estos casos, encadenar las búsquedas:</p>
<blockquote><p>>>> Publisher.objects.filter(country=&#8221;U.S.A.&#8221;).order_by(&#8220;-name&#8221;)<br />
[&lt;Publisher: O'Reilly&gt;, &lt;Publisher: Apress&gt;]
</p></blockquote>
<p>Esto se convierte a una sentencia SQL con WHERE y ORDER BY:</p>
<blockquote><p>SELECT id, name, address, city, state_province, country, website<br />
FROM books_publisher<br />
WHERE country = &#8216;U.S.A&#8217;<br />
ORDER BY name DESC;
</p></blockquote>
<h3>Trocear datos</h3>
<p>Otra necesidad común es buscar sólo un número fijo de filas. Imagina que tiene miles de editores en su base de datos, pero que desea mostrar sólo el primero. Usted puede hacerlo con esta sintaxis:</p>
<blockquote><p>>>> Publisher.objects.order_by(&#8216;name&#8217;)[0]<br />
&lt;Publisher: Apress&gt;
</p></blockquote>
<p>Esto se traduce en:</p>
<blockquote><p>SELECT id, name, address, city, state_province, country, website<br />
FROM books_publisher<br />
ORDER BY name<br />
LIMIT 1;
</p></blockquote>
<p>De igual forma, usted puede recuperar un subconjunto específico de datos:</p>
<blockquote><p>>>> Publisher.objects.order_by(&#8216;name&#8217;)[0:2]</p></blockquote>
<p>Esto devuelve 2 objetos, y se traduce en:</p>
<blockquote><p>SELECT id, name, address, city, state_province, country, website<br />
FROM books_publisher<br />
ORDER BY name<br />
OFFSET 0 LIMIT 2;
</p></blockquote>
<p>Tener en cuenta que el índice negativo no está soportado:</p>
<blockquote><p>>>> Publisher.objects.order_by(&#8216;name&#8217;)[-1]<br />
Traceback (most recent call last):<br />
&#8230;<br />
AssertionError: Negative indexing is not supported.
</p></blockquote>
<p>Esto es fácil de conseguir, sin embargo. Sólo cambiar la sentencia order_by() de esta forma: </p>
<blockquote><p>>>> Publisher.objects.order_by(&#8216;-name&#8217;)[0]</p></blockquote>
<h3>Actualizar varios objetos en una sentencia</h3>
<p>Hemos señalado en la sección &#8220;Inserción y actualización de datos&#8221; que el método save() del modelo actualiza todas las columnas de una fila. Dependiendo de su aplicación, es posible que desee actualizar sólo un subconjunto de columnas.</p>
<p>Por ejemplo, supongamos que usted desea actualizar la editorial Apress para cambiar el nombre de &#8216;Apress&#8217; a &#8216;Apress Publishing&#8217;. Usando save(), se vería algo como esto:</p>
<blockquote><p>>>> p = Publisher.objects.get(name=&#8217;Apress&#8217;)<br />
>>> p.name = &#8216;Apress Publishing&#8217;<br />
>>> p.save()
</p></blockquote>
<p>Esto se traduce en el siguiente SQL:</p>
<blockquote><p>SELECT id, name, address, city, state_province, country, website<br />
FROM books_publisher<br />
WHERE name = &#8216;Apress&#8217;;</p>
<p>UPDATE books_publisher SET</p>
<p style="padding-left:30px;">name = &#8216;Apress Publishing&#8217;,</p>
<p style="padding-left:30px;">address = &#8217;2855 Telegraph Ave.&#8217;,</p>
<p style="padding-left:30px;">city = &#8216;Berkeley&#8217;,</p>
<p style="padding-left:30px;">state_province = &#8216;CA&#8217;,</p>
<p style="padding-left:30px;">country = &#8216;U.S.A.&#8217;,</p>
<p style="padding-left:30px;">website = &#8216;http://www.apress.com&#8217;</p>
<p>WHERE id = 52;
</p></blockquote>
<p>El método save() de Django establece todos los valores de las columnas, no sólo la columna name. Si está en un entorno en el que otras columnas de la base de datos podrían cambiar a causa de algún otro proceso, es más inteligente cambiar sólo la columna que usted necesita. Para ello, utilice el método update() en objetos QuerySet. He aquí un ejemplo:</p>
<blockquote><p>>>> Publisher.objects.filter(id=52).update(name=&#8217;Apress Publishing&#8217;)</p></blockquote>
<p>La traducción a SQL es mucho más eficiente y no provoca efectos laterales:</p>
<blockquote><p>UPDATE books_publisher<br />
SET name = &#8216;Apress Publishing&#8217;<br />
WHERE id = 52;
</p></blockquote>
<p>El método update() funciona en cualquier <em>QuerySet</em>, lo que significa que usted puede editar varios registros de forma masiva. He aquí cómo usted puede cambiar el país de &#8216;U.S.A.&#8217; a &#8216;USA&#8217; en todos los registros Publisher:</p>
<blockquote><p>>>> Publisher.objects.all().update(country=&#8217;USA&#8217;)<br />
2</p></blockquote>
<p>El método update() devuelve un valor: un entero que representa cuántos registros han cambiado. En el ejemplo anterior, fue 2.</p>
<h3>Eliminar objetos</h3>
<p>Para eliminar un objeto de la base de datos, simplemente llamar al <strong>método delete()</strong>:</p>
<blockquote><p>>>> p = Publisher.objects.get(name=&#8221;O&#8217;Reilly&#8221;)<br />
>>> p.delete()<br />
>>> Publisher.objects.all()<br />
[&lt;Publisher: Apress Publishing&gt;]
</p></blockquote>
<p>También puede eliminar objetos de forma masiva llamando al método delete() del resultado de cualquier QuerySet. Esto es similar al método update() que vimos en la última sección:</p>
<blockquote><p>>>> Publisher.objects.filter(country=&#8217;USA&#8217;).delete()<br />
>>> Publisher.objects.all().delete()<br />
>>> Publisher.objects.all()<br />
[]
</p></blockquote>
<p>Tenga cuidado al borrar sus datos. Como medida de precaución contra la supresión de todos los datos de una tabla particular, Django requiere que use explícitamente el método all() si desea borrar toda su tabla. Por ejemplo, esto no funciona:</p>
<blockquote><p>>>> Publisher.objects.delete()<br />
Traceback (most recent call last):<br />
	File &#8220;<console>&#8220;, line 1, in <module><br />
AttributeError: &#8216;Manager&#8217; object has no attribute &#8216;delete&#8217;
</p></blockquote>
<p>Pero funciona si le añade el <strong>método all()</strong>:</p>
<blockquote><p>>>> Publisher.objects.all().delete()</p></blockquote>
<p>Si está eliminando sólo un subconjunto de datos, no es necesario incluir all():</p>
<blockquote><p>>>> Publisher.objects.filter(country=&#8217;USA&#8217;).delete()</p></blockquote>
<h3>Enlaces Relacionados:</h3>
<ul>
<li><a href="http://www.cibernatural.com/tutorial-de-django-i">Tutorial de Django I</a></li>
<li><a href="http://www.cibernatural.com/tutorial-de-django-ii">Tutorial de Django II</a></li>
<li><a href="http://www.cibernatural.com/tutorial-de-django-iii">Tutorial de Django III</a></li>
<li>Tutorial de Django IV</li>
<li><a href="http://www.cibernatural.com/tutorial-de-django-v">Tutorial de Django V</a></li>
<li><a href="http://www.cibernatural.com/tutorial-de-django-vi">Tutorial de Django VI</a></li>
<li><a href="http://www.cibernatural.com/tutorial-de-django-vii">Tutorial de Django VII</a></li>
</ul>

                            <div id="aspdf">
                                <a href="http://www.cibernatural.com/wp-content/plugins/as-pdf/generate.php?post=560">
                                    <span>Descargar en PDF</span>
                                </a>
                            </div>
                        ]]></content:encoded>
			<wfw:commentRss>http://www.cibernatural.com/tutorial-de-django-iv/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

