frecuentes e. Estructuras f. Sentencias g. Ejercicio 2.Django a. Introducción b.URLs y Vistas c. Templates d.Modelo e. Administración f. Formularios g. Magia avanzada Proyecto
frecuentes e. Estructuras f. Sentencias g. Ejercicio 2.Django a. Introducción b.URLs y Vistas c. Templates d.Modelo e. Administración f. Formularios g. Magia avanzada Proyecto
• ... y Diver/do Sintaxis intuiHva y estricta Entre 1/3 y 1/5 más conciso que Java o C++ GNU/Linux, Windows, Mac OS X, ... Standard Library, Third parHes C, C++, Java, .NET, COM, WS, CORBA, ...
frecuentes e. Estructuras f. Sentencias g. Ejercicio 2.Django a. Introducción b.URLs y Vistas c. Templates d.Modelo e. Administración f. Formularios g. Magia avanzada Proyecto
frecuentes e. Estructuras f. Sentencias g. Ejercicio 2.Django a. Introducción b.URLs y Vistas c. Templates d.Modelo e. Administración f. Formularios g. Magia avanzada Proyecto
b a / b a % b -a +a a ** b comparadores a < b a <= b a > b a >= b a == b a != b lógicos a or b a and b not a h@p://docs.python.org/library/operator.html
frecuentes e. Estructuras f. Sentencias g. Ejercicio 2.Django a. Introducción b.URLs y Vistas c. Templates d.Modelo e. Administración f. Formularios g. Magia avanzada Proyecto
mario.py luigi.py princesa.py ... enemigos/ __init__.py seta.py tortuga.py bomba.py ... Módulos 1. Un módulo es un fichero .py 2. Los módulos pueden organizarse en paquetes. 3. Un paquete es una carpeta que conHene un fichero con nombre __init__.py
mario.py luigi.py princesa.py ... enemigos/ __init__.py seta.py tortuga.py bomba.py ... Módulos 1. Un módulo es un fichero .py 2. Los módulos pueden organizarse en paquetes. 3. Un paquete es una carpeta que conHene un fichero con nombre __init__.py 1 2 3
sys.path: import math ¿Dónde los busca Python? 1. El directorio actual: 2. El directorio site-packages de nuestro Python: 3. Los directorios apuntados por PYTHONPATH: 4. El directorio de la instalación de Python: ./ /usr/local/lib/python2.6/site-packages /usr/lib/python2.6/ $ env | grep PYTHONPATH
frecuentes e. Estructuras f. Sentencias g. Ejercicio 2.Django a. Introducción b.URLs y Vistas c. Templates d.Modelo e. Administración f. Formularios g. Magia avanzada Proyecto
“Readability counts” • “Code is read much more ohen than it is wriien.” • Muy recomendable importante seguirlo. PEP 8 ¿PEP 8? h@p://www.python.org/dev/peps/pep-‐0008/
'__delslice__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__setslice__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort'] >>> help(filter) Help on built-in function filter in module __builtin__: filter(...) filter(function or None, sequence) -> list, tuple, or string Return those items of sequence for which function(item) is true. If function is None, return the items that are true. If sequence is a tuple or string, return the same type, else return a list. (END)
frecuentes e. Estructuras f. Sentencias g. Ejercicio 2.Django a. Introducción b.URLs y Vistas c. Templates d.Modelo e. Administración f. Formularios g. Magia avanzada Proyecto
} elseif($name == "Mary"){ $name = "Hello Mary"; } else{ $name = "Who are you?" } name = "Jon" if name == "Jon": name = "Jon Rocks!" elif name == "Mary": name = "Hello Mary" else: name = "Who are you?" Sentencias: if-‐else
código: • Muchos Muchísimos menos errores de Sintaxis. • Mayor velocidad de escritura. • ProtoHpado... UHlizado por grandes empresas. etc... Conclusiones
frecuentes e. Estructuras f. Sentencias g. Ejercicio 2.Django a. Introducción b.URLs y Vistas c. Templates d.Modelo e. Administración f. Formularios g. Magia avanzada Proyecto
independiente y desconoce completamente a las demás. • Menos código. • Rápido desarrollo. • Esto es el siglo 21, todo el trabajo tedioso hay que evitarlo. • Don’t Repeat Yourself (DRY) Filoso]a
independiente y desconoce completamente a las demás. • Menos código. • Rápido desarrollo. • Esto es el siglo 21, todo el trabajo tedioso hay que evitarlo. • Don’t Repeat Yourself (DRY) Every distinct concept and/or piece of data should live in one, and only one, place. Redundancy is bad. Normalization is good.” “ Filoso]a
principio de Python. • Django no debe hacer demasiada “Magia”. • Si algo es “Mágico” ha de haber una buena razón. • Consistencia • Ha de ser consistente a todos los niveles. • Eficiencia, Seguridad, Flexibilidad y Simplicidad. Filoso]a h@p://docs.djangoproject.com/en/dev/misc/design-‐philosophies/
un proyecto... ? Si os ve mi jefe... . !"" dwitter # !"" __init__.py # !"" settings.py # !"" urls.py # $"" wsgi.py $"" manage.py -‐ Sí, disponemos de un proyecto ‘funcional’ en django. de 5 ficheros ;-‐)
$ python manage.py runserver Validating models... 0 errors found Django version 1.4, using settings 'dwitter.settings' Development server is running at http://127.0.0.1:8000/ Quit the server with CONTROL-C.
$ python manage.py runserver Validating models... 0 errors found Django version 1.4, using settings 'dwitter.settings' Development server is running at http://127.0.0.1:8000/ Quit the server with CONTROL-C.
frecuentes e. Estructuras f. Sentencias g. Ejercicio 2.Django a. Introducción b.URLs y Vistas c. Templates d.Modelo e. Administración f. Formularios g. Magia avanzada Proyecto
de entrada para las pe*ciones HTTP • Se definen URLs elegantes mediante expresiones regulares que redirigen a funciones de views.py urls.py views.py hFp://mysite.com/about/ html ... ¿urlpaFerns?
parámetros un objeto H@pRequest y todos los parámetros de la URL capturados, teniendo que devolver siempre un objeto H@pResponse views.py H@pRequest(), ... H@pResponse()
* from mysite.views import hora_actual urlpatterns = patterns('', url(r'^time/$', hora_actual), ) from django.http import HttpResponse from datetime import datetime def hora_actual(request): now = datetime.now() html = "Son las %s." % now return HttpResponse(html) urls.py views.py
frecuentes e. Estructuras f. Sentencias g. Ejercicio 2.Django a. Introducción b.URLs y Vistas c. Templates d.Modelo e. Administración f. Formularios g. Magia avanzada Proyecto
y Context(). • Un objeto Template() con*ene el string de salida que queremos devolver en el HFpResponse (normalmente HTML), pero incluyendo e*quetas especiales de Django. • Un objeto Context() con*ene un diccionario con los valores que dan contexto a una plan*lla, los que deben usarse para renderizar un objeto Template(). "Bienvenido, {{ user }}." {'user': 'alatar'} Template: Context: "Bienvenido, alatar."
from datetime import datetime PLANTILLA = """<html><body> Son las {{ hora }}. </body></html>""" def hora_actual(request): now = datetime.now() t = Template(PLANTILLA) c = Context({'hora': now}) html = t.render(c) return HttpResponse(html) • Primera aproximación al obje*vo: Template + Context
'/home/django/templates', ) senngs.py from django.http import HttpResponse from django.template.loader import get_template from django.template import Context from datetime import datetime def hora_actual(request): now = datetime.now() t = get_template('hora.html') c = Context({'hora': now}) html = t.render(c) return HttpResponse(html)
'/home/django/templates', ) senngs.py from django.http import HttpResponse from django.template.loader import get_template from django.template import Context from datetime import datetime def hora_actual(request): now = datetime.now() t = get_template('hora.html') c = Context({'hora': now}) html = t.render(c) return HttpResponse(html) S*ll boring...
apps? a) b) • La carpeta /templates es buscada dentro de cada app. • Conviene incluir una carpeta con el nombre de la app por claridad. TEMPLATE_LOADERS = ( 'django.template.loaders.filesystem.Loader', 'django.template.loaders.app_directories.Loader', ) return render(request, 'website/index.html') Alterna*va reu*lizable:
Smarty, Tiles, ClearSilver ... •Describen cuál va a ser el resultado que ven los usuarios. • Desacoplado de Python ( Diseñadores muy lejos de Python ) • HTML (o no)... con esteroides. • Muy sencillo de aprender • KISS: Keep It Simple, Stupid • Muy sencillo de extender
HTML/XML. • Los diseñadores saben HTML. • Los diseñadores no saben Python. • No consiste en inventarse un lenguaje. • Una variable no puede cambiar el valor de una variable. • Una template no puede ejecutar código Python.
%} comment for {% for elemento in lista %} <li>{{ elemento }}<li> {% endfor %} if {% if username == "Juan" %} Hola Juan, me gustas! {% else %} Hola {{ username }}, {% endif %} == != > < >= <= in and or not
username|striptags }} striptags Juan es majo guapo y listo {{ username|truncatewords_html:4 }} truncatewords_html Juan es <b>majo guapo</b> ... {{ username|removetags:”em a br” }} removetags Juan es <b>majo guapo y listo</b>
texto a minúsculas capitalizadas: ‣“HOYGAN NESESITO QUE MAYUDEN A HASER UN PROGRAMA EN DJANGO GRASIAS DE ANTEBRASO” ‣“Hoygan necesito que mayuden a haser un programa en django grasias de antebraso”
en vuestra app. c) Hacer que vuestro index.html herede de base.html y exHenda el bloque ‘content’ con su contenido. h@p://bit.ly/base-‐html-‐template
frecuentes e. Estructuras f. Sentencias g. Ejercicio 2.Django a. Introducción b.URLs y Vistas c. Templates d.Modelo e. Administración f. Formularios g. Magia avanzada Proyecto
host='localhost') cursor = db.cursor() cursor.execute('SELECT nama FROM books ORDER BY name') names = [] for row in cursor.fetchall() names.append(row[0]) db.close() except: return render_to_response('500.html') return render_to_response('book_list.html', {'names':names})
max_length=100) created = models.DateTimeField(blank=False) available = models.BooleanField(default=True) • Independencia SGBD! • Definimos estructuras de información genéricas. • Definimos restricciones (notnull, blank, max_lenght...) • Única definición del modelo (configuración, mapeo a db)
NOT NULL PRIMARY KEY, "name" varchar(100) NOT NULL, "created" datetime NOT NULL, "available" bool NOT NULL ); COMMIT; BEGIN; CREATE TABLE "website_books" ( "id" serial NOT NULL PRIMARY KEY, "name" varchar(100) NOT NULL, "created" timestamp with time zone NOT NULL, "available" boolean NOT NULL ); COMMIT;
TABLE "website_books" ( "id" integer NOT NULL PRIMARY KEY, "name" varchar(100) NOT NULL, "created" datetime NOT NULL, "available" bool NOT NULL ); COMMIT; BEGIN; CREATE TABLE "website_books" ( "id" serial NOT NULL PRIMARY KEY, "name" varchar(100) NOT NULL, "created" timestamp with time zone NOT NULL, "available" boolean NOT NULL ); COMMIT;
<app_name>_lower(<model_name>) • id como Primary Key (Personalizable) • Las Foreing Key terminan en _id (Personalizable) • Los Hpos de datos se ajustan en función del SGBD
para todos los modelos de las apps instaladas en el fichero sesngs.py • No actualiza esquemas si la tabla existe. • Eliminar tabla y volver a ejecutar syncdb
auth_group Creating table auth_user Creating table auth_message Creating table django_content_type Creating table django_session Creating table django_site Creating table website_tweet You just installed Django's auth system, which means you don't have any superusers defined. Would you like to create one now? (yes/no): yes Username (Leave blank to use 'neo'): admin E-mail address: user@example.com Password: Password (again): Superuser created successfully. Installing index for auth.Permission model Installing index for auth.Message model Installing index for website.Tweet model
auth_group Creating table auth_user Creating table auth_message Creating table django_content_type Creating table django_session Creating table django_site Creating table website_tweet You just installed Django's auth system, which means you don't have any superusers defined. Would you like to create one now? (yes/no): yes Username (Leave blank to use 'neo'): admin E-mail address: user@example.com Password: Password (again): Superuser created successfully. Installing index for auth.Permission model Installing index for auth.Message model Installing index for website.Tweet model django.contrib.auth
auth_group Creating table auth_user Creating table auth_message Creating table django_content_type Creating table django_session Creating table django_site Creating table website_tweet You just installed Django's auth system, which means you don't have any superusers defined. Would you like to create one now? (yes/no): yes Username (Leave blank to use 'neo'): admin E-mail address: user@example.com Password: Password (again): Superuser created successfully. Installing index for auth.Permission model Installing index for auth.Message model Installing index for website.Tweet model website.tweet
auth_group Creating table auth_user Creating table auth_message Creating table django_content_type Creating table django_session Creating table django_site Creating table website_tweet You just installed Django's auth system, which means you don't have any superusers defined. Would you like to create one now? (yes/no): yes Username (Leave blank to use 'neo'): admin E-mail address: user@example.com Password: Password (again): Superuser created successfully. Installing index for auth.Permission model Installing index for auth.Message model Installing index for website.Tweet model django.contrib.auth
Publisher.objects.get(country="U.S.A.") Traceback (most recent call last): ... MultipleObjectsReturned: get() returned more than one Publisher -- it returned 2! Lookup parameters were {'country': 'U.S.A.'} >>> Publisher.objects.get(name="Anaya") Traceback (most recent call last): ... DoesNotExist: Publisher matching query does not exist.
... >>> c.motor <Motor: Motor object> >>> m.coche <Coche: Coche object> ¿Cómo usamos la relación desde las instancias? Gracias a nosotros Gracias a Django 1 1
ForeignKeyField(Blog) >>> p.blog <Blog: Blog object> >>> b.post_set.all() [<Post: Post object>, ...] ¿Cómo usamos la relación desde las instancias? Gracias a nosotros Gracias a Django 1 n
... >>> p.tags.add(t1, t2) >>> p.tags.all() [<Tag: Tag object>, ...] >>> t.post_set.add(p1, p2) >>> t.post_set.all() [<Post: Post object>, ...] ¿Cómo usamos la relación desde las instancias? Gracias a nosotros Gracias a Django n m
class Blog(models.Model): ... class Post(models.Model): blog = ForeignKeyField(Blog, related_name='posts') >>> p.blog <Blog: Blog object> >>> b.posts.all() [<Post: Post object>, ...] Gracias a nosotros Gracias a Django 1 n
class Blog(models.Model): ... class Post(models.Model): blog = ForeignKeyField(Blog, related_name='posts') >>> p.blog <Blog: Blog object> >>> b.posts.all() [<Post: Post object>, ...] Gracias a nosotros Gracias a Django 1 n Cuando haya 2 relaciones entre 2 modelos, será obligatorio
permalink de un tweet: ‣ URL: tweet/<tweet_id>/ ‣ View: tweet_page ‣ Template: tweet_page.html (Descargar) d)Lanzar Http404 si no existe el tweet_id. e)shortcut!: get_object_or_404() h@p://bit.ly/tweet-‐page
contener toda la información que necesitamos. • Username, Password, Name.... y poco más. • Solución: Definir un Profile (Un Modelo Agregado) para guardar esa información.
>>> type(u) <class 'django.contrib.auth.models.User'> >>> type(u.profile) <class 'website.models.Profile'> •Donde tengamos el User tendremos el Profile. •Donde tengamos el Profile, tendremos el User.
a crear aplicaciones reuHlizables. • Permite subscribirnos a “eventos” a lo largo de todo el framework y actuar frente a ellos (¡Observer-‐Observable!). • Señales interesantes: • pre_save, post_save • pre_delete, post_delete • m2m_changed • request_started, request_finished h@p://docs.djangoproject.com/en/dev/ref/signals/
django.db.models.signals import post_save post_save.connect(create_user_profile, sender=User) 1 2 3 Puede estar en cualquier app de nuestro proyecto. Se recomienda models.py
max_length=200) followers = models.ManyToManyField("self", blank=True, symmetrical=False, related_name="following") models.py • m2m symmetrical (por defecto) • Si yo te sigo a H, tú me sigues a mi. • related_name (en este caso) • Limpieza y evitar profile_set
frecuentes e. Estructuras f. Sentencias g. Ejercicio 2.Django a. Introducción b.URLs y Vistas c. Templates d.Modelo e. Administración f. Formularios g. Magia avanzada Proyecto
next two lines to enable the admin: from django.contrib import admin admin.autodiscover() urlpatterns = patterns('', ... url(r'^admin/', include(admin.site.urls)), ... ) 1 2 urls.py
Define qué modelos serán visibles desde el admin y permite personalizar su aspecto. from django.contrib import admin from website.models import Tweet class TweetAdmin(admin.ModelAdmin): list_display = ('id','user','message','timestamp') admin.site.register(Tweet, TweetAdmin)
vez que se elimina una tabla / BD. • No nos gustan las cosas aburridas. • Ficheros (json/xml/yaml) para inicializar una Tabla. • Pueden crearse una vez dispongamos de la información:
vez que se elimina una tabla / BD. • No nos gustan las cosas aburridas. • Ficheros (json/xml/yaml) para inicializar una Tabla. • Pueden crearse una vez dispongamos de la información: python manage.py dumpdata <appName appName appName.model ...>
vez que se elimina una tabla / BD. • No nos gustan las cosas aburridas. • Ficheros (json/xml/yaml) para inicializar una Tabla. • Pueden crearse una vez dispongamos de la información: python manage.py dumpdata <appName appName appName.model ...> • Se cargan uHlizando: python manage.py loaddata <fixture fixture ...> • Si se llaman iniHal_data y están dentro de la carpeta fixtures de la app, se cargan al ahcer el syncdb.
frecuentes e. Estructuras f. Sentencias g. Ejercicio 2.Django a. Introducción b.URLs y Vistas c. Templates d.Modelo e. Administración f. Formularios g. Magia avanzada Proyecto
<input type='text'...> <input type='checkbox'...> Field Lógica de un campo, asociado a un Widget EmailField IPAddressField widget, initial, error, ... Form Conjunto de Fields de un formulario ContactForm [nombre, email, telefono, mensaje, ...]
import ContactForm def contact(request): if request.method == 'POST': form = ContactForm(request.POST) if form.is_valid(): cd = form.cleaned_data send_mail(cd['subject'], cd['message'], ...) # ... return HttpResponseRedirect('/contact/thanks/') else: form = ContactForm() return render(request, 'contact_form.html', {'form': form}) • Paso 3/3: Programación de la vista en views.py
import ContactForm def contact(request): if request.method == 'POST': form = ContactForm(request.POST) if form.is_valid(): cd = form.cleaned_data send_mail(cd['subject'], cd['message'], ...) # ... return HttpResponseRedirect('/contact/thanks/') else: form = ContactForm() return render(request, 'contact_form.html', {'form': form}) • Paso 3/3: Programación de la vista en views.py Paiern
import ContactForm def contact(request): if request.method == 'POST': form = ContactForm(request.POST) if form.is_valid(): cd = form.cleaned_data send_mail(cd['subject'], cd['message'], ...) # ... return HttpResponseRedirect('/contact/thanks/') else: form = ContactForm() return render(request, 'contact_form.html', {'form': form}) • Paso 3/3: Programación de la vista en views.py Paiern
import ContactForm def contact(request): if request.method == 'POST': form = ContactForm(request.POST) if form.is_valid(): cd = form.cleaned_data send_mail(cd['subject'], cd['message'], ...) # ... return HttpResponseRedirect('/contact/thanks/') else: form = ContactForm() return render(request, 'contact_form.html', {'form': form}) • Paso 3/3: Programación de la vista en views.py Paiern
Author(models.Model): name = models.CharField(max_length=100) birth_date = models.DateField(blank=True, null=True) country = models.ModelChoiceField(Country) ... from django import forms from books.models import Author class AuthorForm(forms.ModelForm): class Meta: model = Author exclude = ('country',) models.py forms.py
frecuentes e. Estructuras f. Sentencias g. Ejercicio 2.Django a. Introducción b.URLs y Vistas c. Templates d.Modelo e. Administración f. Formularios g. Magia avanzada Proyecto
'mysite.views.hello'), url(r'^time/$', 'mysite.views.current_datetime'), url(r'^time/plus/(d{1,2})/$', 'mysite.views.hours_ahead'), ) ¡El primer parámetro de pa@erns() sirve de algo!
mediante un diccionario de Extra Op/ons from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns('', url(r'^foo/$', views.foobar_view, {'template_name': 'template1.html'}), url(r'^bar/$', views.foobar_view, {'template_name': 'template2.html'}), ) Las tuplas de pa@erns() pueden tener 3 elementos
* from django.views.generic.simple import direct_to_template urlpatterns = patterns('', url(r'^about/$', direct_to_template, {'template': 'about.html'}) ) from django.views.generic.simple import direct_to_template Es la Generic View más simple y más uHlizada
que se sirvan de las vistas de django.contrib.auth para implementar login y logout: ‣ URL: login/ ‣ View: auth.views.login ‣ Template: login.html (Descargar) ‣ URL: logout/ ‣ View: auth.views.logout ‣ Template: [redirect a /] h@p://bit.ly/login-‐template
request.META['REMOTE_ADDR']} • Reciben un HFpRequest() como único parámetro. • Devuelven un diccionario para ser usado como Context(). TEMPLATE_CONTEXT_PROCESSORS = ( "django.contrib.auth.context_processors.auth", "django.core.context_processors.debug", "django.core.context_processors.i18n", "django.core.context_processors.media", "django.contrib.messages.context_processors.messages", "website.context_processors.ip_address_processor", )
esta vista con Context, la función render() instancia RequestContext, que alimenta nuestro diccionario con todos los diccionarios devueltos por los Context Processors que tengamos habilitados. def view(request): ... return render(request, '...html', {'...': ...}) def render(request, template, context): t = get_template(template) c = RequestContext(request, context) html = t.render(c) return HttpResponse(html)
Filter es una función Python que: • Recibe 1 o 2 argumentos: (value [, arg]). • Siempre devuelve algo: el resultado, value o "". • Falla silenciosamente: no lanza excepciones. from django import template register = template.Library() @register.filter(name='cut') def cut(value, arg=' '): return value.replace(arg, '')
Vamos a ver cómo crear los 2 Hpos de Tags más sencillos: SimpleTags InclusionTags • Son inline • Reciben 1 argumento • Devuelven un string • Son inline • Reciben n argumentos • Devuelven un diccionario • Insertan su propio fragmento de template
a cada tweet del Hmeline que publique el mismo tweet en tu nombre precedido por “RT “. b)Implementar “borrar tweet”: un botón junto a cada tweet propio que lo elimine. a)Implementar “página de menHons”: un Hmeline que sólo muestre los tweets que te mencionen a H (Hp: message__icontains=).
que Django decida a qué View llamar. -> HttpRequest(): Se corta el flujo de middleware. -> None: El flujo sigue con el siguiente middleware.""" # ... def process_view(self, request, view_func, view_args, view_kwargs): """Se ejecuta antes de que se llame a la View. -> HttpRequest(): Se corta el flujo de middleware. -> None: El flujo sigue con el siguiente middleware.""" # ... def process_response(self, request, response): """Se ejecuta después de que la View devuelva una response. -> HttpResponse()""" # ... def process_exception(self, request, exception): """Se ejecuta cuando una View lanza una excepción. -> HttpResponse(). -> None: La excepción se propaga hasta el cliente.""" # ...
que nos convenga, teniendo en cuenta el orden de ejecución en la Request y en la Response: MIDDLEWARE_CLASSES = ( 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', )
todas páginas. 2. Si el usuario Hene una IP o un User o... 2. Si@o en Mantenimiento 1. Todo el Site muestra un splash excepto... 3. Cache Middleware 1. Si la vista cumple un patrón (User no logeado,...) cacheamos la página. 4. etc...
Un fichero .pot conHene todos los strings usados contabilidad.pot 2. En cada fichero .po se guarda una traducción es_ES.pot es_AR.pot en_GB.pot 3. Cada .po se compila y genera un .mo binario es_ES.mo es_AR.mo en_GB.mo Internacionalización
memcached •Acceder a la BD es caro, muy caro. •El Hardware es “gra*s” en comparación con op*mizar código op*mizado. •Ejemplo (Facebook): 300+Tb Memcached
diferencias: • Atómico • Persistencia • Tipos “ricos” (list, sets, sorted sets, etc..) • Demo : Sistema de Ranking • ¿Cómo ges*onar un ranking de más 10Millones de usuarios? • Cada uuid es un sha1() -‐> 40 caracteres. • Las Puntuaciones son random entre 0 y 100.000 puntos. • Los datos se han introducido de manera aleatoria.
-‐> 1020segundos -‐> ~ 0,1 ms por insert. • 1.6gb en memoria WTF!! • int = 4bytes * 10M = 40Millones de bytes = 38Mb • char(40) = 40 bytes * 10M = 400Millones de bytes = 381Mb • 419Mb en total de datos ocupan 1.6gb en RAM
-‐> 1020segundos -‐> ~ 0,1 ms por insert. • 1.6gb en memoria WTF!! • int = 4bytes * 10M = 40Millones de bytes = 38Mb • char(40) = 40 bytes * 10M = 400Millones de bytes = 381Mb • 419Mb en total de datos ocupan 1.6gb en RAM ¡Más que aceptable para dar solución a un problema con 10Millones de usuarios!
*ene su juego de librerías en la versión que necesita •Sin miedo a actualizar •Sin miedo a migrar •etc... $ virtualenv mi_entorno crear $ source mi_entorno/bin/activate ac/var
un fichero de REQUIREMENTS con un listado de paquetes a instalar. Django==1.4 psycopg2 feedparser==4.1 stripogram==1.5 GChartWrapper==0.8 pip install -E mi_entorno -r REQUIREMENTS
a HTTP and reverse proxy server. • Con una configuración muy sencilla podremos u*lizarlo como proxy inverso a gunicorn. • hFp://gunicorn.org/ • Servidor Web WSGI implementado en Python • Facilidades de puesta en marcha de proyectos django • Fácilmente configurable usando nginx • hFp://nginx.org/
de esquemas. •¿Que sucede si tengo un Modelo con 100.000 filas y quiero añadir una columna? ... south! •Necesito migrar el contenido desde mi an*guo Modelo a uno nuevo... south! •Necesito que ... south! hFp://south.aeracode.org/
fácil implementación y escalable. •Casos prác/cos: •Enviar un email •Calcular el karma de de los usuarios del sistema. •Tareas programadas (Limpieza, Post-‐procesado, etc...) Celery h@p://celeryproject.org
+ y >>> result = add.delay(4, 4) >>> result.wait() # wait for and return the result 8 • Las Task son simples funciones (O class si queremos) • Python 100% el retorno será el resultado • Usamos el decorador @task para registrarla • El método .delay sobre cualquier Task lo ejecuta en background. • Podemos esperar a que un Worker ejecute la tarea o seguir haciendo otras acciones. Celery h@p://celeryproject.org
día •Una de las mejores: graph_models •Usando GraphViz genera un modelo relacional de los modelos de nuestro proyecto. h@p://code.google.com/p/django-‐command-‐extensions/