Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Desarrollo web ágil con Python y Django

Desarrollo web ágil con Python y Django

Curso de Python y Django impartido con Jorge Bastida dentro del Diploma de Especialización en Soluciones Software para Internet de la Universidad de Deusto, octubre 2015.

Avatar for Jaime Irurzun

Jaime Irurzun

October 19, 2015
Tweet

More Decks by Jaime Irurzun

Other Decks in Programming

Transcript

  1. Índice 1.Python   a. Introducción   b.Tipos  de  datos  

    c. Operadores   d.Usos  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
  2. Instalación  Editores $ wget http://bit.ly/atom-amd64 $ sudo dpkg --install atom-amd64

    $ atom $ sudo add-apt-repository ppa:mystic-mirage/pycharm $ sudo apt-get update $ sudo apt-get install pycharm-community $ pycharm-community
  3. Índice 1.Python   a. Introducción   b.Tipos  de  datos  

    c. Operadores   d.Usos  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
  4. • Legible   • Produc=vo   • Portable   •

    Extenso   • Integrable   • ...  y  Diver=do Sintaxis  intui*va  y  estricta   Entre  1/3  y  1/5  más  conciso  que  Java  o  C++   GNU/Linux,  Windows,  Mac  OS  X,  ...   Standard  Library,  Third  par*es   C,  C++,  Java,  .NET,  COM,  WS,  CORBA,  ...
  5. El  Intérprete $ python holamundo.py hola mundo! $ Modo  Batch

    #!/usr/bin/env python
 print "hola mundo!" holamundo.py
  6. El  Intérprete $ python Python 2.7.6 (default, Jun 22 2015,

    17:58:13) [GCC 4.8.2] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> print "hola mundo!" hola mundo! Modo  Interac*vo $ python holamundo.py hola mundo! $ Modo  Batch #!/usr/bin/env python
 print "hola mundo!" holamundo.py
  7. Índice 1.Python   a. Introducción   b.Tipos  de  datos  

    c. Operadores   d.Usos  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
  8. Tipos  de  datos hDp://docs.python.org/library/stdtypes.html object 1234 3.1415 int float 35L

    long True False bool 'spam' "guido's" """n lines""" str [1, [2, 'three'], 4] list
  9. Tipos  de  datos hDp://docs.python.org/library/stdtypes.html object 1234 3.1415 int float 35L

    long True False bool 'spam' "guido's" """n lines""" str [1, [2, 'three'], 4] list {'food': 'spam', 'taste': 'yum'} dict
  10. Tipos  de  datos hDp://docs.python.org/library/stdtypes.html object 1234 3.1415 int float 35L

    long True False bool 'spam' "guido's" """n lines""" str [1, [2, 'three'], 4] list {'food': 'spam', 'taste': 'yum'} dict (1, 'spam', 4, 'U') tuple
  11. Tipos  de  datos hDp://docs.python.org/library/stdtypes.html object 1234 3.1415 int float 35L

    long True False bool 'spam' "guido's" """n lines""" str [1, [2, 'three'], 4] list {'food': 'spam', 'taste': 'yum'} dict (1, 'spam', 4, 'U') tuple ¡Tipado   dinámico!
  12. Índice 1.Python   a. Introducción   b.Tipos  de  datos  

    c. Operadores   d.Usos  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
  13. Operadores numéricos a + b a - b a *

    b a / b a % b -a +a a ** b hDp://docs.python.org/library/operator.html
  14. Operadores numéricos a + b a - b a *

    b a / b a % b -a +a a ** b comparadores a < b a <= b a > b a >= b a == b a != b hDp://docs.python.org/library/operator.html
  15. Operadores numéricos a + b a - b a *

    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 hDp://docs.python.org/library/operator.html
  16. Índice 1.Python   a. Introducción   b.Tipos  de  datos  

    c. Operadores   d.Usos  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
  17. Usos  frecuentes:  list >>> nums = [1, 2, 3] >>>

    nums[0] 1 >>> nums.append(4) >>> print nums [1, 2, 3, 4] >>> 2 in nums True
  18. Usos  frecuentes:  list >>> nums = [1, 2, 3] >>>

    nums[0] 1 >>> nums.append(4) >>> print nums [1, 2, 3, 4] >>> 2 in nums True >>> len(nums) 4
  19. Usos  frecuentes:  str >>> "Python mola"[1:4] 'yth' >>> "Python mola".find("mola")

    7 >>> "Python mola".replace("Python", "PHP no") 'PHP no mola'
  20. 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']
  21. 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"
  22. Usos  frecuentes:  str >>> "{} sabe {} idiomas".format("Hycker", 5) 'Hycker

    sabe 5 idiomas' >>> t = "{nombre} sabe {idiomas} idiomas" >>> t.format(nombre="Hycker", idiomas=5) 'Hycker sabe 5 idiomas'
  23. Usos  frecuentes:  dict >>> user = {'nick': 'neo', 'phone': '5555'}

    >>> user.keys() ['nick', 'phone'] >>> user.values() ['neo', '5555']
  24. Usos  frecuentes:  dict >>> user = {'nick': 'neo', 'phone': '5555'}

    >>> user.keys() ['nick', 'phone'] >>> user.values() ['neo', '5555'] >>> user['nick'] 'neo' >>> user.get('age', 26) 26
  25. Usos  frecuentes:  dict >>> user = {'nick': 'neo', 'phone': '5555'}

    >>> user.keys() ['nick', 'phone'] >>> user.values() ['neo', '5555'] >>> user['nick'] 'neo' >>> user.get('age', 26) 26 >>> 'nick' in user True
  26. Usos  frecuentes:  dict >>> user = {'nick': 'neo', 'phone': '5555'}

    >>> user.keys() ['nick', 'phone'] >>> user.values() ['neo', '5555'] >>> user['nick'] 'neo' >>> user.get('age', 26) 26 >>> 'nick' in user True >>> user.update({'nick': 'alatar', 'age': 25}) >>> user {'nick': 'alatar', 'phone': '5555', 'age': 25}
  27. juego/ __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ódulos 1. Un  módulo  es  un  fichero  .py   2. Los  módulos  pueden   organizarse  en  paquetes.   3. Un  paquete  es  una  carpeta   que  con*ene  un  fichero  con   nombre  __init__.py
  28. juego/ __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ódulos 1. Un  módulo  es  un  fichero  .py   2. Los  módulos  pueden   organizarse  en  paquetes.   3. Un  paquete  es  una  carpeta   que  con*ene  un  fichero  con   nombre  __init__.py 1 2 3
  29. Módulos En  la  lista  de  directorios  que  con*ene  la  lista

     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.7/site-packages /usr/lib/python2.7/ $ env | grep PYTHONPATH
  30. Módulos juego/ __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 ...
  31. Módulos juego/ __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 ... >>> from juego.personajes.mario import Mario >>> Mario() >>> from juego.personajes.mario import * >>> Mario() >>> from juego import personajes >>> personajes.mario.Mario() >>> import juego >>> juego.personajes.mario.Mario()
  32. Índice 1.Python   a. Introducción   b.Tipos  de  datos  

    c. Operadores   d.Usos  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
  33. >>> from __future__ import braces File "<stdin>", line 1 SyntaxError:

    not a chance Identación 4  Espacios  para  la  identación
  34. >>> from __future__ import braces File "<stdin>", line 1 SyntaxError:

    not a chance Identación 4  Espacios  para  la  identación PEP 8
  35. •  Guido  van  Rossum  (2001)   •  Recomendaciones  de  es*lo

      •  “Readability  counts”   •  “Code  is  read  much  more  onen  than  it  is  wrioen.”   •  Muy  recomendable  importante  seguirlo. PEP 8 ¿PEP  8? hDp://www.python.org/dev/peps/pep-­‐0008/
  36. def my_first_function(p1, p2):
 return "Hello World!" 1 2 3 Funciones

    Minúsculas   Palabras  separadas  por  _   Evitar  camelCase   PEP 8
  37. Conversión  de  =pos >>> str(2) '2' >>> int(1.3) 1 >>>

    float(1) 1.0 hDp://docs.python.org/library/func=ons.html
  38. Conversión  de  =pos >>> str(2) '2' >>> int(1.3) 1 >>>

    float(1) 1.0 >>> tuple([1,2,3]) (1, 2, 3) hDp://docs.python.org/library/func=ons.html
  39. Conversión  de  =pos >>> str(2) '2' >>> int(1.3) 1 >>>

    float(1) 1.0 >>> list((1,2,3)) [1, 2, 3] >>> tuple([1,2,3]) (1, 2, 3) hDp://docs.python.org/library/func=ons.html
  40. 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] hDp://docs.python.org/library/func=ons.html
  41. 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] >>> type(True) <type 'bool'> >>> type("Python Mola") <type 'str'> hDp://docs.python.org/library/func=ons.html
  42. 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] >>> sum([0,1,2,3,4]) 10 >>> sum(range(5)) 10 >>> type(True) <type 'bool'> >>> type("Python Mola") <type 'str'> Y  un  muy  largo  etc... hDp://docs.python.org/library/func=ons.html
  43. Funciones  interesantes >>> a = [1,2,3] >>> b = [4,5,6]

    >>> zip(a,b) [(1, 4), (2, 5), (3, 6)] Son  sólo  un  ejemplo... hDp://docs.python.org/library/func=ons.html
  44. 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... hDp://docs.python.org/library/func=ons.html
  45. Funciones  interesantes >>> a = [1,2,3] >>> b = [4,5,6]

    >>> zip(a,b) [(1, 4), (2, 5), (3, 6)] >>> round(1.2345, 2) 1.23 >>> sorted([5,1,3,4,2]) [1, 2, 3, 4, 5] Son  sólo  un  ejemplo... hDp://docs.python.org/library/func=ons.html
  46. Funciones  interesantes >>> a = [1,2,3] >>> b = [4,5,6]

    >>> zip(a,b) [(1, 4), (2, 5), (3, 6)] >>> round(1.2345, 2) 1.23 >>> sorted([5,1,3,4,2]) [1, 2, 3, 4, 5] >>> map(str,[1,2,3,4,5]) ['1', '2', '3', '4', '5'] Son  sólo  un  ejemplo... hDp://docs.python.org/library/func=ons.html
  47. 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']
  48. 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)
  49. class Student(object):
 def __init__(self, name, age):
 self.name = name
 self.age

    = age
 
 def hello(self):
 return 'My name is {}'.format(self.name) Clases s = Student("Jorge", 24) camelCase
  50. class Student(object):
 def __init__(self, name, age):
 self.name = name
 self.age

    = age
 
 def hello(self):
 return 'My name is {}'.format(self.name) 1 2 3 4 5 Clases s = Student("Jorge", 24) camelCase PEP 8
  51. El  operador  () • Es  importante  diferenciar:   funcion  

       vs      funcion()   Clase              vs        Clase()   • El  operador  ()  permite:   • Invocar  funciones:   • Instanciar  clases: resultado = funcion() objeto = Clase("param1")
  52. Índice 1.Python   a. Introducción   b.Tipos  de  datos  

    c. Operadores   d.Usos  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
  53. $name = "Jon";
 
 if($name == "Jon"){
 $name = "Jon

    Rocks!";
 }
 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
  54. $count = 0;
 while ($count < 5) {
 echo "Number

    ".$count;
 $count+=1;
 }
 count = 0
 while count < 5:
 print "Number {}".format(count)
 count+=1
 Sentencias:  while
  55. for ($i=0; $i < 5; $i++) { 
 echo "Number

    ".$count;
 }
 for i in range(4):
 print "Number {}".format(count) Sentencias:  for
  56. try {
 $result = 3 / 0;
 } catch (Exception

    $e) {
 echo "Division by Zero"
 } try:
 result = 3 / 0
 except:
 print "Division by Zero" Sentencias:  try-­‐except
  57. •  Python  es  un  lenguaje  fácil  de  aprender.   •

     Menos  código:   •  Muchos  Muchísimos  menos  errores  de  Sintaxis.   •  Mayor  velocidad  de  escritura.   •  Proto*pado...  U*lizado  por  grandes  empresas. Conclusiones
  58. •  Python  es  un  lenguaje  fácil  de  aprender.   •

     Menos  código:   •  Muchos  Muchísimos  menos  errores  de  Sintaxis.   •  Mayor  velocidad  de  escritura.   •  Proto*pado...  U*lizado  por  grandes  empresas. etc... Conclusiones
  59. Índice 1.Python   a. Introducción   b.Tipos  de  datos  

    c. Operadores   d.Usos  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
  60. Evolución  de  la  Web Desarrollo  Web 1ª  Generación 2ª  Generación

    3ª  Generación HTML   CGI PHP   ASP   JSP   ... Django   Rails   Symfony   ...
  61. •  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  XXI,  todo  el  trabajo  tedioso  hay  que  evitarlo.   •  Don’t  Repeat  Yourself  (DRY) Filoso_a
  62. •  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  XXI,  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
  63. •  Explicit  is  beoer  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.   Filoso_a hDp://docs.djangoproject.com/en/dev/misc/design-­‐philosophies/
  64. La  comunidad • django-­‐users:  31.000+  miembros • django-­‐developers:  9.000+  miembros

    • 66.000  líneas  de  Python • 75.000  líneas  de  Inglés
  65. Configurar  un  motor  de  Base  de  Datos:   •  Oficiales:

        •  PostgreSQL   •  MySQL   •  Oracle   •  SQLite •  Comunidad:     •  Sybase  SQL  Anywhere   •  IBM  DB2   •  Microson  SQL  Server  2005   •  Firebird   •  ODBC 2.  Instalación  SGBD
  66. Configurar  un  motor  de  Base  de  Datos:   •  Oficiales:

        •  PostgreSQL   •  MySQL   •  Oracle   •  SQLite •  Comunidad:     •  Sybase  SQL  Anywhere   •  IBM  DB2   •  Microson  SQL  Server  2005   •  Firebird   •  ODBC 2.  Instalación  SGBD
  67. •  Vamos  a  u*lizar  SQLite  por  comodidad   •  Desde

     Python  2.5  podemos  u*lizar  sqlite    sin  instalar  nada. 2.  Instalación  SGBD
  68. •  Vamos  a  u*lizar  SQLite  por  comodidad   •  Desde

     Python  2.5  podemos  u*lizar  sqlite    sin  instalar  nada. 2.  Instalación  SGBD
  69. 3.  Instalación  Django $ sudo apt-get update $ sudo apt-get

    install python-pip $ sudo pip install django
  70. All  Right? >>> import django >>> django.VERSION (1, 8, 5,

    'final', 0) >>> import django Traceback (most recent call last): File "<stdin>", line 1, in <module> ImportError: No module named django
  71. *  Incluida  la  carpeta  del  proyecto Ficheros  y  Carpetas ¿Es

     Django  tán  simple  y  fácil  de  usar?
  72. *  Incluida  la  carpeta  del  proyecto Ficheros  y  Carpetas Ficheros

    Carpetas ¿Es  Django  tán  simple  y  fácil  de  usar?
  73. Rails 149 35 *  Incluida  la  carpeta  del  proyecto Ficheros

     y  Carpetas Ficheros Carpetas ¿Es  Django  tán  simple  y  fácil  de  usar?
  74. Rails 149 35 Symfony 117 29 *  Incluida  la  carpeta

     del  proyecto Ficheros  y  Carpetas Ficheros Carpetas ¿Es  Django  tán  simple  y  fácil  de  usar?
  75. Rails 149 35 Symfony 117 29 *  Incluida  la  carpeta

     del  proyecto Ficheros  y  Carpetas Django 5 2 Ficheros Carpetas ¿Es  Django  tán  simple  y  fácil  de  usar?
  76. Crear  nuestro  proyecto $ django-admin startproject dwitter -­‐  ¿Esto  es

     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  ;-­‐)
  77. Arrancar  nuestro  proyecto de  5  ficheros  ;-­‐) $ cd dwitter

    $ python manage.py runserver Performing system checks... System check identified no issues (0 silenced). You have unapplied migrations; your app may not work properly until they are applied. Run 'python manage.py migrate' to apply them. October 11, 2015 - 18:18:07 Django version 1.8.5, using settings 'dwitter.settings' Starting development server at http://127.0.0.1:8000/ Quit the server with CONTROL-C.
  78. Índice 1.Python   a. Introducción   b.Tipos  de  datos  

    c. Operadores   d.Usos  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
  79. URLs  y  Vistas • El  fichero  urls.py  actúa  como  puerta

     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 hop://mysite.com/about/ html ... ¿urlpaoerns?
  80. URLs  y  Vistas • La  función  de  views.py  recibe  como

     parámetros  un  objeto   HDpRequest  y  todos  los  parámetros  de  la  URL  capturados,   teniendo  que  devolver  siempre  un  objeto  HDpResponse views.py HDpRequest(),  ... HDpResponse()
  81. URLs  y  Vistas Ejemplo  1:    http://mysite.com/time urls.py views.py from

    django.conf.urls import url from mysite.views import hora_actual urlpatterns = [ url(r'^time$', hora_actual) ] from datetime import datetime from django.http import HttpResponse def hora_actual(request): now = datetime.now() html = "Son las {}.".format(now) return HttpResponse(html)
  82. URLs  y  Vistas urls.py views.py Ejemplo  2:    http://mysite.com/time/plus/2 from

    django.conf.urls import url from mysite.views import dentro_de urlpatterns = [ url(r'^time/plus/(\d{1,2})$', dentro_de) ] from datetime import datetime, timedelta from django.http import HttpResponse def dentro_de(request, offset): offset = int(offset) dt = datetime.now() + timedelta(hours=offset) html = "En {} hora(s), serán las {}.".format(offset, dt) return HttpResponse(html)
  83. URLs  y  Vistas urls.py views.py Ejemplo  2:    http://mysite.com/time/plus/2 from

    django.conf.urls import url from mysite.views import dentro_de urlpatterns = [ url(r'^time/plus/(\d{1,2})$', dentro_de) ] from datetime import datetime, timedelta from django.http import HttpResponse def dentro_de(request, offset): offset = int(offset) dt = datetime.now() + timedelta(hours=offset) html = "En {} hora(s), serán las {}.".format(offset, dt) return HttpResponse(html)
  84. Índice 1.Python   a. Introducción   b.Tipos  de  datos  

    c. Operadores   d.Usos  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
  85. Templates • Separan  la  lógica  de  presentación  a  una  capa

     independiente.   • Ficheros  independientes  (.html)   • Lenguaje  independiente  (¡para  diseñadores!)
  86. Templates • Se  basan  en  dos  *pos  de  objetos:  Template()

     y  Context().   • Un  objeto  Template()  con*ene  el  string  de  salida  que   queremos  devolver  en  el  HopResponse  (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."
  87. Templates 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) • Primera  aproximación  al  obje*vo:  Template  +  Context
  88. Templates • Segunda  aproximación  al  obje*vo:  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)
  89. Templates • Segunda  aproximación  al  obje*vo:  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)
  90. Templates • Segunda  aproximación  al  obje*vo:  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) Boring   boilerplate   code!
  91. Templates • Tercera  aproximación  al  obje*vo:  get_template() 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) se{ngs.py TEMPLATES = [{ 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': ['/home/django/templates']}]
  92. Templates • Tercera  aproximación  al  obje*vo:  get_template() 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) se{ngs.py TEMPLATES = [{ 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': ['/home/django/templates']}]
  93. Templates • Tercera  aproximación  al  obje*vo:  get_template() 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) se{ngs.py TEMPLATES = [{ 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': ['/home/django/templates']}] S*ll   boring...
  94. Templates • Obje*vo  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})
  95. Templates • Obje*vo  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}) Boring...?
  96. Templates • Obje*vo  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!
  97. Templates:  Tip se{ngs.py a) TEMPLATES = [{ 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS':

    ['/home/django/templates']}] b) • La  carpeta  /templates  es  buscada  dentro  de  cada  app.   • Conviene  incluir  una  carpeta  con  el  nombre  de  la  app  por  claridad. return render(request, 'website/index.html') Alterna*va  reu*lizable: TEMPLATES = [{ 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': ['/Users/juan/templates'], 'APP_DIRS': True}]
  98. Templates:  Tip se{ngs.py a) TEMPLATES = [{ 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS':

    ['/home/django/templates']}] Reusable   apps? b) • La  carpeta  /templates  es  buscada  dentro  de  cada  app.   • Conviene  incluir  una  carpeta  con  el  nombre  de  la  app  por  claridad. return render(request, 'website/index.html') Alterna*va  reu*lizable: TEMPLATES = [{ 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': ['/Users/juan/templates'], 'APP_DIRS': True}]
  99. Git

  100. Git $ git clone https://github.com/enjoydjango/dwitter.git $ git checkout -t origin/step-01-views

    Quiero  ir  a... $ git branch ¿Dónde  estoy? $ git checkout step-01-views 1ª
  101. Git $ git reset --hard HEAD $ git clean -fd

    Ignorar  todos  los  cambios  * *  Si  no  habéis  comiteado  nada
  102. ¡Empieza  nuestro  primer  proyecto! a) Crear  la  app  dwioer.website.  

                     python  manage.py  startapp  website   b)Incluir  la  app  en  se{ngs.py.
    INSTALLED_APPS   c) Definir  una  vista  para  la  URL  “/”  que   devuelva  el  texto:
        “Welcome  to  dwioer!”:   ‣ / ‣ timeline(request)
  103. Tarea:  URLs  y  Vistas   a) Implementar  la  vista  timeline()

     para   que  renderice  un  *meline  de  twioer  en   una  template  index.html  a  par*r  de   datos  hardcodeados  en  un  diccionario. hDp://bit.ly/dwiDer-­‐diccionario-­‐tweets
  104. 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
  105. Filoso_a  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.
  106. Templates:  {{}} <html>
 <head>Ejemplo templates</head>
 <body>
 Hola, {{ username }}.


    </body>
 </html> {'username': 'juan'}
 <html>
 <head>Ejemplo templates</head>
 <body>
 Hola, juan.
 </body>
 </html>
  107. Filters  y  Tags {{ varible|filter }} filter {% tag var1

    var2 %} inline  tag {% tag var1 %} ... {% endtag %} block  tag
  108. Templates:  tags  {%  %} {% comment %} Bu! {% endcomment

    %} comment for {% for elemento in lista %}
 <li>{{ elemento }}<li>
 {% endfor %}
  109. Templates:  tags  {%  %} {% comment %} Bu! {% endcomment

    %} 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
  110. Templates:  tags  {%  %} cycle {% for elemento in lista

    %}
 <li class="{% cycle 'rojo' 'azul' %}">{{ elemento }}<li>
 {% endfor %}
  111. Templates:  tags  {%  %} cycle {% for elemento in lista

    %}
 <li class="{% cycle 'rojo' 'azul' %}">{{ elemento }}<li>
 {% endfor %} include {% include "foo/bar.html" %}
  112. 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 %}
  113. 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 %}
  114.   Tarea:  Tags   a) U*lizar  tags  para  que  el

     *meline  se   muestre  con  el  siguiente  formato:   • <username>:  <tweet>  <*mestamp>   • <username>:  <tweet>  <*mestamp>   • ...
  115.   Tarea:  Tags  avanzados   a) Hacer  que  el  *meline

     muestre  el   mensaje  “No  hay  tweets.”  si  el   diccionario  recibido  está  vacío.
  116. Templates:  Filters <html>
 <head>Ejemplo templates</head>
 <body>
 Hola, {{ username|title }}.


    </body>
 </html> {'username': 'juan'}
 <html>
 <head>Ejemplo templates</head>
 <body>
 Hola, Juan.
 </body>
 </html> =tle
  117. Templates:  Filters {'username': 'Juan es majo'} {{ username|length }} length

    12 {{ username|slugify }} slugify juan-es-majo {{ username|wordcount }} wordcount 3
  118. Templates:  Filters {'username': 'Juan es majo'} {{ username|length }} length

    12 {{ username|slugify }} slugify juan-es-majo {{ username|upper }} upper JUAN ES MAJO {{ username|wordcount }} wordcount 3
  119. Templates:  Filters {'username': 'Juan es majo'} {{ username|length }} length

    12 {{ username|slugify }} slugify juan-es-majo {{ username|upper }} upper JUAN ES MAJO {{ username|wordcount }} wordcount 3 {{ username|default:”Desconocido” }} default {'username': None} Desconocido
  120. Templates:  Filters {'username': 'Juan es <b>majo, guapo y <em>listo</em></b>'} {{

    username|striptags }} striptags Juan es majo guapo y listo
  121. Templates:  Filters {'username': 'Juan es <b>majo, guapo y <em>listo</em></b>'} {{

    username|striptags }} striptags Juan es majo guapo y listo {{ username|truncatewords_html:4 }} truncatewords_html Juan es <b>majo guapo</b> ...
  122. Templates:  Filters {'username': 'Juan es <b>majo, guapo y <em>listo</em></b>'} {{

    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>
  123. Templates:  Filters {'url': 'Visitad http://www.djangoproject.com'} {{ url|urlize }} urlize Visitad

    <a href=”http://www.djangoproject.com”> http:// www.djangoproject.com </a>
  124. Templates:  Filters {'url': 'Visitad http://www.djangoproject.com'} {{ url|urlize }} urlize Visitad

    <a href=”http://www.djangoproject.com”> http:// www.djangoproject.com </a> {{ url|urlizetrunc:16 }} urlizetrunc Visitad <a href=”http://www.djangoproject.com”> http:// www.djang...</a>
  125. Templates:  Filters {'lista': ['States', ['Kansas', ['Lawrence', 'Topeka'], 'Illinois']]} {{ lista|unordered_list

    }} unordered_list <li>States
 <ul>
 <li>Kansas
 <ul>
 <li>Lawrence</li>
 <li>Topeka</li>
 </ul>
 </li>
 <li>Illinois</li>
 </ul>
 </li>
  126. Templates:  Filters {'value': 123456789} {{ value|add:”1” }} add 123456790 {{

    value|filesizeformat }} filesizeformat 117.7MB {'date': datetime.datetime(2010, 9, 11, 17, 1, 59, 385323) } {{ date|date:”d M Y” }} date 11 Sep 2010
  127. Templates:  Filters {'value': 123456789} {{ value|add:”1” }} add 123456790 {{

    value|filesizeformat }} filesizeformat 117.7MB {'date': datetime.datetime(2010, 9, 11, 17, 1, 59, 385323) } {{ date|date:”d M Y” }} date 11 Sep 2010 {{ date|timesince }} =mesince 4 days, 6 hours
  128. Templates:  Filters {'value': 123456789} {{ value|add:”1” }} add 123456790 {{

    value|filesizeformat }} filesizeformat 117.7MB {'date': datetime.datetime(2010, 9, 11, 17, 1, 59, 385323) } {{ date|date:”d M Y” }} date 11 Sep 2010 {{ date|timesince }} =mesince 4 days, 6 hours {{ date|timeuntil }} =meun=l 1 days, 6 hours
  129. Tarea:  Filters   a) Añadir  a  cada  tweet  del  *meline

     el   *empo  transcurrido:   • <username>:  <tweet>   <n>  seconds  ago   • <username>:  <tweet>   <n>  minutes  ago   • ...
  130. Tarea:  Filters   a) Formatear  las  publicaciones  de   HOYGANs

     convir*endo  el  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”  
  131. Tarea:  Filters   c) Conseguir  que  todas  las  urls  que

      aparezcan  en  los  tweets  se  conviertan   en  enlaces  <a  href=...  />  de  HTML.
  132. Herencia  de  Templates base.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 %}
  133. Tarea:  Herencia  de  templates   a) Descargar  nuestra  template  base.html.

      b)Incluirla  en  vuestra  app.   c) Hacer  que  vuestro  index.html  herede   de  base.html  y  ex*enda  el  bloque   ‘content’  con  su  contenido. hDp://bit.ly/base-­‐html-­‐template
  134. Índice 1.Python   a. Introducción   b.Tipos  de  datos  

    c. Operadores   d.Usos  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
  135. Ejemplo  SQL def 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})
  136. Ejemplo  SQL def 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}) 1 2 3 4 5 6
  137. def book_list(request): 
 names = Books.objects.all().order_by('name') 
 return render(request, 'book_list.html',

    {'names':names}) def 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})
  138. def book_list(request): 
 names = Books.objects.all().order_by('name') 
 return render(request, 'book_list.html',

    {'names':names}) def 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})
  139. 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)  
  140. 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) 
 2 1 3 4 5 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)  
  141. 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)
  142. Tipos  de  Datos • AutoField • BigIntegerField • BooleanField •

    CharField • CommaSeparatedIntegerField • DateField • DateTimeField • DecimalField • EmailField • FileField • FilePathField • FloatField • ImageField • IntegerField • IPAdressField • NullBooleanField • PositiveIntegerField • PositiveSmallIntegerField • SlugField • SmallIntegerField • TextField • TimeField • URLField • XMLField • ForeingKey • ManyToManyField • OneToOneField
  143. Tipos  de  Datos • AutoField • BigIntegerField • BooleanField •

    CharField • CommaSeparatedIntegerField • DateField • DateTimeField • DecimalField • EmailField • FileField • FilePathField • FloatField • ImageField • IntegerField • IPAdressField • NullBooleanField • PositiveIntegerField • PositiveSmallIntegerField • SlugField • SmallIntegerField • TextField • TimeField • URLField • XMLField • ForeingKey • ManyToManyField • OneToOneField
  144. Propiedades  de  las  Field • null (True|Flase) • blank (True|False)

    • choices (lista) • default (valor) • editable (True|False) • help_text (String) • unique (True|False) • primary_key • unique_for_date • unique_for_month • unique_for_year
  145. Propiedades  de  las  Field • null (True|Flase) • blank (True|False)

    • choices (lista) • default (valor) • editable (True|False) • help_text (String) • unique (True|False) • primary_key • unique_for_date • unique_for_month • unique_for_year
  146. Modelos  built-­‐in INSTALLED_APPS = ( ... 'django.contrib.auth', ... ) class

    User(models.Model): username = models.CharField(max_length=30, unique=True) first_name = models.CharField(max_length=30, blank=True) last_name = models.CharField(max_length=30, blank=True) email = models.EmailField(blank=True) is_staff = models.BooleanField() ... django/contrib/auth/models.py
  147. Modelos  built-­‐in INSTALLED_APPS = ( ... 'django.contrib.auth', ... ) class

    User(models.Model): username = models.CharField(max_length=30, unique=True) first_name = models.CharField(max_length=30, blank=True) last_name = models.CharField(max_length=30, blank=True) email = models.EmailField(blank=True) is_staff = models.BooleanField() ... django/contrib/auth/models.py
  148. Extender  el  modelo  User models.py sewngs.py El  modelo  django.contrib.auth.User  no

     puede  contener  toda   la  información  que  necesitamos.  Pero  podemos  extenderlo:
  149. Extender  el  modelo  User from django.contrib.auth.models import AbstractUser class User(AbstractUser):

    bio = models.CharField(blank=True, max_length=200) ... models.py AUTH_USER_MODEL = 'website.User' sewngs.py El  modelo  django.contrib.auth.User  no  puede  contener  toda   la  información  que  necesitamos.  Pero  podemos  extenderlo:
  150. DB  Inicial Migración   1 + + + + DB

     Final Migraciones  de  esquema Migración   2 Migración   3
  151. DB  Inicial Migración   1 + + + + DB

     Final Migraciones  de  esquema Migración   2 Migración   3 %## website "## __init__.py "## admin.py "## migrations $ "## 0001_initial.py $ "## 0002_auto.py $ "## 0003_auto.py $ %## __init__.py "## models.py "## tests.py %## views.py
  152. Migraciones  de  esquema "## migrations $ "## 0001_initial.py $ %##

    __init__.py $ python manage.py makemigrations Crear   migraciones   $ python manage.py migrate Aplicar   migraciones  
  153. migrate $ python manage.py migrate Operations to perform: Synchronize unmigrated

    apps: staticfiles, messages Apply all migrations: admin, website, contenttypes, auth, sessions Synchronizing apps without migrations: Creating tables... Running deferred SQL... Installing custom SQL... Running migrations: Rendering model states... DONE Applying contenttypes.0001_initial... OK Applying contenttypes.0002_remove_content_type_name... OK Applying auth.0001_initial... OK Applying auth.0002_alter_permission_name_max_length... OK Applying auth.0003_alter_user_email_max_length... OK Applying auth.0004_alter_user_username_opts... OK Applying auth.0005_alter_user_last_login_null... OK Applying auth.0006_require_contenttypes_0002... OK Applying website.0001_initial... OK Applying admin.0001_initial... OK Applying sessions.0001_initial... OK
  154. migrate $ python manage.py migrate Operations to perform: Synchronize unmigrated

    apps: staticfiles, messages Apply all migrations: admin, website, contenttypes, auth, sessions Synchronizing apps without migrations: Creating tables... Running deferred SQL... Installing custom SQL... Running migrations: Rendering model states... DONE Applying contenttypes.0001_initial... OK Applying contenttypes.0002_remove_content_type_name... OK Applying auth.0001_initial... OK Applying auth.0002_alter_permission_name_max_length... OK Applying auth.0003_alter_user_email_max_length... OK Applying auth.0004_alter_user_username_opts... OK Applying auth.0005_alter_user_last_login_null... OK Applying auth.0006_require_contenttypes_0002... OK Applying website.0001_initial... OK Applying admin.0001_initial... OK Applying sessions.0001_initial... OK
  155. ¿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;
  156. ¿Es  magia?  No. $ python manage.py sqlmigrate website 0001_initial 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;
  157. ¿Es  magia?  No. •  Nombres  de  tablas  generados  automá*camente.  

    •  <app_name>_lower(<model_name>)   •  id  como  Primary  Key  (Personalizable)   •  Las  Foreing  Key  terminan  en  _id  (Personalizable)   •  Los  *pos  de  datos  se  ajustan  en  función  del  SGBD  
  158. Nuestro  primer  modelo a)Crear  modelos  User  y  Tweet   b)Crear

     migración  inicial   c) Aplicar  migración
  159. INSERT >>> p = Publisher( ... name='Apress', ... address='2855 Telegraph

    Avenue', ... city='Berkeley', ... state_province='CA', ... country='U.S.A.', ... website='http://www.apress.com/') >>> p.save() a) o = Model(...) o.save()
  160. INSERT >>> p = Publisher.objects.create( ... name='O'Reilly', ... address='10 Fawcett

    St.', ... city='Cambridge', ... state_province='MA', ... country='U.S.A.', ... website='http://www.oreilly.com/') >>> p = Publisher( ... name='Apress', ... address='2855 Telegraph Avenue', ... city='Berkeley', ... state_province='CA', ... country='U.S.A.', ... website='http://www.apress.com/') >>> p.save() a) o = Model(...) o.save() manager.create(...) b)
  161. UPDATE >>> ... >>> p.id
 52
 >>> p.name = 'Apress

    Publishing'
 >>> p.save() o.save() 1
  162. UPDATE >>> Publisher.objects.all().update(country='USA') 2 >>> ... >>> p.id
 52
 >>>

    p.name = 'Apress Publishing'
 >>> p.save() o.save() queryset.update(...) 1 n
  163. DELETE >>> ps = Publisher.objects.all() >>> ps.delete() >>> ... >>>

    p.id
 52
 >>> p.delete() o.delete() queryset.delete() 1 n
  164. SELECT  de  1  resultado >>> Publisher.objects.get(name="Apress")
 <Publisher: Apress> .get(...) >>>

    Publisher.objects.get(name="Anaya") Traceback (most recent call last): ... DoesNotExist: Publisher matching query does not exist.
  165. SELECT  de  1  resultado >>> Publisher.objects.get(name="Apress")
 <Publisher: Apress> .get(...) >>>

    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.
  166. SELECT  de  N  resultados >>> Publisher.objects.all()
 [<Publisher: Apress>, <Publisher: O'Reilly>]

    .all() >>> Publisher.objects.filter( country="U.S.A.", state_province="CA")
 [<Publisher: Apress>] .filter(...)
  167. SELECT  de  N  resultados >>> Publisher.objects.all()
 [<Publisher: Apress>, <Publisher: O'Reilly>]

    .all() >>> Publisher.objects.filter( country="U.S.A.", state_province="CA")
 [<Publisher: Apress>] .filter(...) >>> Publisher.objects.exclude( country="U.S.A.", state_province="CA")
 [<Publisher: O'Reilly>] .exclude(...)
  168. SELECT  de  N  resultados >>> Publisher.objects.all()
 [<Publisher: Apress>, <Publisher: O'Reilly>]

    .all() >>> Publisher.objects.filter( country="U.S.A.", state_province="CA")
 [<Publisher: Apress>] .filter(...) >>> Publisher.objects.exclude( country="U.S.A.", state_province="CA")
 [<Publisher: O'Reilly>] .exclude(...) ¡Devuelven   QuerySets,  no   listas!
  169. get(),  filter()  y  exclude() Modelo.objects.filter(campo1="valor1", campo2="valor2") Los  parámetros  pueden  indicar

     mucho  más  que  igualdad  (=) campo__exact='' campo__iexact='' campo__contains='' campo__icontains='' campo__isnull=T|F campo__day=31 campo__gt=0 campo__gte=0 campo__lt=0 campo__lte=0 campo__in=[ ,] campo__month=12 campo__startswith='' campo__istartswith='' campo__endswith='' campo__iendswith='' campo__range=( ,) campo__year=2010
  170. ORDER  BY >>> Publisher.objects.order_by("name")
 [<Publisher: Apress>, <Publisher: O'Reilly>] .order_by(...) >>>

    Publisher.objects.order_by("-name")
 [<Publisher: O'Reilly>, <Publisher: Apress>]
  171. ORDER  BY >>> Publisher.objects.order_by("name")
 [<Publisher: Apress>, <Publisher: O'Reilly>] .order_by(...) >>>

    Publisher.objects.order_by("-name")
 [<Publisher: O'Reilly>, <Publisher: Apress>] >>> Publisher.objects.order_by("-name", "country")
 [<Publisher: O'Reilly>, <Publisher: Apress>] Múl*ples  campos:
  172. ORDER  BY >>> Publisher.objects.order_by("name")
 [<Publisher: Apress>, <Publisher: O'Reilly>] .order_by(...) >>>

    Publisher.objects.order_by("-name")
 [<Publisher: O'Reilly>, <Publisher: Apress>] >>> Publisher.objects.order_by("-name", "country")
 [<Publisher: O'Reilly>, <Publisher: Apress>] Múl*ples  campos: ¡También   devuelve   QuerySets!
  173. Slicing >>> Publisher.objects.order_by("name")[0]
 <Publisher: Apress> [n:m] >>> Publisher.objects.order_by("name")[:2]
 [<Publisher: Apress>,

    <Publisher: O'Reilly>] >>> Publisher.objects.order_by("name")[1:2]
 [<Publisher: O'Reilly>] LIMIT
  174. Slicing >>> Publisher.objects.order_by("name")[0]
 <Publisher: Apress> [n:m] >>> Publisher.objects.order_by("name")[:2]
 [<Publisher: Apress>,

    <Publisher: O'Reilly>] >>> Publisher.objects.order_by("name")[1:2]
 [<Publisher: O'Reilly>] LIMIT OFFSET
  175. Related  Objects OneToOneField class Coche(models.Model):
 motor = OneToOneField(Motor) class Motor(models.Model):


    ... >>> c.motor
 <Motor: Motor object> ¿Cómo  usamos  la  relación  desde  las  instancias? Gracias  a  nosotros 1 1
  176. Related  Objects OneToOneField class Coche(models.Model):
 motor = OneToOneField(Motor) class Motor(models.Model):


    ... >>> 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
  177. Related  Objects ForeignKeyField class Blog(models.Model):
 ... class Post(models.Model):
 blog =

    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
  178. Related  Objects ManyToManyField class Post(models.Model):
 tags = ManyToManyField(Tag) class Tag(models.Model):


    ... >>> 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
  179. Related  Objects En  todas  ellas  podemos  renombrar  el  puntero  inverso

    class Blog(models.Model):
 ... class Post(models.Model):
 blog = ForeignKeyField(Blog, related_name='posts') 1 n
  180. Related  Objects En  todas  ellas  podemos  renombrar  el  puntero  inverso

    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
  181. Related  Objects En  todas  ellas  podemos  renombrar  el  puntero  inverso

    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
  182. Laziness • Las  consultas  sólo  se  ejecutarán  cuando  realmente  se

      necesite  obtener  los  objetos.  En  las  siguientes  situaciones:   • Iteraciones   • Slicing   • Serialización   • repr() • len() !!! • list() • bool() for p in Publisher.objects.all(): Publisher.objects.filter(country='USA')[0] [Caché] [<Publisher: Publisher object>] len(Publisher.objects.all()) list(Publisher.objects.all()) if Publisher.objects.filter(country='USA'):
  183. Nota:  __unicode__() class Publisher(models.Model):
 ...
 
 def __unicode__(self):
 return self.name

    >>> Publisher.objects.all() [<Publisher: Publisher object>] >>> Publisher.objects.all() [<Publisher: Apress>]
  184. Usando  el  ORM a)Crear  un  User  desde  la  shell:  

    $ python manage.py createsuperuser b)Insertar  varios  Tweets  desde  la  shell.   c) Modificar  views.timeline  para  que   u*lice  los  Tweets  reales  de  la  BD.
  185. Usando  el  ORM d)Implementar  la  vista  tweet_page()  como   permalink

     de  un  tweet:   ‣ URL:    tweet/<tweet_id>/ ‣ View:    tweet_page ‣ Template:    tweet_page.html    (Descargar) e)Lanzar  Http404  si  no  existe  el  tweet_id.   f) shortcut!:  get_object_or_404() hDp://bit.ly/tweet-­‐page
  186. Extender  el  modelo  User models.py $ python manage.py makemigrations $

    python manage.py migrate Crear  migración Aplicar  migración
  187. Extender  el  modelo  User from django.contrib.auth.models import AbstractUser class User(AbstractUser):

    bio = models.CharField(blank=True, max_length=200) models.py $ python manage.py makemigrations $ python manage.py migrate Crear  migración Aplicar  migración
  188. class User(AbstractUser):
 
 bio = models.CharField(blank=True, 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  *,  tú  me  sigues  a  mi. •  related_name  (en  este  caso)   •  Limpieza  y  evitar  user_set Extender  el  modelo  User
  189. Índice 1.Python   a. Introducción   b.Tipos  de  datos  

    c. Operadores   d.Usos  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
  190. urlpatterns = [ ... url(r'^admin/', include(admin.site.urls)), ... ] urls.py INSTALLED_APPS

    = (
 'django.contrib.auth',
 'django.contrib.sessions',
 'django.contrib.admin',
 ...
 ) sewngs.py django.contrib.admin
  191. 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)
  192. Instalar  Admin a)Comprobar  que  no  están  Tweet  y  Profile  

    b)Modificar  admin.py   c) Probar  Administración.
  193. 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:
  194. 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 ...>
  195. 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  u*lizando: python manage.py loaddata <fixture fixture ...> •  Si  se  llaman  iniJal_data  y  están  dentro  de  la  carpeta  fixtures   de  la  app,  se  cargan  al  ahcer  el  syncdb.
  196. Tarea:  Avance  en  dwioer   a)Implementar  la  vista  user_page()  

    para  ofrecer  un  perfil  de  usuario   con  su  *meline  personal:   ‣ URL:    user/<username>/ ‣ View:    user_page ‣ Template:    user_page.html hDp://bit.ly/dwiDer-­‐user-­‐page
  197. Tarea:  DRY  urls  en  dwioer   a)Actualizar  todas  las  URLs

     de   nuestro  proyecto  para  referirnos  a   ellas  por  nombre  usando  {% url %} hDp://bit.ly/dwiDer-­‐user-­‐page
  198. Índice 1.Python   a. Introducción   b.Tipos  de  datos  

    c. Operadores   d.Usos  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
  199. Clases  involucradas Widget Componente  visual  equivalente  a  HTML TextInput CheckboxInput

    <input type='text'...>
 <input type='checkbox'...> Field Lógica  de  un  campo,  asociado  a  un  Widget EmailField IPAddressField widget, initial, error, ...
  200. Clases  involucradas Widget Componente  visual  equivalente  a  HTML TextInput CheckboxInput

    <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, ...]
  201. Fields ▪ BooleanField ▪ CharField ▪ ChoiceField ▪ TypedChoiceField ▪

    DateField ▪ DateTimeField ▪ DecimalField ▪ EmailField ▪ FileField ▪ FilePathField ▪ FloatField ▪ ImageField ▪ IntegerField ▪ IPAddressField ▪ MultipleChoiceField ▪ NullBooleanField ▪ RegexField ▪ SlugField ▪ TimeField ▪ URLField ▪ ComboField ▪ MultiValuefield ▪ SplitDateTimeField ▪ ModelChoiceField ▪ ModelMultipleChoiceField
  202. Fields ▪ BooleanField ▪ CharField ▪ ChoiceField ▪ TypedChoiceField ▪

    DateField ▪ DateTimeField ▪ DecimalField ▪ EmailField ▪ FileField ▪ FilePathField ▪ FloatField ▪ ImageField ▪ IntegerField ▪ IPAddressField ▪ MultipleChoiceField ▪ NullBooleanField ▪ RegexField ▪ SlugField ▪ TimeField ▪ URLField ▪ ComboField ▪ MultiValuefield ▪ SplitDateTimeField ▪ ModelChoiceField ▪ ModelMultipleChoiceField
  203. Creación  de  un  Form 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) • Paso  1/3:  Definición  del  formulario  en  forms.py
  204. Creación  de  un  Form <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> • Paso  2/3:  Maquetación  del  formulario  en  su  template
  205. Creación  de  un  Form 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}) • Paso  3/3:  Programación  de  la  vista  en  views.py
  206. Creación  de  un  Form 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}) • Paso  3/3:  Programación  de  la  vista  en  views.py Paoern
  207. Creación  de  un  Form 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}) • Paso  3/3:  Programación  de  la  vista  en  views.py Paoern
  208. Creación  de  un  Form 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}) • Paso  3/3:  Programación  de  la  vista  en  views.py Paoern
  209. Validación  propia 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 Podemos  programar  validación  extra  asociada  a  cada  Field   del  formulario  escribiendo  un  método  clean_<fieldname>:
  210. Validación  propia 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 Podemos  programar  validación  extra  asociada  a  cada  Field   del  formulario  escribiendo  un  método  clean_<fieldname>:
  211. Maquetación  propia ...
 <form action="" method="post">
 <div class="field">
 {{ form.subject.errors

    }}
 <label for="id_subject">Subject:</label>
 {{ form.subject }}
 </div>
 <div class="field">
 {{ form.email.errors }}
 <label for="id_email">E-mail:</label>
 {{ form.email }}
 </div>
 ...
 <input type="submit" value="Submit">
 </form> ... Podemos  personalizar  la  maquetación  tanto  como   queramos,  prescindiendo  de  las  ayudas  de  form.as_table: <style type="text/css">
 ul.errorlist {
 ...
 }
 .errorlist li {
 ...
 }
 </style> Para  los  diseñadores:
  212. Forms  a  par=r  de  Models from django.db import models
 


    class 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
  213. Primer  Form  en  dwioer a)Crear  un  Form  que  permita  publicar

      tweets  desde  *meline.html  al   usuario  que  esté  logueado  desde   django.contrib.admin  (no  tenemos   login  propio  de  momento).
  214. Tarea:  Avance  en  dwioer   a)Implementar  la  vista  users_list()  

    para  visualizar  la  lista  de  usuarios:   ‣ URL:    users/ ‣ View:    users_list ‣ Template:    users_list.html    (Descargar) hDp://bit.ly/users-­‐list
  215. Índice 1.Python   a. Introducción   b.Tipos  de  datos  

    c. Operadores   d.Usos  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
  216. Magia  avanzada 1. Generic  views   2. Context  Processors  

    3. Custom  Template  Filters  &  Tags   4. Middleware   5. Internacionalización   6. Caching   7. Despliegue   8. Apps  recomendadas
  217. Magia  avanzada 1. Generic  views   2. Context  Processors  

    3. Custom  Template  Filters  &  Tags   4. Middleware   5. Internacionalización   6. Caching   7. Despliegue   8. Apps  recomendadas
  218. Generic  views Generic  Views Vistas  con  funcionalidad  genérica  parametrizable  

    mediante  un  diccionario  de  Extra  Op=ons from django.conf.urls.defaults import *
 from mysite import views
 
 urlpatterns = [
 url(r'^foo/$', views.foobar_view, {'template_name': 'template1.html'}),
 url(r'^bar/$', views.foobar_view, {'template_name': 'template2.html'}),
 ] Las  urls  de  urlpaDerns  aceptan  un  3er  parámetro:
  219. Extra  Op*ons  en  urls.py a)Definir  dos  nuevas  URLs  en  urls.py

      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 /] hDp://bit.ly/login-­‐template
  220. Magia  avanzada 1. Generic  views   2. Context  Processors  

    3. Custom  Template  Filters  &  Tags   4. Middleware   5. Internacionalización   6. Caching   7. Despliegue   8. Apps  recomendadas
  221. Context  Processors ¿Context  Processors?  Son  funciones. • Reciben  un  HopRequest()

     como  único  parámetro.   • Devuelven  un  diccionario  para  ser  usado  como  Context().
  222. Context  Processors ¿Context  Processors?  Son  funciones. def ip_address_processor(request):
 return {'ip_address':

    request.META['REMOTE_ADDR']} • Reciben  un  HopRequest()  como  único  parámetro.   • Devuelven  un  diccionario  para  ser  usado  como  Context().
  223. Context  Processors ¿Context  Processors?  Son  funciones. def ip_address_processor(request):
 return {'ip_address':

    request.META['REMOTE_ADDR']} • Reciben  un  HopRequest()  como  único  parámetro.   • Devuelven  un  diccionario  para  ser  usado  como  Context(). TEMPLATES = [{ 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', 'website.context_processors.ip_address_processor', ],},},]
  224. Context  Processors En  lugar  de  encapsular  sólo  el  contexto  de

     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)
  225. ContextProcessors  en  dwioer c) Cuando  el  usuario  esté  logueado,  

    mostrar  Bienvenido,  <username>  y   un  link  para  desloguearse.   d)Cuando  no  esté  logueado,  mostrar   un  link  a  /login.   e)Tip:  user.is_authen*cated()
  226. Magia  avanzada 1. Generic  views   2. Context  Processors  

    3. Custom  Template  Filters  &  Tags   4. Middleware   5. Internacionalización   6. Caching   7. Despliegue   8. Apps  recomendadas
  227. Template  Library Nos  permite  extender  el  sistema  de  templates  

    de  Django  con  Filters  y  Tags  propios Uso {% load milibreria %} 
 ...
 {{ variable|mifiltro:"param" }}
 ...
 {% mitag param1 param2 %}
  228. Template  Library Nos  permite  extender  el  sistema  de  templates  

    de  Django  con  Filters  y  Tags  propios Uso {% load milibreria %} 
 ...
 {{ variable|mifiltro:"param" }}
 ...
 {% mitag param1 param2 %} Creación
  229. Custom  Filters Un  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.
  230. Custom  Filters Un  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()
 
 def cut(value, arg=' '):
 return value.replace(arg, '')
 
 register.filter('cut', cut) Ejemplo
  231. Custom  Filters Un  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, '')
  232. Python   2.4  se  hizo   sexy Custom  Filters Un

     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, '')
  233. Nuestro  propio  Filter  en  dwioer a)Crear  un  Filter  llamado  |mention

      que  al  detectar  un  “@usuario”   convierta  ese  texto  en  un  enlace  al   perfil  de  dwioer  de  ese  usuario.
  234. 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   • Reciben  1  argumento   • Devuelven  un  string • Son  inline   • Reciben  n  argumentos   • Devuelven  un  diccionario   • Insertan  su  propio   fragmento  de  template
  235. SimpleTags Ejemplo:  Devolver  la  hora  actual  formateada. {% current_time "%Y-%m-%d

    %I:%M %p" %} from django import template
 
 register = template.Library()
 @register.simple_tag
 def current_time(format):
 try:
 return datetime.datetime.now().strftime(str(format))
 except UnicodeEncodeError:
 return ''
  236. InclusionTags Ejemplo:  Mostar  anuncios  si  el  usuario  no  es  premium.

    {% show_adverts user %} {% for advert in adverts %} <img src='{{ advert.image }}' /> {% endfor %} adverts.html milibreria.py
  237. InclusionTags Ejemplo:  Mostar  anuncios  si  el  usuario  no  es  premium.

    @register.inclusion_tag('website/adverts.html')
 def show_adverts(user): adverts = [] if not user.profile.is_premium: adverts = Advert.objects.order_by('?').limit(5) return {'adverts': adverts} {% show_adverts user %} {% for advert in adverts %} <img src='{{ advert.image }}' /> {% endfor %} adverts.html milibreria.py
  238. Nuestro  propio  TemplateTag  en  dwioer a)Crear  un  Tag  llamado  

    toggle_follow  que  permita   pintar  un  enlace  de  ‘follow’  o   ‘unfollow’  junto  a  cada  usuario   dwioer  que  aparece  listado  en   users_list.html
  239. Ejercicios  para  subir  nota c) Implementar  “retweet”:  un  botón  junto

     a  cada   tweet  del  *meline  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  men*ons”:  un   *meline  que  sólo  muestre  los  tweets  que  te   mencionen  a  *  (*p:  message__icontains=).
  240. Magia  avanzada 1. Generic  views   2. Context  Processors  

    3. Custom  Template  Filters  &  Tags   4. Middleware   5. Internacionalización   6. Caching   7. Despliegue   8. Apps  recomendadas
  241. Middleware class 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."""
 # ...
  242. Middleware Tenemos  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',
 )
  243. Middleware 1. Sistema  de  BETA   1. Nos  aseguramos  de

     controlar  todas  páginas.   2. Si  el  usuario  *ene  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...
  244. Magia  avanzada 1. Generic  views   2. Context  Processors  

    3. Custom  Template  Filters  &  Tags   4. Middleware   5. Internacionalización   6. Caching   7. Despliegue   8. Apps  recomendadas
  245. Ofrece  integración  con  la  librería  GNU  geDext  de  i18n  

    1. Un  fichero  .pot  con*ene  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
  246. Internacionalización from django.utils.translation import ugettext as _ print _("Cadena de

    texto") • ¿Cómo  indicar  qué  strings  deben  ser  traducidos? • Ges*ón  cómoda  de  singulares  y  plurales
  247. Internacionalización from django.utils.translation import ugettext as _ print _("Cadena de

    texto") • ¿Cómo  indicar  qué  strings  deben  ser  traducidos? from django.utils.translation import ungettext
 
 frase = ungettext("Hay %(total)d resultado",
 "Hay %(total)d resultados", total)
 % { 'total': total } • Ges*ón  cómoda  de  singulares  y  plurales
  248. Magia  avanzada 1. Generic  views   2. Context  Processors  

    3. Custom  Template  Filters  &  Tags   4. Middleware   5. Internacionalización   6. Caching   7. Despliegue   8. Apps  recomendadas
  249. caching •Si  queremos  escalar  nuestro  proyecto  rápidamente....  Cache!   •Recomendado

     =  memcached,  redis,  …   •Acceder  a  la  BD  es  caro,  muy  caro.   •El  Hardware  es  “gra*s”  en  comparación  con  op*mizar  código  op*mizado.  
  250. caching from django.views.decorators.cache import cache_page
 
 @cache_page(60 * 15)
 def

    my_view(request):
 ... views {% load cache %}
 {% cache 500 sidebar %}
 .. sidebar ..
 {% endcache %} templates
  251. caching low  level >>> from django.core.cache import cache >>> cache.set('my_key',

    'hello, world!', 30) >>> cache.get('my_key') 'hello, world!' •Podemos  cachear  cualquier  *po  de  objeto  que  se  pueda  serializar.   •  QuerySets   •  Listas   •  ...
  252. Magia  avanzada 1. Generic  views   2. Context  Processors  

    3. Custom  Template  Filters  &  Tags   4. Middleware   5. Internacionalización   6. Caching   7. Despliegue   8. Apps  recomendadas
  253. Virtualenv •Independencia  completa  de  las  librerías  del  sitema.   •Cada

     proyecto  *ene  su  juego  de  librerías  en  la  versión  que  necesita   •Sin  miedo  a  actualizar   •Sin  miedo  a  migrar   •etc...
  254. Virtualenv •Independencia  completa  de  las  librerías  del  sitema.   •Cada

     proyecto  *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
  255. Virtualenv •Independencia  completa  de  las  librerías  del  sitema.   •Cada

     proyecto  *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
  256. PIP •Gestor  de  paquetes  del  siglo  21  :D   •Permite

     especificar  un  fichero  de  REQUIREMENTS  con  un  listado  de   paquetes  a  instalar.
  257. PIP •Gestor  de  paquetes  del  siglo  21  :D   •Permite

     especificar  un  fichero  de  REQUIREMENTS  con  un  listado  de   paquetes  a  instalar. Django==1.8   psycopg2   feedparser==4.1   stripogram==1.5   GChartWrapper==0.8 pip install -E mi_entorno -r REQUIREMENTS
  258. Nuestro  primer  Virtualenv  +  PIP a)Crear  un  entorno  virtual  

    b)Instalar  Django==1.0   c) Probar  django.VERSION
  259. nginx  +  Gunicorn nginx gunicorn •  nginx  [engine  x]  is

     a  HTTP  and  reverse  proxy  server.   •  Con  una  configuración  muy  sencilla  podremos  u*lizarlo  como  proxy   inverso  a  gunicorn.   •  hop://gunicorn.org/ •  Servidor  Web  WSGI  implementado  en  Python   •  Facilidades  de  puesta  en  marcha  de  proyectos  django   •  Fácilmente  configurable  usando  nginx   •  hop://nginx.org/
  260. gunicorn Django nginx  :80 web1 gunicorn Django nginx  :80 web2

    gunicorn Django nginx  :80 webn nginx  :80  :443 varnish haproxy frontend1 nginx  :80  :443 varnish haproxy frontend2 ipfailover Deploy no  tan  sencillo
  261. Repe**on  leads  to  boredom,   boredom  to  horrifying  mistakes,  

    horrifying  mistakes  to  God-­‐I-­‐wish-­‐I-­‐was-­‐s*ll-­‐bored. “
  262. env.user = "example"
 env.hosts = ["web1.com", "web2.com", "..."]
 
 def

    deploy():
 run('git pull /home/site/')
 sudo('service supervisord restart')
  263. Magia  avanzada 1. Generic  views   2. Context  Processors  

    3. Custom  Template  Filters  &  Tags   4. Middleware   5. Internacionalización   6. Caching   7. Despliegue   8. Apps  recomendadas
  264. django-­‐haystack •  “EL”  Sistema  de  búsquedas  para  Django   •

     Funciona  con  varios  sistemas  de  Indexación   •  Solr,  Xapian,  Whoosh   •  Features:   •  ‘More  like  this’   •Face*ng   •Highligh*ng   •  Spelling  Sugges*on   •  etc... hDp://haystacksearch.org
  265. django-­‐rest-­‐framework •  Framework  para  crear  APIs  RESTful   •  Muy

     fácil  instalación   •  Serialización  a:   •JSON,  XML,  YAML,…   •OAuth   •Throoling,  web-­‐browseable  API,  pagina*on… hDp://www.django-­‐rest-­‐framework.org/
  266. django-­‐registra=on •Sistema  completo  para  la  ges*ón  de  usuarios.   •Desde

     el  registro,  ac*vación  etc...   •DRY!!   •Instalación  muy  sencilla. hDp://bitbucket.org/ubernostrum/django-­‐registra=on/
  267. django-­‐registra=on /ac*vate/complete/   /ac*vate/<ac*va*on_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/   /  reac*vate/ hDp://bitbucket.org/ubernostrum/django-­‐registra=on/
  268. •Configuración  sencilla   •Auten*cación  con:   •twioer,  facebook,  oauth,  openid,

      dropbox,  flickr,  github,  steam...   •Integración  perfecta  con  contrib.auth hDp://github.com/omab/python-­‐social-­‐auth python-­‐social-­‐auth
  269. • Permite  modificar  atributos  de  los  widgets  dentro  de  las

     templates.   • Sin  la  necesidad  de  sobreescribir  el  Widget  del  Form  podemos  cambiar  por   ejemplo  el  *po  del  Field  para  que  sea  html5  (search,  etc..)   • U*lizando  filtros  podemos  por  ejemplo  añadir  clases  CSS. django-­‐widget-­‐tweaks hDps://github.com/kmike/django-­‐widget-­‐tweaks/ {% load widget_tweaks %} {{ form.title|add_class:"css_class_1 css_class_2" }} {{ form.title|add_error_class:"error-border" }} {% render_field form.search_query type="search" %}
  270. • Nos  permite  estandarizar  la  creación  de   emails  u*lizando

     “views”.   • Gracias  a  un  simple  Form  nos  permite   parametrizar  los  emails  y  generar  previews   en  el  navegador.   • Muy  ú*l  para  frontends  que  *enen  que   maquetar  muchos  emails  tanto  html  como   txt. django-­‐mailviews hDps://github.com/disqus/django-­‐mailviews
  271. • Hay  docenas  de  integraciones  de  redis  con  django,  pero

     sin   duda  alguna  esta  es  la  mejor  que  hemos  probado.   • Muy  bien  testeada   • En  desarrollo   • Features:   • Python3  ready   • Client-­‐side  sharding   • Integrada  con  django.cache   • Raw  connec*on  pool django-­‐redis hDps://github.com/niwibe/django-­‐redis
  272. django-­‐command-­‐extensions •Extensión  para  “manage.py”   •Muchas  u*lidades  para  el  día

     a  día   •Una  de  las  mejores:  graph_models   •Usando  GraphViz  genera  un  modelo  relacional  de  los   modelos  de  nuestro  proyecto. hDp://code.google.com/p/django-­‐command-­‐extensions/
  273. hDp://flask.pocoo.org from flask import Flask
 app = Flask(__name__)
 
 @app.route("/")


    def hello():
 return "Hello World!"
 
 if __name__ == "__main__":
 app.run() $ pip install Flask $ python hello.py * Running on http://localhost:5000/
  274. import tornado.ioloop
 import tornado.web
 
 class MainHandler(tornado.web.RequestHandler):
 def get(self):
 self.write("Hello,

    world")
 
 application = tornado.web.Application([
 (r"/", MainHandler),
 ])
 
 if __name__ == "__main__":
 application.listen(8888)
 tornado.ioloop.IOLoop.instance().start() hDp://tornadoweb.org •  real-­‐=me     •  non-­‐blocking     •  epoll  
  275. Desarrollo  Web 1. Op*mización  
 varnish,  redis,  cron,  batch  

    2. Ges*ón  de  errores
 sentry   3. Ges*ón  de  Incidencias
 pingdom,  pagerduty
  276. 30m 10m no-­‐cache Memcached,  redis  etc...   Contenido  externo  

    •APIs,  RSS,  Twioer   Contenido  “Está=co”   •Úl*mas  no*cias   •Nuevos  usuarios   •Úl*mos  tweets   •... Cachear  Contenido
  277. > GET last_tweets <h1>\n<ul><li>Hello from.... Memcached •Ventajas   •Velocidad  

    •Sencillez   •Inconvenientes   •Volá*l:  sólo  reside  en  memoria.   •Sólo  en*ende  cadenas  de  texto.   Cachear  Contenido
  278. > INCR message:143:comments 1 4445 Redis •Ventajas   •Velocidad  

    •Tipos  de  datos  complejos   •Operaciones  atómicas   •Inconvenientes   •Muy  pocas   •Abuso  =  Problemas  (como  todo)   Welcome to my site. 4445 Comments Cachear  Contenido
  279. Existen  múl=ples  “puntos”  donde  cachear.   •Servidor  web   •Intrusismo

      •Complejidad  media   •Código  del  proyecto  “backend”   •Sencillo  de  implementar   •Poco  eficiente   •Proxy   •Sencillo   •Muy  eficiente   Cachear  Requests
  280. •Requests  Anónimas   •Digg  effect   •Landing  page   •Google

      •Contenido  Está=co   •Assets   •Thumbnails   •APIs   •“Hot  Pages”   Request Response Varnish Server Miss Hit Cachear  Requests
  281. Cliente Servidor 500ms bd smtp 200ms 5s Dejar  que  alguien

     haga  el  trabajo  sucio,  antes  o  después csv Delegar
  282. Cliente Servidor 500ms bd smtp 200ms 5s ¿Cuánto  del  trabajo

     sucio  es  imprescindible  al  instante? csv ? ? ? Delegar
  283. Cliente Servidor 500ms bd smtp 200ms 5s csv ? ¿caché?

    ? Delegar ¿Cuánto  del  trabajo  sucio  es  imprescindible  al  instante?
  284. Cliente Servidor 500ms bd smtp 200ms 5s csv ? ¿caché?

    ¿tarea periódica? Delegar ¿Cuánto  del  trabajo  sucio  es  imprescindible  al  instante?
  285. Cliente Servidor 500ms bd smtp 200ms 5s csv ¿caché? ¿tarea

    periódica? ¿cola de mensajes? Delegar ¿Cuánto  del  trabajo  sucio  es  imprescindible  al  instante?
  286. Cliente Servidor 500ms bd smtp 200ms 5s csv ¿caché? Delegar

    antes Delegar después Delegar ¿Cuánto  del  trabajo  sucio  es  imprescindible  al  instante?
  287. * * * * * <cmd> día de la semana

    (0 - 7) mes (1 - 12) día del mes (1 - 31) hora (0 - 23) minuto (0 - 59) # crontab -e $ crontab -e Scheduler  de  trabajos  de  UNIX Cron
  288. # crontab -l 0 1 * * * /usr/sbin/ntpdate pool.ntp.org

    0 */2 * * * /home/root/bin/server-backup @reboot /home/root/bin/email-admins.sh $ crontab -l */5 * * * * /home/ops/bin/billing.sh @hourly /home/ops/bin/caches.py @daily /home/ops/bin/users-csv.py @weekly /home/ops/bin/spending-reports.sh Scheduler  de  trabajos  de  UNIX Cron
  289. Cliente Servidor 500ms bd smtp 200ms 5s csv ¿caché? Delegar

    antes Delegar después Delegar ¿Cuánto  del  trabajo  sucio  es  imprescindible  al  instante?
  290. Sistema  de  Tareas  Asíncronas  distribuidas.   •Features:  Colas,  Concurrencia,  Distribuido...

      •Pro:  Muy  fácil  de  implementar  y  escalable.   • Casos  prác=cos:   •Enviar  un  email  (No*fica*ones,  ...)   •Calcular  el  karma  de  de  los  usuarios  del  sistema.   •Tareas  programadas  (Limpieza,  Post-­‐procesado,  etc...)   •Regenerar  caches  etc..    hDp://celeryproject.org Celery
  291. El  principal  componente  es  el  Broker.  Se  encarga  de  almacenar

     y  entregar   tareas  a  todos  los  workers.   Estable Experimental Celery
  292. Server #1 celery worker celery beat Server #3 celery worker

    Server #4 web node Server #5 web node añadir procesar procesar añadir añadir Server #2 celery worker procesar Celery  +  RabbitMQ
  293. Server #1 celery worker celery beat Server #3 celery worker

    Server #4 web node Server #5 web node añadir procesar procesar añadir añadir Server #2 celery worker procesar Celery  +  RabbitMQ
  294. Server #1 celery worker celery beat Server #3 celery worker

    Server #4 web node Server #5 web node añadir procesar procesar añadir añadir Server #2 celery worker procesar Celery  +  RabbitMQ
  295. Conceptos  clave:   • Atómico:  Las  tareas  se  entregan  solo

     a  un  worker.   • Distribuido:  Los  nodos  son  independientes  unos  de  otros  y  el   número  puede  aumentar  y  disminuir  dinámicamente.   • Fiable:  Si  no  se  informa  a  RabbitMQ  sobre  la  finalización  de  una   tarea,  esta  vuelve  a  formar  parte  de  la  cola.  En  caso  de  catástrofe  no   perdemos  tareas.   • Rates:  Celery  nos  permite  definir  rates  para  nos  sobrecargar  el   sistema  o  APIs  externas.   • Tareas  Periodicas:  Celery  beat  registrará  por  nosotros  tareas  en  la   cola  de  la  misma  manera  que  lo  haría  cron. Celery  +  RabbitMQ
  296. Preparar  la  información  para  acceder  más   rápido  a  ella

     en  el  momento  de  la  consulta DB Search Indexar
  297. SELECT date(timestamp) as day, count(*) FROM stamp WHERE key=%s AND

    date(timestamp) > current_date - interval %s GROUP BY day ORDER BY day; BEGIN; DROP TABLE IF EXISTS "stamp"; CREATE TABLE "stamp" ( "key" varchar(255) NOT NULL, "timestamp" timestamp without time zone NOT NULL ) ; COMMIT; con 4.221.883 registros, 11.488 segundos DB  Index
  298. BEGIN; DROP TABLE IF EXISTS "stamp"; CREATE TABLE "stamp" (

    "key" varchar(255) NOT NULL, "timestamp" timestamp without time zone NOT NULL ) ; CREATE INDEX "stamp_key_idx" ON stamp(key); COMMIT; SELECT date(timestamp) as day, count(*) FROM stamp WHERE key=%s AND date(timestamp) > current_date - interval %s GROUP BY day ORDER BY day; con 4.221.883 registros, 11.488 segundos DB  Index
  299. BEGIN; DROP TABLE IF EXISTS "stamp"; CREATE TABLE "stamp" (

    "key" varchar(255) NOT NULL, "timestamp" timestamp without time zone NOT NULL ) ; CREATE INDEX "stamp_key_idx" ON stamp(key); COMMIT; SELECT date(timestamp) as day, count(*) FROM stamp WHERE key=%s AND date(timestamp) > current_date - interval %s GROUP BY day ORDER BY day; con 4.221.883 registros, segundos DB  Index
  300. BEGIN; DROP TABLE IF EXISTS "stamp"; CREATE TABLE "stamp" (

    "key" varchar(255) NOT NULL, "timestamp" timestamp without time zone NOT NULL ) ; CREATE INDEX "stamp_key_idx" ON stamp(key); COMMIT; SELECT date(timestamp) as day, count(*) FROM stamp WHERE key=%s AND date(timestamp) > current_date - interval %s GROUP BY day ORDER BY day; con 4.221.883 registros, 11.488 0.107 segundos DB  Index
  301. Cliente Servidor bd q='covent garden' SELECT * FROM messages WHERE

    subject like '%covent garden%' OR body like '%covent garden%' OR author like '%covent garden%'; SELECT * FROM locations WHERE name like '%covent garden%' OR description like '%covent garden%'; SELECT * FROM pages WHERE name like '%covent garden%' OR description like '%covent garden%'; SELECT * FROM shareables WHERE name like '%covent garden%' OR description like '%covent garden%'; Search  Index
  302. Cliente Servidor bd q='covent garden' SELECT * FROM messages WHERE

    subject like '%covent garden%' OR body like '%covent garden%' OR author like '%covent garden%'; SELECT * FROM locations WHERE name like '%covent garden%' OR description like '%covent garden%'; SELECT * FROM pages WHERE name like '%covent garden%' OR description like '%covent garden%'; SELECT * FROM shareables WHERE name like '%covent garden%' OR description like '%covent garden%'; mmm... NO Search  Index
  303. Redis is an open source, BSD licensed, advanced key-value store.

    It is often referred to as a data structure server since keys can contain strings, hashes, lists, sets and sorted sets. “ ” hashes lists sets sorted sets strings pub/sub scripts Redis
  304. Problema:   Mostrar  avatares  de  25  usuarios  que  compartan  algún

     área   con*go  promocionando  aquellos  que  no  tengan  uno  de  los   avatares  por  defecto. Custom Default Redis  como  Index
  305. Solución:  Sorted  Sets
 1.  Para  cada  area  crear  un  sorted

     set  con  el  id  de  todos  los  miembros.   Redis  como  Index
  306. Solución:  Sorted  Sets
 1.  Para  cada  area  crear  un  sorted

     set  con  el  id  de  todos  los  miembros.   > ZADD area:1:followers 1 1 area:1:followers 1 Redis  como  Index
  307. Solución:  Sorted  Sets
 1.  Para  cada  area  crear  un  sorted

     set  con  el  id  de  todos  los  miembros.   > ZADD area:1:followers 1 1 > ZADD area:1:followers 0 2 area:1:followers 1 2 Redis  como  Index
  308. Solución:  Sorted  Sets
 1.  Para  cada  area  crear  un  sorted

     set  con  el  id  de  todos  los  miembros.   > ZADD area:1:followers 1 1 > ZADD area:1:followers 0 2 > ZADD area:2:followers 1 1 area:1:followers 1 2 area:2:followers 1 Redis  como  Index
  309. Solución:  Sorted  Sets
 1.  Para  cada  area  crear  un  sorted

     set  con  el  id  de  todos  los  miembros.   > ZADD area:1:followers 1 1 > ZADD area:1:followers 0 2 > ZADD area:2:followers 1 1 > ZADD area:3:followers 0 4 area:1:followers 1 2 area:2:followers 1 area:3:followers 4 Redis  como  Index
  310. Solución:  Sorted  Sets
 1.  Para  cada  area  crear  un  sorted

     set  con  el  id  de  todos  los  miembros.   > ZADD area:1:followers 1 1 > ZADD area:1:followers 0 2 > ZADD area:2:followers 1 1 > ZADD area:3:followers 0 4 > ZADD area:3:followers 1 5 area:1:followers 1 2 area:2:followers 1 area:3:followers 5 4 Redis  como  Index
  311. Problema: ¿Usuarios que siguen el area #1? > GET area:1:followers

    area:1:followers 1 2 area:2:followers 1 area:3:followers 5 4 Redis  como  Index
  312. Problema:  ¿Usuarios  que  siguen  el  area  #1  o  el  area

     #2?   > ZINTERSTORE areas:1-2:followers 2 area:1:followers area:2:followers AGGREGATE MAX > GET areas:1-2:followers area:2:followers 1 area:3:followers 5 4 areas:1-2:followers area:1:followers 1 2 1 2 Redis  como  Index
  313. Problema:  25  usuarios  que  sigan  el  area  #1  o  el

     area  #2  promocionando  aquellos   que  tengan  avatar.   > ZREVRANGE areas:1-2:followers 0 25 area:2:followers 1 area:3:followers 5 4 area:1:followers 1 2 Redis  como  Index
  314. Problema:  25  usuarios  que  sigan  el  area  #1  o  el

     area  #2  promocionando  aquellos   que  tengan  avatar.   > ZREVRANGE areas:1-2:followers 0 25 area:2:followers 1 area:3:followers 5 4 areas:1-2:followers area:1:followers 1 2 1 2 Redis  como  Index
  315. Yo  mi  me  conmigo...   Es  muy  embarazoso  darse  cuenta

     que  tu  web  se  ha  caído  porque  te  lo  diga  un  cliente.   Hay  docenas  de  servicios  como  pingdom  que  se  dedican  a  testear  tu  web  desde   múl*ples  localizaciones.   Features  interesantes:   • Monitorizar  estado  y  *empo  de  respuesta  de  páginas  clave.   • Comprobar  *empos  de  respuesta  desde  la  otra  parte  del  mundo.     • No*ficaciones  SMS.   • Up*me  reports. Pingdom