• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Django
 

Django

on

  • 851 views

 

Statistics

Views

Total Views
851
Views on SlideShare
800
Embed Views
51

Actions

Likes
1
Downloads
36
Comments
0

1 Embed 51

http://betabeers.com 51

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Django Django Presentation Transcript

    • Juan Riaza @juanriaza
    • Don’t reinvent the wheel
    • https://gist.github.com/3143116
    • Jorge  Bas0da Jaime  Irurzunme@jorgebas0da.com jaime@irurzun.com @jorgebas0da @jaimeirurzun
    • • Legible Sintaxis  intui+va  y  estricta• Produc-vo Entre  1/3  y  1/5  más  conciso  que  Java  o  C++• Portable GNU/Linux,  Windows,  Mac  OS  X,  ...• Extenso Standard  Library,  Third  par+es• Integrable C,  C++,  Java,  .NET,  COM,  WS,  CORBA,  ...• ...  y  Diver-do
    • El  Intérprete
    • El  Intérprete Modo  Batch holamundo.py $ python holamundo.py#!/usr/bin/env python hola mundo!print "hola mundo!" $
    • El  Intérprete Modo  Batch holamundo.py $ python holamundo.py#!/usr/bin/env python hola mundo!print "hola mundo!" $ Modo  Interac0vo$ pythonPython 2.6.5 (r265:79063, Apr 16 2010, 13:09:56)[GCC 4.4.3] on linux2Type "help", "copyright", "credits" or "license" for more information.>>> print "hola mundo!"hola mundo!
    • Tipos  de  datosobject  h>p://docs.python.org/library/stdtypes.html
    • Tipos  de  datos int 1234 long 35L float 3.1415object  h>p://docs.python.org/library/stdtypes.html
    • Tipos  de  datos int 1234 long 35L float 3.1415 bool True Falseobject  h>p://docs.python.org/library/stdtypes.html
    • Tipos  de  datos int 1234 long 35L float 3.1415 bool True False str spam "guidos" """n lines"""object  h>p://docs.python.org/library/stdtypes.html
    • Tipos  de  datos int 1234 long 35L float 3.1415 bool True False str spam "guidos" """n lines"""object list [1, [2, three], 4]  h>p://docs.python.org/library/stdtypes.html
    • Tipos  de  datos int 1234 long 35L float 3.1415 bool True False str spam "guidos" """n lines"""object list [1, [2, three], 4] dict {food: spam, taste: yum}  h>p://docs.python.org/library/stdtypes.html
    • Tipos  de  datos int 1234 long 35L float 3.1415 bool True False str spam "guidos" """n lines"""object list [1, [2, three], 4] dict {food: spam, taste: yum} tuple (1, spam, 4, U)  h>p://docs.python.org/library/stdtypes.html
    • Tipos  de  datos o   ¡T i p ad mi co! int 1234 long 35L float d iná 3.1415 bool True False str spam "guidos" """n lines"""object list [1, [2, three], 4] dict {food: spam, taste: yum} tuple (1, spam, 4, U)  h>p://docs.python.org/library/stdtypes.html
    • Operadores  h>p://docs.python.org/library/operator.html
    • Operadores a + b a - b a * b a / bnuméricos a % b -a +a a ** b  h>p://docs.python.org/library/operator.html
    • Operadores a + b a - b a * b a / b numéricos a % b -a +a a ** b a < b a <= b a > bcomparadores a >= b a == b a != b  h>p://docs.python.org/library/operator.html
    • Operadores a + b a - b a * b a / b numéricos a % b -a +a a ** b a < b a <= b a > bcomparadores a >= b a == b a != b lógicos a or b a and b not a  h>p://docs.python.org/library/operator.html
    • Usos  frecuentes:  list
    • Usos  frecuentes:  list>>> nums = [1, 2, 3]>>> nums[0]1
    • Usos  frecuentes:  list>>> nums = [1, 2, 3]>>> nums[0]1>>> 2 in numsTrue
    • Usos  frecuentes:  list>>> nums = [1, 2, 3]>>> nums[0]1>>> 2 in numsTrue>>> nums.append(4)>>> print nums[1, 2, 3, 4]
    • Usos  frecuentes:  list>>> nums = [1, 2, 3]>>> nums[0]1>>> 2 in numsTrue>>> nums.append(4)>>> print nums[1, 2, 3, 4]>>> len(nums)4
    • Usos  frecuentes:  str
    • Usos  frecuentes:  str>>> "Python mola"[1:4]yth
    • Usos  frecuentes:  str>>> "Python mola"[1:4]yth>>> "Python mola".find("mola")7
    • Usos  frecuentes:  str>>> "Python mola"[1:4]yth>>> "Python mola".find("mola")7>>> "Python mola".replace("Python", "PHP no")PHP no mola
    • Usos  frecuentes:  str>>> "Python mola"[1:4]yth>>> "Python mola".find("mola")7>>> "Python mola".replace("Python", "PHP no")PHP no mola>>> "Python mola".split(" ")[Python, mola]
    • Usos  frecuentes:  str>>> "Python mola"[1:4]yth>>> "Python mola".find("mola")7>>> "Python mola".replace("Python", "PHP no")PHP no mola>>> "Python mola".split(" ")[Python, mola]>>> " ".join(["Python", "mola"])"Python mola"
    • Usos  frecuentes:  dict
    • Usos  frecuentes:  dict>>> user = {nick: neo, age: 24}>>> user.keys()[nick, age]>>> user.values()[neo, 24]
    • Usos  frecuentes:  dict>>> user = {nick: neo, age: 24}>>> user.keys()[nick, age]>>> user.values()[neo, 24]>>> user[age] >>> user.get(age, 20)24 24
    • Usos  frecuentes:  dict>>> user = {nick: neo, age: 24}>>> user.keys()[nick, age]>>> user.values()[neo, 24]>>> user[age] >>> user.get(age, 20)24 24>>> nick in userTrue
    • Usos  frecuentes:  dict>>> user = {nick: neo, age: 24}>>> user.keys()[nick, age]>>> user.values()[neo, 24]>>> user[age] >>> user.get(age, 20)24 24>>> nick in userTrue>>> user.update({nick: alatar, age: 25})>>> user{nick: alatar, age: 25}
    • Usos  frecuentes:  str  %
    • Usos  frecuentes:  str  %>>> "%s es muy sabio" % "Hycker"Hycker es muy sabio
    • Usos  frecuentes:  str  %>>> "%s es muy sabio" % "Hycker"Hycker es muy sabio>>> "%s sabe %i idiomas" % ("Hycker", 5)Hycker sabe 5 idiomas
    • Usos  frecuentes:  str  %>>> "%s es muy sabio" % "Hycker"Hycker es muy sabio>>> "%s sabe %i idiomas" % ("Hycker", 5)Hycker sabe 5 idiomas>>> t = "%(NOMBRE)s sabe %(IDIOMAS)i idiomas">>> v = {NOMBRE: Hycker, IDIOMAS: 5}>>> t % vHycker sabe 5 idiomas
    • Módulosjuego/ __init__.py 1. Un  módulo  es  un  fichero  .py bonus/ __init__.py estrella.py moneda.py 2. Los  módulos  pueden   planta.py ... personajes/ organizarse  en  paquetes. __init__.py mario.py luigi.py princesa.py 3. Un  paquete  es  una  carpeta   ... enemigos/ __init__.py que  con+ene  un  fichero  con   seta.py tortuga.py nombre  __init__.py bomba.py ...
    • Módulosjuego/ __init__.py 1. Un  módulo  es  un  fichero  .py bonus/ __init__.py estrella.py moneda.py 1 2. Los  módulos  pueden   planta.py 2 ... personajes/ organizarse  en  paquetes. __init__.py 3 mario.py luigi.py princesa.py 3. Un  paquete  es  una  carpeta   ... enemigos/ __init__.py que  con+ene  un  fichero  con   seta.py tortuga.py nombre  __init__.py bomba.py ...
    • Módulosjuego/ __init__.py bonus/ __init__.py estrella.py moneda.py planta.py ... personajes/ __init__.py mario.py luigi.py princesa.py ... enemigos/ __init__.py seta.py tortuga.py bomba.py ...
    • Módulosjuego/ __init__.py bonus/ __init__.py >>> from juego.personajes.mario import Mario estrella.py >>> Mario() moneda.py planta.py ... personajes/ __init__.py >>> from juego.personajes.mario import * mario.py >>> Mario() luigi.py princesa.py ... enemigos/ >>> from juego import personajes __init__.py >>> personajes.mario.Mario() seta.py tortuga.py bomba.py ...
    • Estructuras {}
    • Estructuras {}
    • Identación>>> from __future__ import braces File "<stdin>", line 1 SyntaxError: not a chance 4  Espacios  para  la  identación
    • Identación>>> from __future__ import braces File "<stdin>", line 1 SyntaxError: not a chance PEP 8 4  Espacios  para  la  identación
    • ¿PEP  8? PEP 8•  Guido  van  Rossum  (2001)•  Recomendaciones  de  es0lo•  “Readability  counts”•  “Code  is  read  much  more  oQen  than  it  is  wriSen.”•  Muy  recomendable  importante  seguirlo.  h>p://www.python.org/dev/peps/pep-­‐0008/
    • Funcionesdef my_first_function(p1, p2): return "Hello World!" Minúsculas Palabras  separadas  por  _ Evitar  camelCase
    • Funciones 21 def my_first_function(p1, p2): 3 return "Hello World!" PEP 8 Minúsculas Palabras  separadas  por  _ Evitar  camelCase
    • Conversión  de  -pos  h>p://docs.python.org/library/func-ons.html
    • Conversión  de  -pos>>> int(1.3)1  h>p://docs.python.org/library/func-ons.html
    • Conversión  de  -pos>>> int(1.3)1>>> str(2)2  h>p://docs.python.org/library/func-ons.html
    • Conversión  de  -pos>>> int(1.3)1>>> str(2)2>>> float(1)1.0  h>p://docs.python.org/library/func-ons.html
    • Conversión  de  -pos>>> int(1.3)1 >>> tuple([1,2,3]) (1, 2, 3)>>> str(2)2>>> float(1)1.0  h>p://docs.python.org/library/func-ons.html
    • Conversión  de  -pos>>> int(1.3)1 >>> tuple([1,2,3]) (1, 2, 3)>>> str(2)2 >>> list((1,2,3)) [1, 2, 3]>>> float(1)1.0  h>p://docs.python.org/library/func-ons.html
    • Funciones  comunes  h>p://docs.python.org/library/func-ons.html
    • Funciones  comunes>>> len("Python Mola")11>>> len([1,2,3,4])4  h>p://docs.python.org/library/func-ons.html
    • Funciones  comunes>>> len("Python Mola")11>>> len([1,2,3,4])4>>> range(5)[0, 1, 2, 3, 4]>>> range(1,7)[1, 2, 3, 4, 5, 6]>>> range(1,7,2)[1, 3, 5]  h>p://docs.python.org/library/func-ons.html
    • Funciones  comunes >>> type(True)>>> len("Python Mola") <type bool>11 >>> type("Python Mola")>>> len([1,2,3,4]) <type str>4>>> range(5)[0, 1, 2, 3, 4]>>> range(1,7)[1, 2, 3, 4, 5, 6]>>> range(1,7,2)[1, 3, 5]  h>p://docs.python.org/library/func-ons.html
    • Funciones  comunes >>> type(True)>>> len("Python Mola") <type bool>11 >>> type("Python Mola")>>> len([1,2,3,4]) <type str>4>>> range(5) >>> sum([0,1,2,3,4])[0, 1, 2, 3, 4] 10>>> range(1,7) >>> sum(range(5))[1, 2, 3, 4, 5, 6] 10>>> range(1,7,2)[1, 3, 5] Y  un  muy  largo  etc...  h>p://docs.python.org/library/func-ons.html
    • Funciones  interesantes Son  sólo  un  ejemplo...  h>p://docs.python.org/library/func-ons.html
    • Funciones  interesantes>>> a = [1,2,3]>>> b = [4,5,6]>>> zip(a,b)[(1, 4), (2, 5), (3, 6)] Son  sólo  un  ejemplo...  h>p://docs.python.org/library/func-ons.html
    • Funciones  interesantes>>> a = [1,2,3]>>> b = [4,5,6]>>> zip(a,b)[(1, 4), (2, 5), (3, 6)]>>> sorted([5,1,3,4,2])[1, 2, 3, 4, 5] Son  sólo  un  ejemplo...  h>p://docs.python.org/library/func-ons.html
    • Funciones  interesantes>>> a = [1,2,3]>>> b = [4,5,6] >>> round(1.2345, 2)>>> zip(a,b) 1.23[(1, 4), (2, 5), (3, 6)]>>> sorted([5,1,3,4,2])[1, 2, 3, 4, 5] Son  sólo  un  ejemplo...  h>p://docs.python.org/library/func-ons.html
    • Funciones  interesantes>>> a = [1,2,3]>>> b = [4,5,6] >>> round(1.2345, 2)>>> zip(a,b) 1.23[(1, 4), (2, 5), (3, 6)]>>> sorted([5,1,3,4,2]) >>> map(str,[1,2,3,4,5])[1, 2, 3, 4, 5] [1, 2, 3, 4, 5] Son  sólo  un  ejemplo...  h>p://docs.python.org/library/func-ons.html
    • Funciones  de  ayuda
    • Funciones  de  ayuda>>> dir([1,2,3])[__add__, __class__, __contains__, __delattr__, __delitem__,__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]
    • Funciones  de  ayuda>>> dir([1,2,3])[__add__, __class__, __contains__, __delattr__, __delitem__,__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)
    • Clasesclass Student(object): def __init__(self, name, age): self.name = name self.age = age def hello(self): return My name is %s % self.name s = Student("Jorge", 24) camelCase
    • Clases 1 2class Student(object): 3 def __init__(self, name, age): 4 self.name = name self.age = age def hello(self): 5 return My name is %s % self.name s = Student("Jorge", 24) PEP 8 camelCase
    • El  operador  ()• Es  importante  diferenciar: funcion      vs      funcion() Clase              vs        Clase()• El  operador  ()  permite: • Invocar  funciones: resultado = funcion() • Instanciar  clases: objeto = Clase("param1")
    • Sentencias:  if-­‐else$name = "Jon"; name = "Jon"if($name == "Jon"){ if name == "Jon": $name = "Jon Rocks!"; name = "Jon Rocks!"} elif name == "Mary":elseif($name == "Mary"){ name = "Hello Mary" $name = "Hello Mary"; else:} name = "Who are you?"else{ $name = "Who are you?"}
    • Sentencias:  while $count = 0; while ($count < 5) { echo "Number ".$count; $count+=1; } count = 0 while count < 5: print "Number %i" % count count+=1
    • Sentencias:  for for ($i=0; $i < 5; $i++) { echo "Number ".$count; } for i in range(4): print "Number %i" % count
    • Sentencias:  try-­‐except try { $result = 3 / 0; } catch (Exception $e) { echo "Division by Zero" } try: result = 3 / 0 except: print "Division by Zero"
    • Conclusiones•  Python  es  un  lenguaje  fácil  de  aprender.•  Menos  código: •  Muchos  Muchísimos  menos  errores  de  Sintaxis. •  Mayor  velocidad  de  escritura.•  Proto0pado...  U0lizado  por  grandes  empresas.
    • Conclusiones•  Python  es  un  lenguaje  fácil  de  aprender.•  Menos  código: •  Muchos  Muchísimos  menos  errores  de  Sintaxis. •  Mayor  velocidad  de  escritura.•  Proto0pado...  U0lizado  por  grandes  empresas. etc...
    • Evolución  de  la  Web Desarrollo  Web1ª  Generación 2ª  Generación 3ª  Generación HTML PHP Django CGI ASP Rails JSP Symfony ... ...
    • Frameworks  web
    • Django:  Qué  y  dónde
    • Filosoa•  Loose  coupling,    Acoplamiento  débil. •  Cada  capa  es  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)
    • Filosoa•  Loose  coupling,    Acoplamiento  débil. •  Cada  capa  es  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.”
    • Filosoa•  Explicit  is  beSer  than  implicit. •  Este  es  un  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.  h>p://docs.djangoproject.com/en/dev/misc/design-­‐philosophies/
    • La  comunidad
    • La  comunidad• django-­‐users 22.000  miembros• django-­‐developers 7.000  miembros• djangoproject.com +500.000  visitas  únicas  mensuales
    • ¿Quién  usa  Django?
    • ¿Quién  usa  Django?
    • Bienvenidos  al  mundo  de  Oz
    • Ficheros  y  Carpetas ¿Es  Django  tán  simple  y  fácil  de  usar? *  Incluida  la  carpeta  del  proyecto
    • Ficheros  y  Carpetas ¿Es  Django  tán  simple  y  fácil  de  usar?FicherosCarpetas *  Incluida  la  carpeta  del  proyecto
    • Ficheros  y  Carpetas ¿Es  Django  tán  simple  y  fácil  de  usar? Rails SymfonyFicheros 149 117Carpetas 35 29 *  Incluida  la  carpeta  del  proyecto
    • Ficheros  y  Carpetas ¿Es  Django  tán  simple  y  fácil  de  usar? Rails SymfonyFicheros 149 117Carpetas 35 29 *  Incluida  la  carpeta  del  proyecto
    • Ficheros  y  Carpetas ¿Es  Django  tán  simple  y  fácil  de  usar? Rails Symfony DjangoFicheros 149 117 5Carpetas 35 29 2 *  Incluida  la  carpeta  del  proyecto
    • Let’s  enjoy
    • Crear  nuestro  proyecto de  5  ficheros  ;-­‐)
    • Crear  nuestro  proyecto de  5  ficheros  ;-­‐) $ django-admin startproject dwitter
    • Crear  nuestro  proyecto de  5  ficheros  ;-­‐) $ django-admin startproject dwitter . !"" dwitter #   !"" __init__.py #   !"" settings.py #   !"" urls.py #   $"" wsgi.py $"" manage.py -­‐  ¿Esto  es  un  proyecto...  ?      Si  os  ve  mi  jefe... -­‐  Sí,  disponemos  de  un  proyecto  ‘funcional’  en  django.
    • seungs.py
    • Arrancar  nuestro  proyecto de  5  ficheros  ;-­‐)
    • Arrancar  nuestro  proyecto de  5  ficheros  ;-­‐) $ cd dwitter $ 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.
    • Arrancar  nuestro  proyecto de  5  ficheros  ;-­‐) $ cd dwitter $ 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.
    • MVC  en  DjangoModelo  =  Model Vista  =  Template Controlador  =  URL+View
    • URLs  y  Vistas• El  fichero  urls.py  actúa  como  puerta  de  entrada  para  las   pe0ciones  HTTP• Se  definen  URLs  elegantes  mediante  expresiones  regulares   que  redirigen  a  funciones  de  views.py hSp://mysite.com/about/ urls.py ¿urlpaSerns? html views.py ...
    • URLs  y  Vistas• La  función  de  views.py  recibe  como  parámetros  un  objeto   H>pRequest  y  todos  los  parámetros  de  la  URL  capturados,   teniendo  que  devolver  siempre  un  objeto  H>pResponse H>pRequest(),  ... views.py H>pResponse()
    • URLs  y  Vistas Ejemplo  1:    http://mysite.com/time from django.conf.urls.defaults import * from mysite.views import hora_actual urls.py urlpatterns = patterns(, url(r^time/$, hora_actual), ) from django.http import HttpResponse from datetime import datetimeviews.py def hora_actual(request): now = datetime.now() html = "Son las %s." % now return HttpResponse(html)
    • URLs  y  Vistas Ejemplo  2:    http://mysite.com/time/plus/2 from django.conf.urls.defaults import * from mysite.views import dentro_de urls.py urlpatterns = patterns(, url(r^time/plus/(d{1,2})/$, dentro_de), ) from django.http import HttpResponse from datetime import datetime, timedelta def dentro_de(request, offset):views.py offset = int(offset) dt = datetime.now() + timedelta(hours=offset) html = "En %i hora(s), serán las %s." % (offset, dt) return HttpResponse(html)
    • URLs  y  Vistas Ejemplo  2:    http://mysite.com/time/plus/2 from django.conf.urls.defaults import * from mysite.views import dentro_de urls.py urlpatterns = patterns(, url(r^time/plus/(d{1,2})/$, dentro_de), ) from django.http import HttpResponse from datetime import datetime, timedelta def dentro_de(request, offset):views.py offset = int(offset) dt = datetime.now() + timedelta(hours=offset) html = "En %i hora(s), serán las %s." % (offset, dt) return HttpResponse(html)
    • ¡Recuerda!:  MVC
    • Templates• Separan  la  lógica  de  presentación  a  una  capa  independiente. • Ficheros  independientes  (.html) • Lenguaje  independiente  (¡para  diseñadores!)
    • Templates • Se  basan  en  dos  0pos  de  objetos:  Template()  y  Context(). • Un  objeto  Template()  con0ene  el  string  de  salida  que   queremos  devolver  en  el  HSpResponse  (normalmente   HTML),  pero  incluyendo  e0quetas  especiales  de  Django. • Un  objeto  Context()  con0ene  un  diccionario  con  los   valores  que  dan  contexto  a  una  plan0lla,  los  que  deben   usarse  para  renderizar  un  objeto  Template().Template: "Bienvenido, {{ user }}." "Bienvenido, alatar." Context: {user: alatar}
    • Templates• Primera  aproximación  al  obje0vo:  Template  +  Context from django.http import HttpResponse from django.template import Template, Context 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)
    • Templates• Segunda  aproximación  al  obje0vo:  open(),  read(),  close() from django.http import HttpResponse from django.template import Template, Context from datetime import datetime def hora_actual(request): now = datetime.now() fp = open(/home/django/templates/hora.html) t = Template(fp.read()) fp.close() c = Context({hora: now}) html = t.render(c) return HttpResponse(html)
    • Templates• Segunda  aproximación  al  obje0vo:  open(),  read(),  close() from django.http import HttpResponse from django.template import Template, Context from datetime import datetime def hora_actual(request): now = datetime.now() fp = open(/home/django/templates/hora.html) t = Template(fp.read()) fp.close() c = Context({hora: now}) html = t.render(c) return HttpResponse(html)
    • Templates• Segunda  aproximación  al  obje0vo:  open(),  read(),  close() from django.http import HttpResponse from django.template import Template, Context from datetime import datetime def hora_actual(request): now = datetime.now() Bo ring   plate   fp = open(/home/django/templates/hora.html) boiler t = Template(fp.read()) fp.close() code! c = Context({hora: now}) html = t.render(c) return HttpResponse(html)
    • Templates• Tercera  aproximación  al  obje0vo:  get_template() TEMPLATE_DIRS = ( seungs.py /home/django/templates, ) 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)
    • Templates• Tercera  aproximación  al  obje0vo:  get_template() TEMPLATE_DIRS = ( seungs.py /home/django/templates, ) 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)
    • Templates• Tercera  aproximación  al  obje0vo:  get_template() TEMPLATE_DIRS = ( seungs.py /home/django/templates, ) 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): S0ll   now = datetime.now() t = get_template(hora.html) c = Context({hora: now}) html = t.render(c) boring... return HttpResponse(html)
    • Templates• Obje0vo  alcanzado:  render() from django.shortcuts import render from datetime import datetime def hora_actual(request): now = datetime.now() return render(request, hora.html, {hora: now})
    • Templates• Obje0vo  alcanzado:  render() from django.shortcuts import render from datetime import datetime def hora_actual(request): now = datetime.now() return render(request, hora.html, {hora: now}) Bori ng...?
    • Templates• Obje0vo  alcanzado:  render() from django.shortcuts import render from datetime import datetime def hora_actual(request): now = datetime.now() return render(request, hora.html, {hora: now}) AWESOME!
    • Templates  en  detalle•  Si,  otro  sistema  de  templates •  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
    • Filosoa  y  Limitaciones•  La  sintaxis  debe  estar  desacoplada  del  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.
    • Templates:  {{}}<html> <head>Ejemplo templates</head> <body> Hola, {{ username }}. </body></html> {username: juan}<html> <head>Ejemplo templates</head> <body> Hola, juan. </body></html>
    • Filters  y  Tags
    • Filters  y  Tags
    • Filters  y  Tagsfilter {{ varible|filter }}
    • Filters  y  Tags filter {{ varible|filter }}inline  tag {% tag var1 var2 %}
    • Filters  y  Tags filter {{ varible|filter }}inline  tag {% tag var1 var2 %}block  tag {% tag var1 %} ... {% endtag %}
    • Templates:  tags  {%  %}
    • Templates:  tags  {%  %}comment {% comment %} Bu! {% endcomment %}
    • Templates:  tags  {%  %}comment {% comment %} Bu! {% endcomment %} for {% for elemento in lista %} <li>{{ elemento }}<li> {% endfor %}
    • Templates:  tags  {%  %}comment {% comment %} Bu! {% endcomment %} for {% for elemento in lista %} <li>{{ elemento }}<li> {% endfor %} if {% if username == "Juan" %} Hola Juan, me gustas! == != > < >= <= in and or not {% else %} Hola {{ username }}, {% endif %}
    • Templates:  tags  {%  %}
    • Templates:  tags  {%  %}cycle {% for elemento in lista %} <li class="{% cycle rojo azul %}">{{ elemento }}<li> {% endfor %}
    • Templates:  tags  {%  %} cycle {% for elemento in lista %} <li class="{% cycle rojo azul %}">{{ elemento }}<li> {% endfor %}include {% include "foo/bar.html" %}
    • Templates:  tags  {%  %} cycle {% for elemento in lista %} <li class="{% cycle rojo azul %}">{{ elemento }}<li> {% endfor %}include {% include "foo/bar.html" %}forloop {% for elemento in lista %} <li>{{ forloop.counter }}.{{ elemento }}<li> {% endfor %}
    • Templates:  tags  {%  %} cycle {% for elemento in lista %} <li class="{% cycle rojo azul %}">{{ elemento }}<li> {% endfor %}include {% include "foo/bar.html" %}forloop {% for elemento in lista %} <li>{{ forloop.counter }}.{{ elemento }}<li> {% endfor %}empty {% for elemento in lista %} <li class="{% cycle rojo azul %}">{{ elemento }}<li> {% empty %} Sin elementos. {% endfor %}
    • Templates:  Filters <html> <head>Ejemplo templates</head>-tle <body> Hola, {{ username|title }}. </body> </html> {username: juan} <html> <head>Ejemplo templates</head> <body> Hola, Juan. </body> </html>
    • Templates:  Filters
    • Templates:  Filters {username: Juan es majo}length {{ username|length }} 12
    • Templates:  Filters {username: Juan es majo}length {{ username|length }} 12 cut {{ username|cut }} Juanesmajo
    • Templates:  Filters {username: Juan es majo}length {{ username|length }} 12 cut {{ username|cut }} Juanesmajoslugify {{ username|slugify }} juan-es-majo
    • Templates:  Filters {username: Juan es majo} length {{ username|length }} 12 cut {{ username|cut }} Juanesmajo slugify {{ username|slugify }} juan-es-majowordcount {{ username|wordcount }} 3
    • Templates:  Filters {username: Juan es majo} length {{ username|length }} 12 cut {{ username|cut }} Juanesmajo slugify {{ username|slugify }} juan-es-majowordcount {{ username|wordcount }} 3 upper {{ username|upper }} JUAN ES MAJO
    • Templates:  Filters {username: Juan es majo} length {{ username|length }} 12 cut {{ username|cut }} Juanesmajo slugify {{ username|slugify }} juan-es-majowordcount {{ username|wordcount }} 3 upper {{ username|upper }} JUAN ES MAJO {username: None} default {{ username|default:”Desconocido” }} Desconocido
    • Templates:  Filters
    • Templates:  Filters{username: Juan es <b>majo, guapo y <em>listo</em></b>} striptags {{ username|striptags }} Juan es majo guapo y listo
    • Templates:  Filters {username: Juan es <b>majo, guapo y <em>listo</em></b>} striptags {{ username|striptags }} Juan es majo guapo y listotruncatewords_html {{ username|truncatewords_html:4 }} Juan es <b>majo guapo</b> ...
    • Templates:  Filters {username: Juan es <b>majo, guapo y <em>listo</em></b>} striptags {{ username|striptags }} Juan es majo guapo y listotruncatewords_html {{ username|truncatewords_html:4 }} Juan es <b>majo guapo</b> ... removetags {{ username|removetags:”em a br” }} Juan es <b>majo guapo y listo</b>
    • Templates:  Filters
    • Templates:  Filters {value: 123456789}add {{ value|add:”1” }} 123456790
    • Templates:  Filters {value: 123456789} add {{ value|add:”1” }} 123456790filesizeformat {{ value|filesizeformat }} 117.7MB
    • Templates:  Filters {value: 123456789} add {{ value|add:”1” }} 123456790filesizeformat {{ value|filesizeformat }} 117.7MB {date: datetime.datetime(2010, 9, 11, 17, 1, 59, 385323) } date {{ date|date:”d M Y” }} 11 Sep 2010
    • Templates:  Filters {value: 123456789} add {{ value|add:”1” }} 123456790filesizeformat {{ value|filesizeformat }} 117.7MB {date: datetime.datetime(2010, 9, 11, 17, 1, 59, 385323) } date {{ date|date:”d M Y” }} 11 Sep 2010-mesince {{ date|timesince }} 4 days, 6 hours
    • Templates:  Filters {value: 123456789} add {{ value|add:”1” }} 123456790filesizeformat {{ value|filesizeformat }} 117.7MB {date: datetime.datetime(2010, 9, 11, 17, 1, 59, 385323) } date {{ date|date:”d M Y” }} 11 Sep 2010-mesince {{ date|timesince }} 4 days, 6 hours-meun-l {{ date|timeuntil }} 1 days, 6 hours
    • Herencia  de  Templatesbase.html <html> <head> <title>Mi página personal</title> </head> <body> {% block content %} Contenido por defecto. {% endblock %} </body> </html>hija.html {% extends "base.html" %} {% block content %} Hola desde la portada. {% endblock %}
    • Modelos
    • ¿SQL?
    • Ejemplo  SQLdef book_list(request): try: db = MySQLdb.connect(user=me, db=mydb, passwd=secret, 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})
    • Ejemplo  SQLdef book_list(request): try: 1 2 db = MySQLdb.connect(user=me, db=mydb, passwd=secret, host=localhost) 3 cursor = db.cursor() cursor.execute(SELECT nama FROM books ORDER BY name) 4 names = [] for row in cursor.fetchall() 5 names.append(row[0]) db.close() except: return render_to_response(500.html) 6 return render_to_response(book_list.html, {names:names})
    • 12  lineas  de  Python...  ¬_¬
    • ORM  (Object-­‐Rela0onal  mapping)
    • Ejemplo  ORMdef book_list(request): names = Books.objects.all().order_by(name) return render(request, book_list.html, {names:names})
    • Ejemplo  ORMdef book_list(request):1 names = Books.objects.all().order_by(name) 2 return render(request, book_list.html, {names:names})
    • Fucking  Ninjas!
    • Modelo from django.db import models class Books(models.Model): name = models.CharField(blank=True, 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)  
    • Modelo from django.db import models 1 32 class Books(models.Model): name = models.CharField(blank=True, max_length=100) 4 created = models.DateTimeField(blank=False) 5 available = models.BooleanField(default=True) 6 •  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)  
    • Fucking  Awesome  Ninjas!
    • Tipos  de  Datos• AutoField • IPAdressField• BigIntegerField • NullBooleanField• BooleanField • PositiveIntegerField• CharField • PositiveSmallIntegerField• CommaSeparatedIntegerField • SlugField• DateField • SmallIntegerField• DateTimeField • TextField• DecimalField • TimeField• EmailField • URLField• FileField • XMLField• FilePathField • ForeingKey• FloatField • ManyToManyField• ImageField • OneToOneField• IntegerField
    • Propiedades  de  las  Field• null (True|Flase) • unique (True|False)• blank (True|False) • primary_key• choices (lista) • unique_for_date• default (valor) • unique_for_month• editable (True|False) • unique_for_year• help_text (String)
    • ¿Es  magia?  No. BEGIN; CREATE 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;
    • ¿Es  magia?  No. $ python manage.py sqlall website BEGIN; CREATE 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;
    • Configurar  sesngs.pyDATABASES = { default: { postgresql_psycopg2, ENGINE: django.db.backends., postgresql, mysql, NAME: , sqlite3 or oracle. USER: , PASSWORD: , HOST: , PORT: , }}
    • Configurar  sesngs.pyDATABASES = { default: { postgresql_psycopg2, ENGINE: django.db.backends., 1 postgresql, mysql, NAME: , 2 sqlite3 or oracle. USER: , PASSWORD: , 3 HOST: , PORT: , }}
    • Creando  Tablas•  Crea  las  tablas  para  todos  los  modelos  de  las  apps  instaladas   en  el  fichero  seungs.py•  No  actualiza  esquemas  si  la  tabla  existe. •  Eliminar  tabla  y  volver  a  ejecutar  syncdb
    • Creando  Tablas $ python manage.py syncdb•  Crea  las  tablas  para  todos  los  modelos  de  las  apps  instaladas   en  el  fichero  seungs.py•  No  actualiza  esquemas  si  la  tabla  existe. •  Eliminar  tabla  y  volver  a  ejecutar  syncdb
    • syncdb$ python manage.py syncdbCreating table auth_permissionCreating table auth_groupCreating table auth_userCreating table auth_messageCreating table django_content_typeCreating table django_sessionCreating table django_siteCreating table website_tweetYou just installed Djangos auth system, which means you dont have anysuperusers defined.Would you like to create one now? (yes/no): yesUsername (Leave blank to use neo): adminE-mail address: user@example.comPassword:Password (again):Superuser created successfully.Installing index for auth.Permission modelInstalling index for auth.Message modelInstalling index for website.Tweet model
    • syncdb$ python manage.py syncdbCreating table auth_permissionCreating table auth_groupCreating table auth_user django.contrib.authCreating table auth_messageCreating table django_content_typeCreating table django_sessionCreating table django_siteCreating table website_tweetYou just installed Djangos auth system, which means you dont have anysuperusers defined.Would you like to create one now? (yes/no): yesUsername (Leave blank to use neo): adminE-mail address: user@example.comPassword:Password (again):Superuser created successfully.Installing index for auth.Permission modelInstalling index for auth.Message modelInstalling index for website.Tweet model
    • ¿Cuantos  sistemas  de  Auten0cación  habéis  programado?
    • ¿Alguno  era  mejor  que  el  anterior?  ;-­‐)
    • contrib.auth  puede  ser  el  úl0mo  :D
    • syncdb$ python manage.py syncdbCreating table auth_permissionCreating table auth_groupCreating table auth_userCreating table auth_messageCreating table django_content_typeCreating table django_sessionCreating table django_siteCreating table website_tweet website.tweetYou just installed Djangos auth system, which means you dont have anysuperusers defined.Would you like to create one now? (yes/no): yesUsername (Leave blank to use neo): adminE-mail address: user@example.comPassword:Password (again):Superuser created successfully.Installing index for auth.Permission modelInstalling index for auth.Message modelInstalling index for website.Tweet model
    • syncdb$ python manage.py syncdbCreating table auth_permissionCreating table auth_groupCreating table auth_userCreating table auth_messageCreating table django_content_typeCreating table django_sessionCreating table django_siteCreating table website_tweetYou just installed Djangos auth system, which means you dont have anysuperusers defined.Would you like to create one now? (yes/no): yesUsername (Leave blank to use neo): admin django.contrib.authE-mail address: user@example.comPassword:Password (again):Superuser created successfully.Installing index for auth.Permission modelInstalling index for auth.Message modelInstalling index for website.Tweet model
    • BD  Lista  para  usarse
    • BD  Lista  para  usarse
    • Previo:  Clases  del  ORM ts = Publisher.objects.all() Model Manager QuerySet
    • INSERT
    • INSERT o = Model(...) o.save()a) >>> p = Publisher( ... name=Apress, ... address=2855 Telegraph Avenue, ... city=Berkeley, ... state_province=CA, ... country=U.S.A., ... website=http://www.apress.com/) >>> p.save()
    • INSERT o = Model(...) o.save()a) >>> p = Publisher( ... name=Apress, ... address=2855 Telegraph Avenue, ... city=Berkeley, ... state_province=CA, ... country=U.S.A., ... website=http://www.apress.com/) >>> p.save() manager.create(...)b) >>> p = Publisher.objects.create( ... name=OReilly, ... address=10 Fawcett St., ... city=Cambridge, ... state_province=MA, ... country=U.S.A., ... website=http://www.oreilly.com/)
    • UPDATE
    • UPDATE o.save() >>> ... >>> p.id1 52 >>> p.name = Apress Publishing >>> p.save()
    • UPDATE o.save() >>> ... >>> p.id1 52 >>> p.name = Apress Publishing >>> p.save() queryset.update(...)n >>> Publisher.objects.all().update(country=USA) 2
    • DELETE
    • DELETE o.delete() >>> ... >>> p.id1 52 >>> p.delete()
    • DELETE o.delete() >>> ... >>> p.id1 52 >>> p.delete() queryset.delete() >>> ps = Publisher.objects.all()n >>> ps.delete()
    • SELECT  de  1  resultado
    • SELECT  de  1  resultado .get(...) >>> Publisher.objects.get(name="Apress") <Publisher: Apress>
    • SELECT  de  1  resultado .get(...) >>> Publisher.objects.get(name="Apress") <Publisher: Apress>>>> Publisher.objects.get(name="Anaya")Traceback (most recent call last): ...DoesNotExist: Publisher matching query does not exist.
    • SELECT  de  1  resultado .get(...) >>> Publisher.objects.get(name="Apress") <Publisher: Apress>>>> Publisher.objects.get(name="Anaya")Traceback (most recent call last): ...DoesNotExist: Publisher matching query does not exist.>>> 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.}
    • SELECT  de  N  resultados
    • SELECT  de  N  resultados .all() >>> Publisher.objects.all() [<Publisher: Apress>, <Publisher: OReilly>]
    • SELECT  de  N  resultados .all() >>> Publisher.objects.all() [<Publisher: Apress>, <Publisher: OReilly>] .filter(...) >>> Publisher.objects.filter( country="U.S.A.", state_province="CA") [<Publisher: Apress>]
    • SELECT  de  N  resultados .all() >>> Publisher.objects.all() [<Publisher: Apress>, <Publisher: OReilly>] .filter(...) >>> Publisher.objects.filter( country="U.S.A.", state_province="CA") [<Publisher: Apress>] .exclude(...) >>> Publisher.objects.exclude( country="U.S.A.", state_province="CA") [<Publisher: OReilly>]
    • SELECT  de  N  resultadosen   evuelv ¡D s,  no   .all() uery Set Q li stas! >>> Publisher.objects.all() [<Publisher: Apress>, <Publisher: OReilly>] .filter(...) >>> Publisher.objects.filter( country="U.S.A.", state_province="CA") [<Publisher: Apress>] .exclude(...) >>> Publisher.objects.exclude( country="U.S.A.", state_province="CA") [<Publisher: OReilly>]
    • get(),  filter()  y  exclude()
    • get(),  filter()  y  exclude() Modelo.objects.filter(campo1="valor1", campo2="valor2")Los  parámetros  pueden  indicar  mucho  más  que  igualdad  (=)
    • get(),  filter()  y  exclude() Modelo.objects.filter(campo1="valor1", campo2="valor2") Los  parámetros  pueden  indicar  mucho  más  que  igualdad  (=)campo__exact= campo__gt=0 campo__startswith=campo__iexact= campo__gte=0 campo__istartswith=campo__contains= campo__lt=0 campo__endswith=campo__icontains= campo__lte=0 campo__iendswith=campo__isnull=T|F campo__in=[ ,] campo__range=( ,)campo__day=31 campo__month=12 campo__year=2010
    • ORDER  BY
    • ORDER  BY .order_by(...)>>> Publisher.objects.order_by("name")[<Publisher: Apress>, <Publisher: OReilly>]
    • ORDER  BY .order_by(...)>>> Publisher.objects.order_by("name")[<Publisher: Apress>, <Publisher: OReilly>]>>> Publisher.objects.order_by("-name")[<Publisher: OReilly>, <Publisher: Apress>]
    • ORDER  BY .order_by(...) >>> Publisher.objects.order_by("name") [<Publisher: Apress>, <Publisher: OReilly>] >>> Publisher.objects.order_by("-name") [<Publisher: OReilly>, <Publisher: Apress>] Múl0ples  campos:>>> Publisher.objects.order_by("-name", "country")[<Publisher: OReilly>, <Publisher: Apress>]
    • ORDER  BY ¡También   devu elve   .order_by(...) uer y Sets! Q >>> Publisher.objects.order_by("name") [<Publisher: Apress>, <Publisher: OReilly>] >>> Publisher.objects.order_by("-name") [<Publisher: OReilly>, <Publisher: Apress>] Múl0ples  campos:>>> Publisher.objects.order_by("-name", "country")[<Publisher: OReilly>, <Publisher: Apress>]
    • Slicing
    • Slicing [n:m]>>> Publisher.objects.order_by("name")[0]<Publisher: Apress>>>> Publisher.objects.order_by("name")[:2][<Publisher: Apress>, <Publisher: OReilly>]>>> Publisher.objects.order_by("name")[1:2][<Publisher: OReilly>]
    • Slicing [n:m]>>> Publisher.objects.order_by("name")[0]<Publisher: Apress>>>> Publisher.objects.order_by("name")[:2][<Publisher: Apress>, <Publisher: OReilly>] LIMIT>>> Publisher.objects.order_by("name")[1:2][<Publisher: OReilly>]
    • Slicing [n:m]>>> Publisher.objects.order_by("name")[0]<Publisher: Apress>>>> Publisher.objects.order_by("name")[:2][<Publisher: Apress>, <Publisher: OReilly>] LIMIT>>> Publisher.objects.order_by("name")[1:2][<Publisher: OReilly>] O FFSET
    • Related  Objects
    • Related  Objects OneToOneField class Coche(models.Model):1 motor = OneToOneField(Motor) class Motor(models.Model):1 ...
    • Related  Objects OneToOneField class Coche(models.Model): 1 motor = OneToOneField(Motor) class Motor(models.Model): 1 ... ¿Cómo  usamos  la  relación  desde  las  instancias? Gracias  a  nosotros>>> c.motor<Motor: Motor object>
    • Related  Objects OneToOneField class Coche(models.Model): 1 motor = OneToOneField(Motor) class Motor(models.Model): 1 ... ¿Cómo  usamos  la  relación  desde  las  instancias? Gracias  a  nosotros Gracias  a  Django>>> c.motor >>> m.coche<Motor: Motor object> <Coche: Coche object>
    • Related  Objects
    • Related  Objects ForeignKeyField class Blog(models.Model):1 ... class Post(models.Model):n blog = ForeignKeyField(Blog)
    • Related  Objects ForeignKeyField class Blog(models.Model): 1 ... class Post(models.Model): n blog = ForeignKeyField(Blog) ¿Cómo  usamos  la  relación  desde  las  instancias? Gracias  a  nosotros Gracias  a  Django>>> p.blog >>> b.post_set.all()<Blog: Blog object> [<Post: Post object>, ...]
    • Related  Objects
    • Related  Objects ManyToManyField class Post(models.Model):n tags = ManyToManyField(Tag) class Tag(models.Model):m ...
    • Related  Objects ManyToManyField class Post(models.Model): n tags = ManyToManyField(Tag) class Tag(models.Model): m ... ¿Cómo  usamos  la  relación  desde  las  instancias? Gracias  a  nosotros Gracias  a  Django>>> p.tags.add(t1, t2) >>> t.post_set.add(p1, p2)>>> p.tags.all() >>> t.post_set.all()[<Tag: Tag object>, ...] [<Post: Post object>, ...]
    • Related  Objects
    • Related  ObjectsEn  todas  ellas  podemos  renombrar  el  puntero  inverso class Blog(models.Model): 1 ... class Post(models.Model): n blog = ForeignKeyField(Blog, related_name=posts)
    • Related  ObjectsEn  todas  ellas  podemos  renombrar  el  puntero  inverso class Blog(models.Model): 1 ... class Post(models.Model): n blog = ForeignKeyField(Blog, related_name=posts) Gracias  a  nosotros Gracias  a  Django >>> p.blog >>> b.posts.all() <Blog: Blog object> [<Post: Post object>, ...]
    • Related  ObjectsEn  todas  ellas  podemos  renombrar  el  puntero  inverso class Blog(models.Model): 1 ... class Post(models.Model): n blog = ForeignKeyField(Blog, related_name=posts) Gracias  a  nosotros Gracias  a  Django >>> p.blog >>> b.posts.all() <Blog: Blog object> [<Post: Post object>, ...]Cuando  haya  2  relaciones  entre  2  modelos,  será  obligatorio
    • Y  la  guinda  final:  ¡Todo  es  LAZY!
    • Laziness
    • Laziness• Las  consultas  sólo  se  ejecutarán  cuando  realmente  se   necesite  obtener  los  objetos.  En  las  siguientes  situaciones: • Iteraciones for p in Publisher.objects.all(): • Slicing Publisher.objects.filter(country=USA)[0] • Serialización [Caché] • repr() [<Publisher: Publisher object>] • len() !!! len(Publisher.objects.all()) • list() list(Publisher.objects.all()) • bool() if Publisher.objects.filter(country=USA):
    • CRUD:  Create,  Retrieve,  Update  &  Delete
    • django.contrib.admin1 2 3
    • django.contrib.admin 1 2 3
    • django.contrib.admin1
    • Django  admin:  Instalación urls.py from django.conf.urls.defaults import * # Uncomment the next two lines to enable the admin: # from django.contrib import admin 1 # admin.autodiscover() urlpatterns = patterns(, ... 2 # url(r^admin/, include(admin.site.urls)), ... )
    • Django  admin:  Instalación urls.py from django.conf.urls.defaults import * # Uncomment the next two lines to enable the admin: from django.contrib import admin 1 admin.autodiscover() urlpatterns = patterns(, ... 2 url(r^admin/, include(admin.site.urls)), ... )
    • Django  admin:  Instalación seungs.py INSTALLED_APPS = ( django.contrib.auth, django.contrib.contenttypes, django.contrib.sessions, django.contrib.sites, django.contrib.admin, 1 ... )
    • Actualizando  la  BD
    • Actualizando  la  BD $ python manage.py syncdb Creating table django_admin_log Installing index for admin.LogEntry model Admin  lista  para  usar
    • ¿Y  nuestra  app? ?
    • ¿Y  nuestra  app?
    • admin.py• Cada  app  debe  de  tener  el  suyo.• 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)
    • 1,2,3  Borrar  la  BD....  1,2,3...  Borrar  la  BD
    • Fixtures
    • Fixtures•  Es  muy  aburrido  crear  juegos  de  datos  cada  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:
    • Fixtures•  Es  muy  aburrido  crear  juegos  de  datos  cada  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 ...>
    • Fixtures•  Es  muy  aburrido  crear  juegos  de  datos  cada  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  u0lizando: python manage.py loaddata <fixture fixture ...>•  Si  se  llaman  ini<al_data  y  están  dentro  de  la  carpeta  fixtures   de  la  app,  se  cargan  al  ahcer  el  syncdb.
    • Formularios
    • Clases  involucradas
    • Clases  involucradasWidget Componente  visual  equivalente  a  HTML TextInput <input type=text...> CheckboxInput <input type=checkbox...>
    • Clases  involucradasWidget Componente  visual  equivalente  a  HTML TextInput <input type=text...> CheckboxInput <input type=checkbox...>Field Lógica  de  un  campo,  asociado  a  un  Widget EmailField widget, initial, error, ... IPAddressField
    • Clases  involucradasWidget Componente  visual  equivalente  a  HTML TextInput <input type=text...> CheckboxInput <input type=checkbox...>Field Lógica  de  un  campo,  asociado  a  un  Widget EmailField widget, initial, error, ... IPAddressField Form Conjunto  de  Fields  de  un  formulario ContactForm [nombre, email, telefono, mensaje, ...]
    • Fields
    • Fields■ BooleanField ■ IPAddressField■ CharField ■ MultipleChoiceField■ ChoiceField ■ NullBooleanField■ TypedChoiceField ■ RegexField■ DateField ■ SlugField■ DateTimeField ■ TimeField■ DecimalField ■ URLField■ EmailField ■ ComboField■ FileField ■ MultiValuefield■ FilePathField ■ SplitDateTimeField■ FloatField ■ ModelChoiceField■ ImageField ■ ModelMultipleChoiceField■ IntegerField
    • Creación  de  un  Form• Paso  1/3:  Definición  del  formulario  en  forms.py from django import forms class ContactForm(forms.Form): subject = forms.CharField(max_length=100, label=Topic) email = forms.EmailField(required=False) message = forms.CharField(widget=forms.Textarea)
    • Creación  de  un  Form• Paso  2/3:  Maquetación  del  formulario  en  su  template <html> <body> <h1>Contact us</h1> {% if form.errors %} <p style="color: red;"> Please correct the error{{ form.errors|pluralize }} below. </p> {% endif %} <form action="" method="post"> <table> {{ form.as_table }} </table> <input type="submit" value="Submit"> </form> </body> </html>
    • Creación  de  un  Form• Paso  3/3:  Programación  de  la  vista  en  views.py from django.shortcuts import render from mysite.contact.forms 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})
    • Creación  de  un  Form• Paso  3/3:  Programación  de  la  vista  en  views.py from django.shortcuts import render from mysite.contact.forms import ContactForm def contact(request): if request.method == POST: Pa _ern 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})
    • Creación  de  un  Form• Paso  3/3:  Programación  de  la  vista  en  views.py from django.shortcuts import render from mysite.contact.forms import ContactForm def contact(request): if request.method == POST: Pa _ern 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})
    • Creación  de  un  Form• Paso  3/3:  Programación  de  la  vista  en  views.py from django.shortcuts import render from mysite.contact.forms import ContactForm def contact(request): if request.method == POST: Pa _ern 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})
    • Validación  propia Podemos  programar  validación  extra  asociada  a  cada  Field  del  formulario  escribiendo  un  método  clean_<fieldname>: from django import forms class ContactForm(forms.Form): subject = forms.CharField(max_length=100) email = forms.EmailField(required=False) message = forms.CharField(widget=forms.Textarea) def clean_message(self): message = self.cleaned_data[message] num_words = len(message.split()) if num_words < 4: raise forms.ValidationError("Not enough words!") return message
    • Validación  propia Podemos  programar  validación  extra  asociada  a  cada  Field  del  formulario  escribiendo  un  método  clean_<fieldname>: from django import forms class ContactForm(forms.Form): subject = forms.CharField(max_length=100) email = forms.EmailField(required=False) message = forms.CharField(widget=forms.Textarea) def clean_message(self): message = self.cleaned_data[message] num_words = len(message.split()) if num_words < 4: raise forms.ValidationError("Not enough words!") return message
    • Maquetación  propia Podemos  personalizar  la  maquetación  tanto  como   queramos,  prescindiendo  de  las  ayudas  de  form.as_table:...<form action="" method="post"> <div class="field"> {{ form.subject.errors }} Para  los  diseñadores: <label for="id_subject">Subject:</label> {{ form.subject }} <style type="text/css"> </div> ul.errorlist { <div class="field"> ... {{ form.email.errors }} } <label for="id_email">E-mail:</label> .errorlist li { {{ form.email }} ... </div> } ... </style> <input type="submit" value="Submit"></form>...
    • Forms  a  par0r  de  Models:  El  COLMO  del  DRY
    • Forms  a  par-r  de  Models from django.db import models class Author(models.Model):models.py 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 forms.py class AuthorForm(forms.ModelForm): class Meta: model = Author exclude = (country,)
    • Magia  avanzada
    • ROSA
    • NUNCAROSA
    • NUNCAINFRAVALORÉISROSA
    • NUNCAINFRAVALORÉISEL  PODERROSA
    • NUNCAINFRAVALORÉISEL  PODERDE  UN   PONYROSA
    • Views  avanzadas Generic  Views Vistas  con  funcionalidad  genérica  parametrizable   mediante  un  diccionario  de  Extra  Op-ons Las  tuplas  de  pa>erns()  pueden  tener  3  elementosfrom django.conf.urls.defaults import *from mysite import viewsurlpatterns = patterns(, url(r^foo/$, views.foobar_view, {template_name: template1.html}), url(r^bar/$, views.foobar_view, {template_name: template2.html}),)
    • Views  avanzadas from django.views.generic.simple import direct_to_template Renderiza  directamente  la  template  indicadafrom django.conf.urls.defaults import *from django.views.generic.simple import direct_to_templateurlpatterns = patterns(, url(r^about/$, direct_to_template, {template: about.html})) Es  la  Generic  View  más  simple  y  más  u+lizada
    • Template  LibraryNos  permite  extender  el  sistema  de  templates   de  Django  con  Filters  y  Tags  propios
    • Template  LibraryNos  permite  extender  el  sistema  de  templates   de  Django  con  Filters  y  Tags  propios Uso{% load milibreria %}...{{ variable|mifiltro:"param" }}...{% mitag param1 param2 %}
    • Template  LibraryNos  permite  extender  el  sistema  de  templates   de  Django  con  Filters  y  Tags  propios Uso Creación{% load milibreria %}...{{ variable|mifiltro:"param" }}...{% mitag param1 param2 %}
    • Custom  FiltersUn  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.
    • Custom  FiltersUn  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() Ejemplo def cut(value, arg= ): return value.replace(arg, ) register.filter(cut, cut)
    • Custom  FiltersUn  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, )
    • Custom  FiltersUn  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 Py thon   register = template.Library()2.4  se  hizo   @register.filter(name=cut) sexy def cut(value, arg= ): return value.replace(arg, )
    • Custom  Tags El  método  genérico  para  crear  Tags  es  complejo.Vamos  a  ver  cómo  crear  los  2  +pos  de  Tags  más  sencillos: SimpleTags InclusionTags• Son  inline • Son  inline• Reciben  1  argumento • Reciben  n  argumentos• Devuelven  un  string • Devuelven  un  diccionario • Insertan  su  propio   fragmento  de  template
    • SimpleTagsEjemplo:  Devolver  la  hora  actual  formateada. {% current_time "%Y-%m-%d %I:%M %p" %}
    • SimpleTags Ejemplo:  Devolver  la  hora  actual  formateada. {% current_time "%Y-%m-%d %I:%M %p" %}from django import templateregister = template.Library()@register.simple_tagdef current_time(format): try: return datetime.datetime.now().strftime(str(format)) except UnicodeEncodeError: return
    • InclusionTags Ejemplo:  Mostar  anuncios  si  el  usuario  no  es  premium. {% show_adverts user %}milibreria.py {% for advert in adverts %}adverts.html <img src={{ advert.image }} /> {% endfor %}
    • InclusionTags Ejemplo:  Mostar  anuncios  si  el  usuario  no  es  premium. {% show_adverts user %} @register.inclusion_tag(website/adverts.html) def show_adverts(user): adverts = []milibreria.py if not user.profile.is_premium: adverts = Advert.objects.order_by(?).limit(5) return {adverts: adverts} {% for advert in adverts %}adverts.html <img src={{ advert.image }} /> {% endfor %}
    • Middleware Nos  permite  escribir  funcionalidad  reu0lizable  que  se  inserta  en  el  flujo  de  ejecución  de  Django
    • Middlewareclass MyMiddleware(object): def process_request(self, request): """Se ejecuta antes de 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.""" # ...
    • MiddlewareTenemos  que  incluir  nuestro  middleware  en  el  lugar  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,)
    • Middleware1. Sistema  de  BETA 1. Nos  aseguramos  de  controlar  todas  páginas. 2. Si  el  usuario  +ene  una  IP  o  un  User  o...2. Si6o  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...
    • InternacionalizaciónOfrece  integración  con  la  librería  GNU  ge>ext  de  i18n1. Un  fichero  .pot  con+ene  todos  los  strings  usados contabilidad.pot2. En  cada  fichero  .po  se  guarda  una  traducción es_ES.pot      es_AR.pot      en_GB.pot3. Cada  .po  se  compila  y  genera  un  .mo  binario es_ES.mo      es_AR.mo      en_GB.mo
    • Internacionalización• ¿Cómo  indicar  qué  strings  deben  ser  traducidos?• Ges+ón  cómoda  de  singulares  y  plurales
    • Internacionalización• ¿Cómo  indicar  qué  strings  deben  ser  traducidos? from django.utils.translation import ugettext as _ print _("Cadena de texto")• Ges+ón  cómoda  de  singulares  y  plurales
    • Internacionalización• ¿Cómo  indicar  qué  strings  deben  ser  traducidos? from django.utils.translation import ugettext as _ print _("Cadena de texto")• Ges+ón  cómoda  de  singulares  y  plurales from django.utils.translation import ungettext frase = ungettext("Hay %(total)d resultado", "Hay %(total)d resultados", total) % { total: total }
    • caching• Si  queremos  escalar  nuestro  proyecto  rápidamente....  Cache! • Recomendado  =  memcached• Acceder  a  la  BD  es  caro,  muy  caro.• El  Hardware  es  “gra0s”  en  comparación  con  op0mizar  código  op0mizado.• Ejemplo  (Facebook):
    • caching• Si  queremos  escalar  nuestro  proyecto  rápidamente....  Cache! • Recomendado  =  memcached• Acceder  a  la  BD  es  caro,  muy  caro.• El  Hardware  es  “gra0s”  en  comparación  con  op0mizar  código  op0mizado.• Ejemplo  (Facebook): 300+Tb  Memcached
    • cachingviews from django.views.decorators.cache import cache_page @cache_page(60 * 15) def my_view(request): ...
    • caching views from django.views.decorators.cache import cache_page @cache_page(60 * 15) def my_view(request): ...templates {% load cache %} {% cache 500 sidebar %} .. sidebar .. {% endcache %}
    • cachinglow  level
    • cachinglow  level >>> from django.core.cache import cache >>> cache.set(my_key, hello, world!, 30) >>> cache.get(my_key) hello, world! • Podemos  cachear  cualquier  0po  de  objeto  que  se  pueda  serializar. •  QuerySets •  Listas •  ...
    • Deploying  Django1. h_p://virtualenv.openplans.org/2. h_p://pip.openplans.org/
    • Deploying  DjangoVirtualenv  +  PIP  1. h_p://virtualenv.openplans.org/2. h_p://pip.openplans.org/
    • Virtualenv• Independencia  completa  de  las  librerías  del  sitema.• Cada  proyecto  0ene  su  juego  de  librerías  en  la  versión  que  necesita • Sin  miedo  a  actualizar • Sin  miedo  a  migrar • etc...
    • Virtualenv • Independencia  completa  de  las  librerías  del  sitema. • Cada  proyecto  0ene  su  juego  de  librerías  en  la  versión  que  necesita • Sin  miedo  a  actualizar • Sin  miedo  a  migrar • etc...crear $ virtualenv mi_entorno
    • Virtualenv • Independencia  completa  de  las  librerías  del  sitema. • Cada  proyecto  0ene  su  juego  de  librerías  en  la  versión  que  necesita • Sin  miedo  a  actualizar • Sin  miedo  a  migrar • etc...crear $ virtualenv mi_entornoac-var $ source mi_entorno/bin/activate
    • PIP• Gestor  de  paquetes  del  siglo  21  :D• Permite  especificar  un  fichero  de  REQUIREMENTS  con  un  listado  de   paquetes  a  instalar.
    • PIP• Gestor  de  paquetes  del  siglo  21  :D• Permite  especificar  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
    • El  Stack
    • nginx  +  Gunicornnginx •  nginx  [engine  x]  is  a  HTTP  and  reverse  proxy  server. •  Con  una  configuración  muy  sencilla  podremos  u0lizarlo  como  proxy   inverso  a  gunicorn. •  hSp://gunicorn.org/gunicorn •  Servidor  Web  WSGI  implementado  en  Python •  Facilidades  de  puesta  en  marcha  de  proyectos  django •  Fácilmente  configurable  usando  nginx •  hSp://nginx.org/
    • Deploy sencillo Frontend nginx  :80worker  1 worker  2 worker  n gunicorn WSGI  Server Django
    • Deploy no  tan  sencillo frontend1 frontend2 ipfailovernginx  :80  :443 nginx  :80  :443 varnish varnish haproxy haproxy web1 web2 webn nginx  :80 nginx  :80 nginx  :80 gunicorn gunicorn gunicorn Django Django Django
    • Fabric
    • “ Repe00on  leads  to  boredom, boredom  to  horrifying  mistakes, horrifying  mistakes  to  God-­‐I-­‐wish-­‐I-­‐was-­‐s0ll-­‐bored.
    • $ fab deploy -R test
    • $ fab deploy -R www
    • Magia  avanzada1. Views  avanzadas2. Context  Processors3. Custom  Template  Filters  &  Tags4. Middleware5. Internacionalización6. Caching7. Despliegue8. Apps  recomendadas
    • Apps
    • django-­‐south
    • django-­‐south hSp://south.aeracode.org/•  Sistema  inteligente  para  realizar  de  manera  automá0ca  migraciones   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  an0guo  Modelo  a  uno   nuevo...  south!• Necesito  que  ...  south!
    • django-­‐southcrear  primer  schema $ python manage.py schemamigration website --initialcrear  2-­‐*  migración $ python manage.py schemamigration website --autoaplicar  migraciones $ python manage.py migrate
    • django-­‐south hSp://south.aeracode.org/crear  primer  schema $ python manage.py schemamigration website --initialcrear  2-­‐*  migración $ python manage.py schemamigration website --autoaplicar  migraciones $ python manage.py migrate
    • django-­‐haystack  h>p://haystacksearch.org
    • django-­‐haystack•  “EL”  Sistema  de  búsquedas  para  Django•  Funciona  con  varios  sistemas  de  Indexación •  Solr,  Xapian,  Whoosh•  Features: •  ‘More  like  this’ • Face0ng • Highligh0ng •  Spelling  Sugges0on •  etc...  h>p://haystacksearch.org
    • django-­‐registra-on  h>p://bitbucket.org/ubernostrum/django-­‐registra-on/
    • django-­‐registra-on• Sistema  completo  para  la  ges0ón  de  usuarios.• Desde  el  registro,  ac0vación  etc...• DRY!!• Instalación  muy  sencilla.  h>p://bitbucket.org/ubernostrum/django-­‐registra-on/
    • django-­‐registra-on  h>p://bitbucket.org/ubernostrum/django-­‐registra-on/
    • django-­‐registra-on/ac0vate/complete//ac0vate/<ac0va0on_key>//  register//  register/complete//  register/closed//  login//  logout//  password/change//  password/change/done//  password/reset//  password/reset/confirm/<token>/  password/reset/complete//  password/reset/done//  reac0vate/  h>p://bitbucket.org/ubernostrum/django-­‐registra-on/
    • django-­‐debug-­‐toolbar  h>p://github.com/robhudson/django-­‐debug-­‐toolbar
    • Celery  h>p://celeryproject.org
    • Celery• Sistema  de  Tareas  Asíncronas  distribuidas.• Features:  Colas,  Concurrencia,  Distribuido...• Muy  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...)  h>p://celeryproject.org
    • Celery from celery.decorators import task @task def add(x, y): return x + y>>> result = add.delay(4, 4)>>> result.wait() # wait for and return the result8  h>p://celeryproject.org
    • Celery from celery.decorators import task • Las  Task  son  simples  funciones  (O  class  si  queremos) @task def add(x, y): • Python  100%  el  retorno  será  el  resultado return x + y • Usamos  el  decorador  @task  para  registrarla • El  método  .delay  sobre  cualquier  Task  lo  >>> result = add.delay(4, 4) ejecuta  en  background.>>> result.wait() # wait for and return the result8 • Podemos  esperar  a  que  un  Worker  ejecute   la  tarea  o  seguir  haciendo  otras  acciones.  h>p://celeryproject.org
    • Sublime  Text  2  h>p://www.sublimetext.com/2
    • Pycharm  h>p://www.jetbrains.com/pycharm
    • La  punta  del  iceberg
    •  h>p://www.djangobook.com
    • How  to  ...  using  Django?