introducciÓn a django - o2w.es es un helper con opciones para crear proyectos y apps. ......
TRANSCRIPT
2 . 2
1.0.1 DJANGO
Framework de desarrollo web de servidor muy potente.
Escrito en pythonEstilo MVCNombrado así en alusión a Django Reinhardt(guitarrista de jazz)Creado en 2005 para gestionar sitios de noticiasonline.Bajo licencia BSD
2 . 3
1.0.2 QUIEN USA DJANGO
La NASA crea las webs en django.PinterestInstagramTodas las webs de mozilla (disponibles en github)Muchas webs de google (las hace potato)The Washington PostThe GuardianTicketeaetc…
2 . 4
1.0.3 ESTÁ COMPUESTO POR
Modelos (ORM)Vistas (Views)Plantillas (Templates)Formularios (Forms)AdminMiddlewaresGestión de cache
2 . 6
1.0.5 MÁS
SesionesSerializaciónSitemapsGestión de ficheros estáticosValidación de datosTipos genéricosSeñales…
2 . 7
1.0.6 ESTRUCTURA BÁSICA
Con�guraciónArchivo o archivos en los que se define laconfiguración
UrlsSe usa uno principal que se especifica en el settings.
ModelosDefinen nuestros modelos de la base de datos.
VistasContienen la lógica
TemplatesLa capa de presentación
2 . 8
1.0.7 URLS
Con el archivo de urls lo que hacemos es vincular las urlsa acciones, o sea a vistas (views).
my_app/urls.py
urlpatterns = [ url(r'̂download/(?P<uuid>[\w]+)/$', views.download, name='download'), url(r'̂', include('web.urls')), url(r'̂ckeditor/', include('ckeditor.urls')), url(r'̂admin/', include(admin.site.urls)),]
2 . 9
1.0.8 MODELOSEjemplo de modelo, normalmente en models.py
class Log(models.Model): tarea = models.ForeignKey(Tarea, null=True, blank=True) accion = models.ForeignKey(Accion, null=True, blank=True) para = models.CharField(null=True, blank=True, max_length=255) asunto = models.CharField(null=True, blank=True, max_length=255)
def __str__(self,): return "Tarea {} - para {} - {}".format(self.tarea, self.para, self.asunto)
Los modelos son clases en python que modelan algo delmundo real. Estos modelos persisten en una base de
datos.
2 . 10
1.0.9 TEMPLATES
Normalmente desde las vistas:
Vamos a acceder a los modelos de la base de datosusando el orm.Con los datos obtenidos creamos lo que se llama uncontextoRenderizamos html con el template y la informacióndel contextoDevolvemos el html en un HttpResponse
2 . 11
1.0.10 EJEMPLO DE PLANTILLAS_base.html
<!DOCTYPE html>{% load static %}<html lang="es"> <head> <link href="{% static "css/main.css" %}" type="text/css"> </head> <body> {% block body %}{% endblock %} </body></html>
index.html
{% extends '_base.html' %}{% block body %}<h1>Hola mundo</h1>{% endblock %}
2 . 12
1.0.11 VISTAS
Las vistas son clases o funciones que devuelven unhttpResponse, normalmente con html.
2 . 13
1.0.12 EJEMPLOS DE VISTASEjemplo de una vista que usa Class Base View
class EnlacesView(ListView): template_name = '_enlaces.html' model = Enlaces
class IndexView(TemplateView): template_name = 'index.html'
enlaces = EnlacesView.as_view()index = IndexView.as_view()
Ejemplo de otra con un decorador.
@render_to('map.html')def map(request): country = request.GET.get('country', '') countries = models.Country.objects\ .filter(name__in=['IRELAND', 'N IRELAND', 'UK']) return { 'countries': countries, 'selected_country': country }
2 . 14
1.0.13 EJEMPLO DE VISTAEjemplo de una vista que descarga un pdf
class DownloadView(DetailView): model = Url slug_field = 'uuid' slug_url_kwarg = 'uuid'
def get_object(self,): obj = super(DownloadView, self).get_object() return obj.get_object()
def get(self, request, *args, **kwargs): obj = self.get_object() response = HttpResponse(content_type='application/pdf') response['Content-Disposition'] = 'attachment; filename="descarga.pdf"' response.write(obj.get_pdf() return response
download = DownloadView.as_view()
urls.py para la vista anterior
from . import viewsurlpatterns = [ url(r'̂download/(?P<uuid>[\w]+)/$', views.download, name='download'),]
2 . 15
1.0.14 BASES DE DATOS EN DJANGO
PostgresLa bd recomendada, la mejor soportada en django.
Mysqlbien soportada
SQLiteEmpleada para tests o entornos de desarrollomayormente.
OracleVersión 11.2 y superior
2 . 16
1.0.15 ORM
El orm abstrae las consultas de de sql. Esto nos damuchas ventajas … y algunos inconvenientes.
Al abstraer sql hacemos el código portable paracualquier base de datos.Conceptualmente es más fácil de manejar.Trabajas con términos relacionados con el dominio dela aplicación.
2 . 17
1.0.16 EJEMPLOSQueryset devuelve una secuencia de modelos de tipo servicio.
queryset = Servicio.objects\ .no_programados\ .ignorar_gruas_de_traslados\ .no_tareas\ .no_salidas_de_base\ .filter(pendiente=False)\ .filter(anulado=False)\ .exclude(fecha_localizacion__isnull=True)
if condicion: queryset = queryset.exclude(excluido=True)
2 . 18
1.0.17 EJEMPLOSModificamos el servicio y guardamos los datos en la bd.
servicio = Servicio.objects.first()servicio.excluido = Trueservicio.save()
Creamos un servicio
servicio = Servicio.objects.create(nombre="Prueba", fecha=timezone.now(), pendiente=True)
3 . 1
2 INSTALACIÓNPara instalar django normalmente se usa virtualenv.
Es una especie de contenedor que hace que laslibrerías se instalen dentro del directorio indicado. Asípodemos tener diferentes versiones de una librería envarios proyectos.
Creación de un un virtualenv e instalamos django
# Creamosvirtualenv .
# Activamossource bin/activate
# Instalamos appspip install django==1.10.1
3 . 2
2.0.1 REQUIREMENTS
Por convención se usa un archivo en el raíz del proyectodónde se especifican los requerimientos del mismos
requirements.txtel archivo requirements.txt contiene las dependencias de la aplicación.
django==1.7.3djangocms-admin-styledjangorestframework==2.4.4
Es aconsejable especificar las versiones
Se instalan usando pip install -r requirements.txt
3 . 3
2.0.2 CREACIÓN DE UN PROYECTO
Una vez que hemos instalado django usandorequirements o pip install django, podemos usar
django-admin es un helper con opciones para crear proyectos y apps.
django-admin startproject miapp .
Esta instrucción nos creará una estructura de directoriossimilar a esta.Estructura de un proyecto
manage.pymiapp/├── __init__.py├── settings.py├── urls.py└── wsgi.py
3 . 4
2.0.3 SETTINGS
Bastante complejo y largo, lo bueno es que se parecerábastante en muchos proyectos.
3 . 5
2.0.4 INSTALLED_APPSUna variable importante es la que contiene las aplicaciones que carga django.
INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'polls',)
Contiene las aplicaciones que carga django.
3 . 6
2.0.5 DATABASESLa variable databases sirve para configurar las bases de datos, podemos tener varias.
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'principal', 'USER': 'root', 'PASSWORD': '', 'HOST': 'localhost', }, 'secundaria': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'NAME': 'secundaria', 'USER': 'user', 'PASSWORD': 'pass', 'HOST': '192.168.200.219', },}
Normalmente se controla el comportamiento con losrouters, también se puede manualmente.
3 . 7
2.0.6 OTROS
CACHESConfiguramos las caches, memcached o redis, etc.
DEBUGPara activar debug
LANGUAGE_CODELenguaje por defecto de la app
LANGUAGESLista de idiomas
MIDDLEWARE_CLASSESListado de clases que pueden modificar la petición ola respuesta.
ROOT_URLCONFArchivo dónde se configuran las urls.
3 . 8
2.0.7 ¿CÓMO EMPEZAR?
Pensar como la app va a interactuar con el exterior (lasurls).Definir los modelos de datos.Definir las vistas.Crear las plantillas.
3 . 9
2.0.8 POR DÓNDE EMPEZAR
Lo anteriormente comentado lo podemos encontrar enlos siguientes archivos
urls.pymodels.pyviews.pytemplates
4 . 1
3 MODELOSLos modelos son clases que son subclases dedjango.db.models.ModelCada atributo representa un campo de la base dedatos.
Ejemplo de un modelo con dos campos.
from django.db import models
class Person(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=30)
4 . 2
3.0.1 TIPOS DE CAMPOS MÁS USADOS (FIELDS)
BooleanFieldCharFieldDateField, DateTimeField, TimeFieldDecimalFieldEmailField y URLFieldFileField e ImageFieldFloatFieldIntegerFieldSlugFieldTextField
4 . 4
3.0.3 RELACCIONES
ForeignKeyRelaciones entre modelos (1 a n)
ManyToManyFieldRelacciones (m a n)
OneToOneFieldRelacción (1 a 1)
Ejemplo de uso de campos relacionales.
staff_member = models.ForeignKey(User, limit_choices_to={'is_staff': True})friends = models.ManyToManyField("self")user = models.OneToOneField(settings.AUTH_USER_MODEL)
4 . 5
3.0.4 MIGRACIONES
A partir de django 1.7 (antes south)Las migraciones, son la manera de propagar loscambios de los modelos en la base da datos. De estamanera, las bases de datos se van adaptandoautomáticamente a los cambios que ocurren en losmodelos.
5 . 1
3.1 USOComando que crea una migración (cambios o creación) para una aplicación.
./manage.py makemigrations [app]
Se usa para crear migraciones de los modelos de unaapp, es necesario especificarla se se trata de una appnueva que no tiene migraciones. Si ya tiene, y noespecificamos [app] se aplica a todas.
Aplica las migraciones que no están aplicadas a la base de datos.
./manage.py migrate [app]
Ejecuta las migraciones contra la base de datos. Sólolas que no se han procesado ya.
5 . 2
3.1.1 JUGAR CON EL MODELO
Usando el shellPodemos interactuar directamente con django a través del shell
./manage.py shell
Crear un 3 clientes nuevos.Buscar el cliente con más trabajadores.Darlo de baja (activo = False)
5 . 3
3.1.2 REPASO ORM
�lterFiltra
excludeFiltra excluyendo según las condiciones
create, delete, updateCreación, borrado, modificación
get, get_or_createObtiene una instancia, en el segundo caso si noexiste lo crea.
�rst, lastEl primero y último del queryset
5 . 4
3.1.3 REPASO ORM (2)
earliest, latestPrimero y último según campo especificado
existsDevuelve si existe la queryset
countDevuelve el total de instancias de modelo delqueryset
order_byOrdena queryset, "-campo" para inverso.
usingLa usamos si queremos que la queryset use otra dbdiferente a default
5 . 5
3.1.4 SE PUEDEN CREAR NUEVOS MÉTODOS PARA ELQUERYSET
Por defecto los modelos tienen un manager, podemoscambiarlo por otro creando nuevos métodos o usando
filtros por defecto.Ejemplo de creación de queryset personalizados.
class PersonQuerySet(models.QuerySet): def __init__(self): return super().__init__().filter(role__in=['A', 'E'])
def authors(self): return self.filter(role='A')
def editors(self): return self.filter(role='E')
class Person(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) role = models.CharField(max_length=1, choices=(('A', _('Author')), ('E', _('Editor')))) objects = PersonQuerySet.as_manager()
5 . 6
3.1.5 EXPRESIONES DEL ORM
Son de la forma�eld__lookuptype=value
lookuptypes exact, iexact, contains, icontains, startwith,endwith, in, gt, gte, lt, lte, range, year, month, day,
week_day, hour, minute, second, isnull, search, regex,iregex
5 . 7
3.1.6 MODELOS RELACIONADOS
Se puede hacer búsquedas en los modelos relacionadosusando __
Por ejemplo, los clientes que tengan facturas con líneasde más de 100
Busqueda en tablas relacionadas a traves de ForeignKeyField, ManyToManyField, OneToOneField
Clientes.objects.filter(facturas__lineas__total__gte=100)
Facturas.objects.filter(lineas__descripcion="Servicio")
Facturas.objects.filter(lineas__servicio__codigo="1")
5 . 8
3.1.7 SQL EN EL ORM
Se pueden hacer consultas a la db usando sql. Podemoscombinar el orm con los modelos.
Devolvería instancias de Person con los datos de la consula.
>>> for p in Person.objects.raw('SELECT * FROM myapp_person'):... print(p)John SmithJane Jones
5 . 9
3.1.8 EJECUTANDO SQL DIRECTAMENTE
Se puede obtener el cursor de la base de datos pararealizar consultas directas.
Se hace usando el PEP 0249, Database API, es la mismapara todas.
Ejecutando directamente sql
from django.db import connectionfrom django.db import connections
cursor = connection.cursor()cursor = connections["default"].cursor()
cursor.execute("UPDATE bar SET foo = 1 WHERE baz = %s", [self.baz])
cursor.execute("SELECT foo FROM bar WHERE baz = %s", [self.baz])row = cursor.fetchone()
6 . 1
4 URLSSon expresiones regulares.argumentos con nombre *(?P<arg>\d+) y sin nombre(\d+)Se pueden montar otras url usando include
Configuración de urls, normalmente my_app.urls.py
urlpatterns = [ url(r'̂$', main_views.homepage, name='home'), url(r'̂help/', include('apps.help.urls')),]
6 . 2
4.0.1 URLS (2)
Usamos nombres en las urls para referirnos a ellas:
Templates usando {% url %}Código usando django.core.urlresolvers.reverse()Desde el modelo usando get_absolute_url()
El tag url nos busca en las urls configuradas y nos devuelve la ruta
<a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>
Resolvemos la url en python
from django.core.urlresolvers import reversereturn HttpResponseRedirect(reverse('news-year-archive', args=(2012,)))
6 . 3
4.0.2 EJEMPLO REALEjemplo en la url principal montamos otras aplicaciones.
urlpatterns = [ url(r'̂i18n/', include('django.conf.urls.i18n')), url(r'̂accounts/', include('allauth.urls')), url(r'̂admin/', include(admin.site.urls)), url(r'̂', include('perfil.urls')), url(r'̂captcha/', include('captcha.urls')), url(r'̂actividades/', include('actividades.urls')), url(r'̂api/v1/', include('api.urls')), url(r'̂tests/', include('tests.urls')), url(r'̂comentarios/', include('django.contrib.comments.urls')), url(r'̂$', views.home, name="home"), url(r'̂sobre-nosotros/', include('sobre_nosotros.urls')), url(r'̂ayuda/', include('ayuda.urls')), url(r'̂colaboradores/', include('colaboradores.urls')), url(r'̂invitacion/', include('invitaciones.urls')), url(r'̂404/', TemplateView.as_view(template_name='404.html')), url(r'̂', include('cms.urls')), url(r'̂filer/', include('filer.urls')),]
7 . 1
5 VISTASPodemos crear vistas usando funciones o clases
Cada vista recibe un HttpRequest y devuelve unHttpResponse
7 . 2
5.0.1 FUNCIONES
Son funciones que reciben como primer parámetrorequest (HttpRequest) y devuelven un response
(HttpResponse).Vista básica
def vista(request): return HttpResponse("<h1>Mi Vista</h1>")
Estas son algunas funciones útiles para las vistas que sonfunciones.
Librería de atajos de django.
from django.shortcuts import render, render_to_response, redirect, get_object_or_404, get_list_or_404
7 . 3
5.0.2 CLASS BASED VIEWS
Es la evolución de las vistas para reutilizar más código.Definen comportamientos clásicos y nos permite
sustituir lo que necesitamos. Referencia: http://ccbv.co.uk/
TemplateViewRedirectViewListViewDetailViewFormViewCreateViewUpdateViewDeleteViewDe fechas
7 . 4
5.0.3 TEMPLATEVIEW
template_name / get_template_nameget_context_dataVista de plantilla la función get_context_data añade info a la plantilla.
class HomeView(TemplateView): template_name = "my_app/index.html"
def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['number'] = random.randrange(1, 100) return context
home = login_required(HomeView.as_view())
7 . 5
5.0.4 REDIRECTVIEW
url / get_redirect_url()permanent
Redirige a /frontend
class HomeView(RedirectView): url = "/frontend/"
7 . 6
5.0.5 LISTVIEW
modelorderingpaginate_byqueryset / get_queryset()template_namecontext_object_name
7 . 7
5.0.6 EJEMPLO LISTVIEWLa plantilla por defecto es my_app/document_list.html podemos cambiarlo usando template_name
class DocumentList(ListView): model = Document paginate_by = 10
Muestra todos los Documentos de la página seleccionada y muestra el paginador.
{% extends '_base.htm' %}{% block body %} {% for item in object_list %} <p>{{item.name}}</p> <p>{{item.description}}</p> {% endfor %}
{% if page_obj %} {% bootstrap_paginate page_obj range=10 %} {% endif %}{% endblock %}
7 . 8
5.0.7 LISTVIEW: ¿QUÉ HACE EL CÓDIGO ANTERIOR?
Hace un queryset del modelo Document.objects.all()Pagina los resultados, selecciona la página segúnrequest.GET.get("page")Compone un context con object_list, page_obj, etcRenderizamos la plantilla my_app/document_list.htmlcon eso contextoDevuelve el resultado en un HttpResponse
7 . 9
5.0.8 DETAILVIEW
modelqueryset / get_queryset()pk_url_kwargslug_fieldslug_url_kwargtemplate_namecontext_object_name
7 . 10
5.0.9 DETAILVIEW: EJEMPLOUrl para configurar la vista
urlpatterns = [ url(r'̂documento/(?P<pk>\d+)/$', DocumentDetailView.as_view(), name='documento_detail')]
Selecciona el objecto, y renderiza en my_app/document_detail.html
class DocumentDetailView(DetailView): model = Document
Muestra el detalle del documento
{% extends '_base.htm' %}{% block body %} <p>{{object.name}}</p> <p>{{object.description}}</p>{% endblock %}
7 . 11
5.0.10 CREATEVIEW
context_object_namefieldsinitialmodelqueryset / get_queryset()pk_url_kwargslug_fieldslug_url_kwargtemplate_namecontext_object_name
7 . 12
5.0.11 CREATEVIEW: EJEMPLOVista de create view
class DocumentCreateView(CreateView):model = Documento fields = ['nombre', 'descripcion', 'archivo']
Mostramos el formulario dinámicamente generado a partir del modelo.
{% extends '_base.htm' %}{% block body %}<form action="" method="post">{% csrf_token %} {{ form.as_p }} <input type="submit" value="Crear documento" /></form>{% endblock %}
7 . 13
5.0.12 CREATEVIEW
Cuando es GET:
Genera el formulario dinámicamente a base delmodelo usando ModelFormRenderiza el formulario.
Cuando es POST:
Valida el formulario contra la especificación delmodelo.Si no es válido muestra el formulario con los erroresSi es válido guarda el objecto en la base de datos.Redirige a la url del objecto (si está definida).
7 . 14
5.0.13 UPDATEVIEW
Es practicamente igual que CreateView, pero con partede los mixins de DetailView para seleccionar el objeto a
editar
8 . 2
6.0.1 TEMPLATE_CONTEXT_PROCESSORS
Son clases o funciones que añaden información alcontexto a la hora de renderizar las plantillas.Podemos añadir las nuestras si queremos añadir a lasplantillas nuestro contexto.'django.core.context_processors.auth','django.core.context_processors.debug','django.core.context_processors.i18n','django.core.context_processors.media',
8 . 3
6.0.2 ORIENTADAS A OBJETOS
extends, para extender de la plantilla padreblock para sustituir bloquesinclude para incluir otras plantillas
_base.html
<html lang="es"> <head> <title>{% block "title" %}My App{% endblock %}</title> {% block "extra_header" %}{% endblock %} </head> <body>{% block body %}{% endblock %}</body></html>
index.html
{% extends '_base.html' %}{% block title %}Título: Hola Mundo{% endblock %}{% block body %}<h1>Hola mundo</h1>{% endblock %}
8 . 4
6.0.3 DJANGO TEMPLATE LANGUAGE
tags{% nombre %}
tagsblock, comment, for, firstof, if, load, with, include, …
�ltros|filtro
�ltrosadd, capfirst, center, cut, floatformat, join, last, safe,…
8 . 5
6.0.4 TAGS Y FILTROS PERSONALIZADOS
Al poner {% load mistags %}
Busca en el módulo de todas las aplicacionesapps/templatetags/mistags.py
8 . 6
6.0.5 FILTROSCreación de un tag personalizado que podemos usar en las plantillas.
@register.filter(name='elimina')def elimina(value, arg): return value.replace(arg, '')
Como se usa el tag.
{% load mistags %}
{{ variable|elimina:","}}
8 . 7
6.0.6 TAGSEjemplo de creación de tags
@register.simple_tag(takes_context=True)def current_time(context, format_string): timezone = context['timezone'] return your_get_current_time_method(timezone, format_string)
@register.simple_tag(name='minustwo')def some_function(value): return value - 2
Ejemplo de uso
{% load mistags %}
{% current_time fecha %}{% minustwo 5 %}
8 . 8
6.0.7 INCLUSIÓN TAGS
Nos permiten reutilizar lógica y presentación.Definimos la plantilla a usar en el tag.
<ul>{% for book in books %} <li>{{ book.title }}</li>{% endfor %}</ul>
Definimos el tag y asignamos la plantilla
@register.inclusion_tag('book_snippet.html')def books_for_author(author): books = Book.objects.filter(authors=author) return {'books': books}
Usamos el tag, renderizaría la plantilla con el contexto generado en el tag.
{% load mistags %}{% books_for_author author %}
8 . 9
6.0.8 MÁS COMPLEJASPodemos crear tags que parseen nuestra propia sintaxis.
@register.tag(name="upper")def do_upper(parser, token): nodelist = parser.parse(('endupper',)) parser.delete_first_token() return UpperNode(nodelist)
class UpperNode(template.Node): def __init__(self, nodelist): self.nodelist = nodelist
def render(self, context): output = self.nodelist.render(context) return output.upper()
Ejemplo de uso
{% upper %} This will appear in uppercase, {{ user_name }}.{% endupper %}
9 . 1
7 ADMINISTRACIÓN DEDJANGO
Es una herramienta muy potente y compleja.
En nuestra aplicación, si queremos gestionar un modeloen el admin tenemos que hacer lo siguiente.
Ejemplo básico de uso de admin
from django.contrib import adminfrom .models import MiModelo
admin.site.register(MiModelo)
9 . 2
7.0.1 LOGIN EN EL ADMIN
Si ejecutamos.Comando para iniciar el servidor web de desarrollo de django
python manage.py runserver
Y abrimos el navegador en ,veremos que nos pide usuario y contraseña para entrar
al admin.
http://localhost:8000/admin
9 . 3
7.0.2 ADMIN
Administración de django con dos modelos registrados.
Figura 1: Administración de django, vemos los modelos registrados.
9 . 4
7.0.3 CREAR SUPERUSER
Actualmente no tenemos ningún usuario creado en elsistema. Podemos crear un usuario con todos los
permisos usando.Comando para crear un usuario superadministrador
python manage.py createsupersuser
9 . 5
7.0.4 BÁSICO
Django include los archivos o módulos (admin.py oadmin/__init__.py) llamados admin de todas las
aplicaciones registradas.
Registramos los modelos un una clase llamada admin.Ejemplo para que aparezca el modelo en el admin
from django.contrib import admin
from .models import Message
admin.site.register(Message)
9 . 6
7.0.5 PERSONALIZANDO MODEL ADMINEl admin es muy fácil y potente de personalizar.
from django.contrib import admin
from .models import Concept, Invoice
class ConceptInline(admin.TabularInline): model = Concept extra = 0
class InvoiceAdmin(admin.ModelAdmin): list_display = ["organization", "buyer", "date", "total"] inlines = [ConceptInline] search_fields = ["buyer", "organization"] list_filter = ["organization"] date_hierarchy = 'created_at'
admin.site.register(Invoice, InvoiceAdmin)
9 . 7
Figura 2: Pantalla de edición de admin.
9 . 8
7.0.7 ADMIN LISTADO
Figura 3: Listado de usuarios y filtros para aplicar.
10 . 1
8 ESTÁTICOSNormalmente una aplicación web necesita más cosas,aparte del html generado por django para funcionar.
ImágenesJavascriptCssetc
La aplicación django.contrib.static�les, se encarga degestionar esto.
Archivos subidos por el usuario se llaman MEDIA
10 . 2
8.0.1 CONFIGURACIÓN BÁSICA
En settingsSTATIC_URL = '/static/'
En las plantillas{% load staticfiles %}<img src="{% static "my_app/myexample.jpg" %}" alt="My image"/>}"
10 . 3
8.0.2 DURANTE EL DESARROLLO.Hacemos que el servidor de django sirva los estáticos
from django.conf import settingsfrom django.conf.urls.static import static
urlpatterns = [ # ... the rest of your URLconf goes here ...] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
También podemos añadir para que sirva MEDIA
urlpatterns = [ # ... the rest of your URLconf goes here ...] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
10 . 4
8.0.3 EN PRODUCCIÓN
Es el servidor web, cdn, etc quien sirve los estáticos.
Para desplegar los archivos estáticos a dóndecorresponda se usa.
$ python manage.py collectstatic
11 . 1
9 FORMULARIOSNormalmente el manejo de formularios en web, es untrabajo tedioso y delicado.Hay que realizar la validación de los valores deentrada.Imprimir los erroresRenderizar las formularios parciales, con los informesde error y los valores.
Django viene con clases para trabajar con formularios.
11 . 2
9.0.1 FORMULARIOS
django.forms funciona de manera similar a los modelos.
Nuestra clase hereda de django.forms.Form yañadimos atributos como tipos de campo, cada uno deestos tipos corresponde con un campo de formulariohtml.
Formulario de django
from django import forms
class ContactForm(forms.Form): subject = forms.CharField() email = forms.EmailField(required=False) message = forms.CharField()
11 . 3
9.0.2 FORMULARIOS
Cada tipo de campo tiene asociado por defecto una clasewidget que será la encargada de renderizarlo.
De esta manera, los formularios pueden autogenerar elhtml de los campos.
Como se utiliza el formulario en las plantillas
<form action="/your-name/" method="post"> {% csrf_token %} {{ form.as_p }} <input type="submit" value="Submit" /></form>
Podemos usar, para imprimir los formularios en pantallade diferentes formas
form.as_table, form.as_ul, form.as_p
11 . 4
9.0.3 FORMULARIOS
Los formularios reciben un diccionario (contexto).>>> data = {'subject': 'hello',... 'message': 'Hi there',... 'email': '[email protected]'}>>> f = ContactForm(data)>>> f.is_valid()True>>> f.is_bound == True>>> f2 = ContactForm()>>> f2.is_bound === False
Si la información está validada, podemos acceder a ellaen la propiedad cleaned_data
>>> f.cleaned_data{ 'message': 'Hi there', 'email': '[email protected]', 'subject': 'hello'}
11 . 5
9.0.4 VALIDACIÓN DE FORMULARIOS
Los campos que especificamos en la clase, ya se validanautomáticamente según las reglas que les especificamos.
Required, max_length, emailfield, max_value,min_value, etc..
11 . 6
9.0.5 VALIDACIÓN
Pero muchas veces queremos que el valor del campovalide además otra lógica.
from django import forms
class ContactForm(forms.Form): subject = forms.CharField() email = forms.EmailField(required=False) message = forms.CharField()
def clean_email(self): data = self.cleaned_data['email'] if "@example.com" not in data: raise forms.ValidationError("Ese dominio no existe, no me engañes!")
return data
11 . 7
9.0.6 MODELFORMS
Comúnmente, al trabajar con los modelos de la base dedatos vamos a tener que crear formularios para nuestros
modelos.
Django nos hace más fácil esa labor usando la clasedjango.forms.ModelForm
from django.forms import ModelFormfrom .models import Noticia
class NoticiaForm(ModelForm): class Meta: model = Noticia fields = ['fecha', 'titulo', 'texto']
noticia = Noticia.objects.get(pk=1)form = NoticiaForm(instance=noticia)
11 . 8
9.0.7 VALIDACIÓN DE MODELFORM
A la hora de validar un ModelForm, se realizan dos pasos
Validación del formularioValidación del modelo
11 . 9
9.0.8 MODELFORM
Si usamos .save() sobre un ModelForm válido, el modelose guardará en la base de datos y nos lo devolverá.
f = NoticiaForm(request.POST)
if f.is_valid(): noticia = f.save()
12 . 1
10 INTERNACIONALIZACIÓNY LOCALIZACIÓN
Hay soporte para
Traducción de textoFormateo de fecha y horaFormateo de númerosManejo de zonas horarias
12 . 2
10.0.1 INTERNACIONALIZACIÓN (I18N)
Lo que tiene que ver con la traducción de textosUSE_I18NLANGUAGE = lenguaje_pais -> es_ES
12 . 3
10.0.2 COMO SE USA
En pythonfrom django.utils.translation import ugettext as _from django.http import HttpResponse
def my_view(request): output = _("Welcome to my site.") return HttpResponse(output)
def my_view2(request, m, d): output = _('Today is %(month)s %(day)s.') % {'month': m, 'day': d} return HttpResponse(output)
12 . 4
10.0.3 PLURALES
from django.utils.translation import ungettextfrom django.http import HttpResponse
def hello_world(request, count): page = ungettext( 'there is %(count)d object', 'there are %(count)d objects', count) % { 'count': count, } return HttpResponse(page)
12 . 5
10.0.4 LAZY TRANSLATION
from django.db import modelsfrom django.utils.translation import ugettext_lazy as _
class MyThing(models.Model): name = models.CharField(_('name'), help_text=_('This is the help text'))
class Meta: verbose_name = _('my thing') verbose_name_plural = _('my things')
Solo se traducen cuando se usan. (Por ejemplo alrenderizar la plantilla)
12 . 6
10.0.5 EN PLANTILLAS
Ejemplo{% load i18n %}
<title>{% trans "This is the title." %}</title><title>{% trans myvar %}</title>
{% trans "starting point" as start %}{% trans "end point" as end %}{% trans "La Grande Boucle" as race %}
<h1> <a href="/" title="{% blocktrans %}Back to '{{ race }}' homepage {% endblocktrans %}">{{ race }}</a></h1><p>{% for stage in tour_stages %} {% cycle start end %}: {{ stage }}{% if forloop.counter|divisibleby:2 %}<br /> {% else %}, {% endif %}{% endfor %}</p>
12 . 7
10.0.6 OBTENIENDO EL IDIOMA Y CAMBIÁNDOLO
Ejemplo de como usar i18n en las plantillas{% load i18n %}
{% get_current_language as LANGUAGE_CODE %}<!-- Current language: {{ LANGUAGE_CODE }} --><p>{% trans "Welcome to our page" %}</p>
{% language 'en' %} {% get_current_language as LANGUAGE_CODE %} <!-- Current language: {{ LANGUAGE_CODE }} --> <p>{% trans "Welcome to our page" %}</p>{% endlanguage %}
12 . 8
10.0.7 EN JAVASCRIPT
En las urls se monta el javascript_catalogfrom django.views.i18n import javascript_catalog
urlpatterns = [ url(r'̂jsi18n/(?P<packages>\S+?)/$', javascript_catalog),]
En la plantilla<script type="text/javascript" src="{% url 'django.views.i18n.javascript_catalog' %}"></script>
12 . 9
10.0.8 EN JAVASCRIPT
Tendremos disponibles una serie de funcionesdocument.write(gettext('this is to be translated'));var object_count = 1 // or 0, or 2, or 3, ...
s = ngettext('literal for the singular case', 'literal for the plural case', object_count);
fmts = ngettext('There is %s object. Remaining: %s', 'There are %s objects. Remaining: %s', 11);s = interpolate(fmts, [11, 20]);
document.write(get_format('DATE_FORMAT'));
12 . 10
10.0.9 INTERNACIONALIZACIÓN DE URLS
from django.conf.urls import include, urlfrom django.conf.urls.i18n import i18n_patternsfrom django.utils.translation import ugettext_lazy as _
news_patterns = [ url(r'̂$', news_views.index, name='index'), url(_(r'̂category/(?P<slug>[\w-]+)/$'), news_views.category, name='category'), url(r'̂(?P<slug>[\w-]+)/$', news_views.details, name='detail'),]
urlpatterns += i18n_patterns( url(_(r'̂about/$'), about_views.main, name='about'), url(_(r'̂news/'), include(news_patterns, namespace='news')),)
12 . 11
10.0.10 URLS
i18n_patterns sólo está permitido un el archivo de urlsprincipal.
from django.core.urlresolvers import reversefrom django.utils.translation import activate
>>> activate('en')>>> reverse('news:category', kwargs={'slug': 'recent'})'/en/news/category/recent/'
>>> activate('nl')>>> reverse('news:category', kwargs={'slug': 'recent'})'/nl/nieuws/categorie/recent/'
12 . 12
10.0.11 CREACIÓN DE LOS FICHEROS DE TRADUCCIÓN
Una vez que en nuestra aplicación lo tenemos todopreparado para la traducción.Necesitamos extraer las cadenas traducibles para quese puedan traducir usando herramientas para ello.manage makemessages o django-adminmakemessages
12 . 13
10.0.12 MAKEMESSAGES
django-admin makemessages -l en
Creará locale/en/LC_MESSAGES/django.po, dentro de laaplicación que estamos traduciendo.
#: path/to/python/module.py:23msgid "Welcome to my site."msgstr """"
12 . 14
10.0.13 MAKEMESSAGES
Para volver a revisar de nuevo y extraer las cadenasnuevas usamos (para todos los idiomas)
django-admin makemessages -a
Para generar los ficheros de javascript se usa.django-admin makemessages -d djangojs -l en
12 . 15
10.0.14 COMPILANDO LOS MENSAJES
Cada vez que hagamos cambios en los archivos detraducción es necesario compilarlos a un formato más
eficiente que pueda leer django.django-admin compilemessages
Esto generará un fichero .mo por cada fichero .po queencuentre.
Para la compilación de los ficheros se usa gettext, en elmanual de django pone como instalarlo en windows.
https://docs.djangoproject.com/en/1.8/topics/i18n/translation/
12 . 16
10.0.15 LOCALEMIDDLEWARE
Si tenemos activo el localeMiddleware y no está puesta lacookie de idioma (no tenemos una sesión activa).
Django intentará adivinar las preferencias de idiomausando la cabecera Accept-language del navegador, y
nos redirigirá a la url del idioma adecuado.
12 . 17
10.0.16 IDIOMAS DISPONIBLES
En settings podemos encontrarLANGUAGES = ( ('de', _('German')), ('en', _('English')),)
LANGUAGE_CODE = 'es' # El idioma por defecto
12 . 18
10.0.17 LOCALIZACIÓN (L10N)
Lo que tiene tiene que ver con formateo y zonashorariasUSE_L10n
Podemos usarUSE_THOUSAND_SEPARATOR = True
Si queremos activar el separador de miles.
Para activar la localización en los modelos usamoslocalize
class CashRegisterForm(forms.Form): product = forms.CharField() revenue = forms.DecimalField(max_digits=4, decimal_places=2, localize=True)
12 . 19
10.0.18 EN LAS PLANTILLAS
Para usarlo en las plantillas usamos{% load l10n %}
{% localize on %} {{ value }}{% endlocalize %}
{% localize off %} {{ value }}{% endlocalize %}
{{ value|localize }}
12 . 20
10.0.19 LOCALIZACIÓN
Django tenía una aplicación localflavor para laslocalizaciones. Actualmente, ha sido extraída y vive como
aplicación de terceros en:
https://django-localflavor.readthedocs.org/en/latest/
Usando esta aplicación tendremos disponibles (enespaña por ejemplo)
ESCCCField. Campo que valida Banco EspañolESIdentityCardNumberField. Spanish NIF/NIE/CIFESPhoneNumberField,ESPostalCodeField,ESProvinceSelect,ESRegionSelectBICFormField, IBANFormField
13 . 1
11 LIBRERÍAS DE TERCERASPARTES
Librerías interesantes para trabajar con django.
django-pipeline (gestión de estáticos)easy-thumbnailsdjango-bracesdjangorestframeworkdjango-debug-toolbarcelery (procesos, colas de mensajes, async)weasyprint (generación de pdfs)requestsdjango-allauth (gestión de usuarios)
14 . 2
12.0.1 STACK
uwsgiServidor de aplicaciones
nginxServidor web y sirve estáticos
supervisorManeja procesos, celery o uwsgi
redisServidor de cache
PostgreSQLServidor de base de datos
14 . 3
12.0.2 AUTOMATIZACIÓN
El deploy de una app de django es complejo, esimportante automatizar el proceso ya que normalmente
cuando haces deploy querrás hacer:
Descargar el nuevo código (git pull)Instalar los nuevos requirements de la app.Realizar migraciones de la base de datos.generación de estáticos.decirle al servidor de apps que recarge el código.
Ansible tiene módulos compatibles con django que tepermiten automatizar el proceso.