Upload
betabeers
View
695
Download
0
Embed Size (px)
DESCRIPTION
Citation preview
Juan Riaza
@juanriaza
Don’t reinvent the wheel
• 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, ...
El Intérprete
El Intérprete
$ python holamundo.py hola mundo!$
Modo Batch
#!/usr/bin/env pythonprint "hola mundo!"
holamundo.py
El Intérprete
$ pythonPython 2.6.5 (r265:79063, Apr 16 2010, 13:09:56) [GCC 4.4.3] on linux2Type "help", "copyright", "credits" or "license" for more information.>>> print "hola mundo!"hola mundo!
Modo Interac0vo
$ python holamundo.py hola mundo!$
Modo Batch
#!/usr/bin/env pythonprint "hola mundo!"
holamundo.py
Tipos de datos
h>p://docs.python.org/library/stdtypes.html
object
Tipos de datos
h>p://docs.python.org/library/stdtypes.html
object
1234 3.1415int float35Llong
Tipos de datos
h>p://docs.python.org/library/stdtypes.html
object
1234 3.1415int float35Llong
True Falsebool
Tipos de datos
h>p://docs.python.org/library/stdtypes.html
object
1234 3.1415int float35Llong
True Falsebool
'spam' "guido's" """n lines"""str
Tipos de datos
h>p://docs.python.org/library/stdtypes.html
object
1234 3.1415int float35Llong
True Falsebool
'spam' "guido's" """n lines"""str
[1, [2, 'three'], 4]list
Tipos de datos
h>p://docs.python.org/library/stdtypes.html
object
1234 3.1415int float35Llong
True Falsebool
'spam' "guido's" """n lines"""str
[1, [2, 'three'], 4]list
{'food': 'spam', 'taste': 'yum'}dict
Tipos de datos
h>p://docs.python.org/library/stdtypes.html
object
1234 3.1415int float35Llong
True Falsebool
'spam' "guido's" """n lines"""str
[1, [2, 'three'], 4]list
{'food': 'spam', 'taste': 'yum'}dict
(1, 'spam', 4, 'U')tuple
Tipos de datos
h>p://docs.python.org/library/stdtypes.html
object
1234 3.1415int float35Llong
True Falsebool
'spam' "guido's" """n lines"""str
[1, [2, 'three'], 4]list
{'food': 'spam', 'taste': 'yum'}dict
(1, 'spam', 4, 'U')tuple
¡Tipado
dinámico!
Operadores
h>p://docs.python.org/library/operator.html
Operadores
numéricosa + b a - b a * b a / b
a % b -a +a a ** b
h>p://docs.python.org/library/operator.html
Operadores
numéricosa + b a - b a * b a / b
a % b -a +a a ** b
comparadoresa < b a <= b a > b
a >= b a == b a != b
h>p://docs.python.org/library/operator.html
Operadores
numéricosa + b a - b a * b a / b
a % b -a +a a ** b
comparadoresa < b a <= b a > b
a >= b a == b a != b
lógicos a or b a and b not a
h>p://docs.python.org/library/operator.html
Usos frecuentes: list
Usos frecuentes: list>>> nums = [1, 2, 3]>>> nums[0]1
Usos frecuentes: list>>> nums = [1, 2, 3]>>> nums[0]1
>>> 2 in numsTrue
Usos frecuentes: list>>> nums = [1, 2, 3]>>> nums[0]1
>>> nums.append(4)>>> print nums[1, 2, 3, 4]
>>> 2 in numsTrue
Usos frecuentes: list>>> nums = [1, 2, 3]>>> nums[0]1
>>> nums.append(4)>>> print nums[1, 2, 3, 4]
>>> 2 in numsTrue
>>> len(nums)4
Usos frecuentes: str
Usos frecuentes: str>>> "Python mola"[1:4]'yth'
Usos frecuentes: str>>> "Python mola"[1:4]'yth'
>>> "Python mola".find("mola")7
Usos frecuentes: str>>> "Python mola"[1:4]'yth'
>>> "Python mola".find("mola")7
>>> "Python mola".replace("Python", "PHP no")'PHP no mola'
Usos frecuentes: str>>> "Python mola"[1:4]'yth'
>>> "Python mola".find("mola")7
>>> "Python mola".replace("Python", "PHP no")'PHP no mola'
>>> "Python mola".split(" ")['Python', 'mola']
Usos frecuentes: str>>> "Python mola"[1:4]'yth'
>>> "Python mola".find("mola")7
>>> "Python mola".replace("Python", "PHP no")'PHP no mola'
>>> "Python mola".split(" ")['Python', 'mola']
>>> " ".join(["Python", "mola"])"Python mola"
Usos frecuentes: dict
Usos frecuentes: dict>>> user = {'nick': 'neo', 'age': 24}>>> user.keys()['nick', 'age']>>> user.values()['neo', 24]
Usos frecuentes: dict>>> user = {'nick': 'neo', 'age': 24}>>> user.keys()['nick', 'age']>>> user.values()['neo', 24]
>>> user['age']24
>>> user.get('age', 20)24
Usos frecuentes: dict>>> user = {'nick': 'neo', 'age': 24}>>> user.keys()['nick', 'age']>>> user.values()['neo', 24]
>>> user['age']24
>>> user.get('age', 20)24
>>> 'nick' in userTrue
Usos frecuentes: dict>>> user = {'nick': 'neo', 'age': 24}>>> user.keys()['nick', 'age']>>> user.values()['neo', 24]
>>> user['age']24
>>> user.get('age', 20)24
>>> 'nick' in userTrue
>>> user.update({'nick': 'alatar', 'age': 25})>>> user{'nick': 'alatar', 'age': 25}
Usos frecuentes: str %
Usos frecuentes: str %
>>> "%s es muy sabio" % "Hycker"'Hycker es muy sabio'
Usos frecuentes: str %
>>> "%s es muy sabio" % "Hycker"'Hycker es muy sabio'
>>> "%s sabe %i idiomas" % ("Hycker", 5)'Hycker sabe 5 idiomas'
Usos frecuentes: str %
>>> "%s es muy sabio" % "Hycker"'Hycker es muy sabio'
>>> "%s sabe %i idiomas" % ("Hycker", 5)'Hycker sabe 5 idiomas'
>>> t = "%(NOMBRE)s sabe %(IDIOMAS)i idiomas">>> v = {'NOMBRE': 'Hycker', 'IDIOMAS': 5}>>> t % v'Hycker sabe 5 idiomas'
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ódulos1. 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
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ódulos1. 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
23
Módulosjuego/ __init__.py bonus/ __init__.py estrella.py moneda.py planta.py ... personajes/ __init__.py mario.py luigi.py princesa.py ... enemigos/ __init__.py seta.py tortuga.py bomba.py ...
Módulosjuego/ __init__.py bonus/ __init__.py 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()
{}Estructuras
{}Estructuras
>>> from __future__ import braces File "<stdin>", line 1 SyntaxError: not a chance
Identación
4 Espacios para la identación
>>> from __future__ import braces File "<stdin>", line 1 SyntaxError: not a chance
Identación
4 Espacios para la identaciónPEP 8
• Guido van Rossum (2001)
• Recomendaciones de es0lo
• “Readability counts”
• “Code is read much more oQen than it is wriSen.”
• Muy recomendable importante seguirlo.
PEP 8¿PEP 8?
h>p://www.python.org/dev/peps/pep-‐0008/
def my_first_function(p1, p2): return "Hello World!"
Funciones
MinúsculasPalabras separadas por _Evitar camelCase
def my_first_function(p1, p2): return "Hello World!"
12
3
Funciones
MinúsculasPalabras separadas por _Evitar camelCase
PEP 8
Conversión de -pos
h>p://docs.python.org/library/func-ons.html
Conversión de -pos
>>> int(1.3)1
h>p://docs.python.org/library/func-ons.html
Conversión de -pos
>>> str(2)'2'
>>> int(1.3)1
h>p://docs.python.org/library/func-ons.html
Conversión de -pos
>>> str(2)'2'
>>> int(1.3)1
>>> float(1)1.0
h>p://docs.python.org/library/func-ons.html
Conversión de -pos
>>> str(2)'2'
>>> int(1.3)1
>>> float(1)1.0
>>> tuple([1,2,3])(1, 2, 3)
h>p://docs.python.org/library/func-ons.html
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)
h>p://docs.python.org/library/func-ons.html
Funciones comunes
h>p://docs.python.org/library/func-ons.html
Funciones comunes
>>> len("Python Mola")11>>> len([1,2,3,4])4
h>p://docs.python.org/library/func-ons.html
Funciones comunes
>>> len("Python Mola")11>>> len([1,2,3,4])4
>>> range(5)[0, 1, 2, 3, 4]>>> range(1,7)[1, 2, 3, 4, 5, 6]>>> range(1,7,2)[1, 3, 5]
h>p://docs.python.org/library/func-ons.html
Funciones comunes
>>> 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'>
h>p://docs.python.org/library/func-ons.html
Funciones comunes
>>> len("Python Mola")11>>> len([1,2,3,4])4
>>> range(5)[0, 1, 2, 3, 4]>>> range(1,7)[1, 2, 3, 4, 5, 6]>>> range(1,7,2)[1, 3, 5]
>>> 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...
h>p://docs.python.org/library/func-ons.html
Funciones interesantes
Son sólo un ejemplo...
h>p://docs.python.org/library/func-ons.html
Funciones interesantes
>>> a = [1,2,3]>>> b = [4,5,6]>>> zip(a,b)[(1, 4), (2, 5), (3, 6)]
Son sólo un ejemplo...
h>p://docs.python.org/library/func-ons.html
Funciones interesantes
>>> a = [1,2,3]>>> b = [4,5,6]>>> zip(a,b)[(1, 4), (2, 5), (3, 6)]
>>> sorted([5,1,3,4,2])[1, 2, 3, 4, 5]
Son sólo un ejemplo...
h>p://docs.python.org/library/func-ons.html
Funciones interesantes
>>> a = [1,2,3]>>> b = [4,5,6]>>> 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...
h>p://docs.python.org/library/func-ons.html
Funciones interesantes
>>> a = [1,2,3]>>> b = [4,5,6]>>> zip(a,b)[(1, 4), (2, 5), (3, 6)]
>>> 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...
h>p://docs.python.org/library/func-ons.html
Funciones de ayuda
Funciones de ayuda>>> dir([1,2,3])['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__delslice__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__setslice__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
Funciones de ayuda>>> dir([1,2,3])['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__delslice__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__setslice__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
>>> help(filter)Help on built-in function filter in module __builtin__:
filter(...) filter(function or None, sequence) -> list, tuple, or string Return those items of sequence for which function(item) is true. If function is None, return the items that are true. If sequence is a tuple or string, return the same type, else return a list.(END)
class Student(object): def __init__(self, name, age): self.name = name self.age = age def hello(self): return 'My name is %s' % self.name
Clases
s = Student("Jorge", 24)
camelCase
class Student(object): def __init__(self, name, age): self.name = name self.age = age def hello(self): return 'My name is %s' % self.name
1 2
3
4
5
Clases
s = Student("Jorge", 24)
camelCasePEP 8
El operador ()
• Es importante diferenciar:
funcion vs funcion()
Clase vs Clase()
• El operador () permite:
• Invocar funciones:
• Instanciar clases:
resultado = funcion()
objeto = Clase("param1")
$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
$count = 0;while ($count < 5) { echo "Number ".$count; $count+=1;}
count = 0while count < 5: print "Number %i" % count count+=1
Sentencias: while
for ($i=0; $i < 5; $i++) { echo "Number ".$count;}
for i in range(4): print "Number %i" % count
Sentencias: for
try { $result = 3 / 0;} catch (Exception $e) { echo "Division by Zero"}
try: result = 3 / 0except: print "Division by Zero"
Sentencias: try-‐except
• Python es un lenguaje fácil de aprender.• Menos código:
• Muchos Muchísimos menos errores de Sintaxis.
• Mayor velocidad de escritura.
• Proto0pado... U0lizado por grandes empresas.
Conclusiones
• Python es un lenguaje fácil de aprender.• Menos código:
• Muchos Muchísimos menos errores de Sintaxis.
• Mayor velocidad de escritura.
• Proto0pado... U0lizado por grandes empresas.
etc...
Conclusiones
Evolución de la Web
Desarrollo Web
1ª Generación 2ª Generación 3ª Generación
HTML
CGIPHP
ASP
JSP
...
Django
Rails
Symfony
...
Frameworks web
Django: Qué y dónde
• Loose coupling, Acoplamiento débil.
• Cada capa es independiente y desconoce completamente
a las demás.
• Menos código.
• Rápido desarrollo.• Esto es el siglo 21, todo el trabajo tedioso hay que evitarlo.
• Don’t Repeat Yourself (DRY)
Filoso\a
• Loose coupling, Acoplamiento débil.
• Cada capa es independiente y desconoce completamente
a las demás.
• Menos código.
• Rápido desarrollo.• Esto es el siglo 21, todo el trabajo tedioso hay que evitarlo.
• Don’t Repeat Yourself (DRY)
Every distinct concept and/or piece of data should live in one, and only one, place. Redundancy is bad. Normalization is good.”“
Filoso\a
• Explicit is beSer than implicit.
• Este es un principio de Python.• Django no debe hacer demasiada “Magia”.
• Si algo es “Mágico” ha de haber una buena razón.
• Consistencia• Ha de ser consistente a todos los niveles.
• Eficiencia, Seguridad, Flexibilidad y Simplicidad.
Filoso\a
h>p://docs.djangoproject.com/en/dev/misc/design-‐philosophies/
La comunidad
La comunidad
• django-‐users
22.000 miembros
• django-‐developers
7.000 miembros
• djangoproject.com
+500.000 visitas únicas mensuales
¿Quién usa Django?
¿Quién usa Django?
Bienvenidos al mundo de Oz
* Incluida la carpeta del proyecto
Ficheros y Carpetas¿Es Django tán simple y fácil de usar?
* Incluida la carpeta del proyecto
Ficheros y Carpetas
Ficheros
Carpetas
¿Es Django tán simple y fácil de usar?
Rails Symfony
149 117
35 29
* Incluida la carpeta del proyecto
Ficheros y Carpetas
Ficheros
Carpetas
¿Es Django tán simple y fácil de usar?
Rails Symfony
149 117
35 29
* Incluida la carpeta del proyecto
Ficheros y Carpetas
Ficheros
Carpetas
¿Es Django tán simple y fácil de usar?
Rails Symfony
149 117
35 29
* Incluida la carpeta del proyecto
Ficheros y Carpetas
Django
5
2
Ficheros
Carpetas
¿Es Django tán simple y fácil de usar?
Let’s enjoy
Crear nuestro proyectode 5 ficheros ;-‐)
Crear nuestro proyecto
$ django-admin startproject dwitter
de 5 ficheros ;-‐)
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 ;-‐)
seungs.py
Arrancar nuestro proyectode 5 ficheros ;-‐)
Arrancar nuestro proyectode 5 ficheros ;-‐)
$ cd dwitter$ python manage.py runserver
Validating models...0 errors found
Django version 1.4, using settings 'dwitter.settings'Development server is running at http://127.0.0.1:8000/Quit the server with CONTROL-C.
Arrancar nuestro proyectode 5 ficheros ;-‐)
$ cd dwitter$ python manage.py runserver
Validating models...0 errors found
Django version 1.4, using settings 'dwitter.settings'Development server is running at http://127.0.0.1:8000/Quit the server with CONTROL-C.
MVC en Django
Modelo = Model Vista = Template Controlador = URL+View
URLs y Vistas
• El fichero urls.py actúa como puerta de entrada para las pe0ciones HTTP
• Se definen URLs elegantes mediante expresiones regulares que redirigen a funciones de views.py
urls.py
views.py
hSp://mysite.com/about/
html ...
¿urlpaSerns?
URLs y Vistas
• La función de views.py recibe como parámetros un objeto
H>pRequest y todos los parámetros de la URL capturados,
teniendo que devolver siempre un objeto H>pResponse
views.py
H>pRequest(), ...
H>pResponse()
URLs y VistasEjemplo 1: http://mysite.com/time
from django.conf.urls.defaults import *from mysite.views import hora_actual
urlpatterns = patterns('', url(r'^time/$', hora_actual),)
from django.http import HttpResponsefrom datetime import datetime
def hora_actual(request): now = datetime.now() html = "Son las %s." % now
return HttpResponse(html)
urls.py
views.py
URLs y Vistas
from django.conf.urls.defaults import *from mysite.views import dentro_de
urlpatterns = patterns('', url(r'^time/plus/(\d{1,2})/$', dentro_de),)
from django.http import HttpResponsefrom datetime import datetime, timedelta
def dentro_de(request, offset): offset = int(offset) dt = datetime.now() + timedelta(hours=offset) html = "En %i hora(s), serán las %s." % (offset, dt)
return HttpResponse(html)
urls.py
views.py
Ejemplo 2: http://mysite.com/time/plus/2
URLs y Vistas
from django.conf.urls.defaults import *from mysite.views import dentro_de
urlpatterns = patterns('', url(r'^time/plus/(\d{1,2})/$', dentro_de),)
from django.http import HttpResponsefrom datetime import datetime, timedelta
def dentro_de(request, offset): offset = int(offset) dt = datetime.now() + timedelta(hours=offset) html = "En %i hora(s), serán las %s." % (offset, dt)
return HttpResponse(html)
urls.py
views.py
Ejemplo 2: http://mysite.com/time/plus/2
¡Recuerda!: MVC
Templates• Separan la lógica de presentación a una capa independiente.
• Ficheros independientes (.html)
• Lenguaje independiente (¡para diseñadores!)
Templates• Se basan en dos 0pos de objetos: Template() y Context().
• Un objeto Template() con0ene el string de salida que queremos devolver en el HSpResponse (normalmente HTML), pero incluyendo e0quetas especiales de Django.
• Un objeto Context() con0ene un diccionario con los valores que dan contexto a una plan0lla, los que deben usarse para renderizar un objeto Template().
"Bienvenido, {{ user }}."
{'user': 'alatar'}
Template:
Context:
"Bienvenido, alatar."
Templates
from django.http import HttpResponsefrom django.template import Template, Contextfrom 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 obje0vo: Template + Context
Templates• Segunda aproximación al obje0vo: open(), read(), close()
from django.http import HttpResponsefrom django.template import Template, Contextfrom datetime import datetime
def hora_actual(request): now = datetime.now() fp = open('/home/django/templates/hora.html') t = Template(fp.read()) fp.close() c = Context({'hora': now}) html = t.render(c) return HttpResponse(html)
Templates• Segunda aproximación al obje0vo: open(), read(), close()
from django.http import HttpResponsefrom django.template import Template, Contextfrom datetime import datetime
def hora_actual(request): now = datetime.now() fp = open('/home/django/templates/hora.html') t = Template(fp.read()) fp.close() c = Context({'hora': now}) html = t.render(c) return HttpResponse(html)
Templates• Segunda aproximación al obje0vo: open(), read(), close()
from django.http import HttpResponsefrom django.template import Template, Contextfrom 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!
Templates• Tercera aproximación al obje0vo: get_template()
from django.http import HttpResponsefrom django.template.loader import get_templatefrom django.template import Contextfrom 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)
TEMPLATE_DIRS = ( '/home/django/templates',)
seungs.py
Templates• Tercera aproximación al obje0vo: get_template()
TEMPLATE_DIRS = ( '/home/django/templates',)
seungs.py
from django.http import HttpResponsefrom django.template.loader import get_templatefrom django.template import Contextfrom datetime import datetime
def hora_actual(request): now = datetime.now() t = get_template('hora.html') c = Context({'hora': now}) html = t.render(c) return HttpResponse(html)
Templates• Tercera aproximación al obje0vo: get_template()
TEMPLATE_DIRS = ( '/home/django/templates',)
seungs.py
from django.http import HttpResponsefrom django.template.loader import get_templatefrom django.template import Contextfrom 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)
S0ll
boring...
Templates• Obje0vo alcanzado: render()
from django.shortcuts import renderfrom datetime import datetime
def hora_actual(request): now = datetime.now() return render(request, 'hora.html', {'hora': now})
Templates• Obje0vo alcanzado: render()
from django.shortcuts import renderfrom datetime import datetime
def hora_actual(request): now = datetime.now() return render(request, 'hora.html', {'hora': now})
Boring...?
Templates• Obje0vo alcanzado: render()
from django.shortcuts import renderfrom datetime import datetime
def hora_actual(request): now = datetime.now() return render(request, 'hora.html', {'hora': now})
AWESOME!
Templates en detalle
• Si, otro sistema de templates
• Smarty, Tiles, ClearSilver ...
•Describen cuál va a ser el resultado que ven los usuarios.
• Desacoplado de Python ( Diseñadores muy lejos de Python )
• HTML (o no)... con esteroides.
• Muy sencillo de aprender
• KISS: Keep It Simple, Stupid
• Muy sencillo de extender
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.
Templates: {{}}
<html> <head>Ejemplo templates</head> <body> Hola, {{ username }}. </body></html>
{'username': 'juan'}
<html> <head>Ejemplo templates</head> <body> Hola, juan. </body></html>
Filters y Tags
Filters y Tags
Filters y Tags
{{ varible|filter }}filter
Filters y Tags
{{ varible|filter }}filter
{% tag var1 var2 %}inline tag
Filters y Tags
{{ varible|filter }}filter
{% tag var1 var2 %}inline tag
{% tag var1 %} ...{% endtag %}
block tag
Templates: tags {% %}
Templates: tags {% %}
{% comment %} Bu! {% endcomment %}comment
Templates: tags {% %}
{% comment %} Bu! {% endcomment %}comment
for {% for elemento in lista %} <li>{{ elemento }}<li>{% endfor %}
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
Templates: tags {% %}
Templates: tags {% %}cycle {% for elemento in lista %}
<li class="{% cycle 'rojo' 'azul' %}">{{ elemento }}<li>{% endfor %}
Templates: tags {% %}cycle {% for elemento in lista %}
<li class="{% cycle 'rojo' 'azul' %}">{{ elemento }}<li>{% endfor %}
include {% include "foo/bar.html" %}
Templates: tags {% %}cycle {% for elemento in lista %}
<li class="{% cycle 'rojo' 'azul' %}">{{ elemento }}<li>{% endfor %}
include {% include "foo/bar.html" %}
forloop {% for elemento in lista %} <li>{{ forloop.counter }}.{{ elemento }}<li>{% endfor %}
Templates: tags {% %}cycle {% for elemento in lista %}
<li class="{% cycle 'rojo' 'azul' %}">{{ elemento }}<li>{% endfor %}
include {% include "foo/bar.html" %}
forloop {% for elemento in lista %} <li>{{ forloop.counter }}.{{ elemento }}<li>{% endfor %}
empty {% for elemento in lista %} <li class="{% cycle 'rojo' 'azul' %}">{{ elemento }}<li>{% empty %} Sin elementos.{% endfor %}
Templates: Filters
<html> <head>Ejemplo templates</head> <body> Hola, {{ username|title }}. </body></html>
{'username': 'juan'}
<html> <head>Ejemplo templates</head> <body> Hola, Juan. </body></html>
-tle
Templates: Filters
Templates: Filters{'username': 'Juan es majo'}
{{ username|length }}length 12
Templates: Filters{'username': 'Juan es majo'}
{{ username|length }}length 12
{{ username|cut }}cut Juanesmajo
Templates: Filters{'username': 'Juan es majo'}
{{ username|length }}length 12
{{ username|cut }}cut Juanesmajo
{{ username|slugify }}slugify juan-es-majo
Templates: Filters{'username': 'Juan es majo'}
{{ username|length }}length 12
{{ username|cut }}cut Juanesmajo
{{ username|slugify }}slugify juan-es-majo
{{ username|wordcount }}wordcount 3
Templates: Filters{'username': 'Juan es majo'}
{{ username|length }}length 12
{{ username|cut }}cut Juanesmajo
{{ username|slugify }}slugify juan-es-majo
{{ username|upper }}upper JUAN ES MAJO
{{ username|wordcount }}wordcount 3
Templates: Filters{'username': 'Juan es majo'}
{{ username|length }}length 12
{{ username|cut }}cut Juanesmajo
{{ username|slugify }}slugify juan-es-majo
{{ username|upper }}upper JUAN ES MAJO
{{ username|wordcount }}wordcount 3
{{ username|default:”Desconocido” }}default
{'username': None}
Desconocido
Templates: Filters
Templates: Filters{'username': 'Juan es <b>majo, guapo y <em>listo</em></b>'}
{{ username|striptags }}striptags
Juan es majo guapo y listo
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> ...
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>
Templates: Filters
Templates: Filters{'value': 123456789}
{{ value|add:”1” }}add 123456790
Templates: Filters{'value': 123456789}
{{ value|add:”1” }}add 123456790
{{ value|filesizeformat }}filesizeformat 117.7MB
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
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
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
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 %}
Modelos
¿SQL?
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})
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})
12
34
5
6
12 lineas de Python... ¬_¬
ORM (Object-‐Rela0onal mapping)
Ejemplo ORM
def book_list(request):
names = Books.objects.all().order_by('name')
return render(request, 'book_list.html', {'names':names})
Ejemplo ORM
def book_list(request):
names = Books.objects.all().order_by('name')
return render(request, 'book_list.html', {'names':names})
1 2
Fucking Ninjas!
Modelofrom 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)
Modelofrom 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)
Fucking Awesome Ninjas!
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
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
¿Es magia? No.
BEGIN;CREATE TABLE "website_books" ( "id" integer NOT NULL PRIMARY KEY, "name" varchar(100) NOT NULL, "created" datetime NOT NULL, "available" bool NOT NULL);COMMIT;
BEGIN;CREATE TABLE "website_books" ( "id" serial NOT NULL PRIMARY KEY, "name" varchar(100) NOT NULL, "created" timestamp with time zone NOT NULL, "available" boolean NOT NULL);COMMIT;
¿Es magia? No.$ python manage.py sqlall website
BEGIN;CREATE TABLE "website_books" ( "id" integer NOT NULL PRIMARY KEY, "name" varchar(100) NOT NULL, "created" datetime NOT NULL, "available" bool NOT NULL);COMMIT;
BEGIN;CREATE TABLE "website_books" ( "id" serial NOT NULL PRIMARY KEY, "name" varchar(100) NOT NULL, "created" timestamp with time zone NOT NULL, "available" boolean NOT NULL);COMMIT;
Configurar sesngs.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.',
'NAME': '',
'USER': '',
'PASSWORD': '',
'HOST': '',
'PORT': '',
}
}
'postgresql_psycopg2',
'postgresql', 'mysql',
'sqlite3' or 'oracle'.
Configurar sesngs.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.',
'NAME': '',
'USER': '',
'PASSWORD': '',
'HOST': '',
'PORT': '',
}
}
1
2
3
'postgresql_psycopg2',
'postgresql', 'mysql',
'sqlite3' or 'oracle'.
Creando Tablas
• Crea las tablas para todos los modelos de las apps instaladas
en el fichero seungs.py
• No actualiza esquemas si la tabla existe.
• Eliminar tabla y volver a ejecutar syncdb
Creando Tablas
$ python manage.py syncdb
• Crea las tablas para todos los modelos de las apps instaladas
en el fichero seungs.py
• No actualiza esquemas si la tabla existe.
• Eliminar tabla y volver a ejecutar syncdb
syncdb$ python manage.py syncdbCreating table auth_permissionCreating table auth_groupCreating table auth_userCreating table auth_messageCreating table django_content_typeCreating table django_sessionCreating table django_siteCreating table website_tweet
You just installed Django's auth system, which means you don't have any superusers defined.Would you like to create one now? (yes/no): yesUsername (Leave blank to use 'neo'): admin E-mail address: [email protected]: Password (again): Superuser created successfully.Installing index for auth.Permission modelInstalling index for auth.Message modelInstalling index for website.Tweet model
syncdb$ python manage.py syncdbCreating table auth_permissionCreating table auth_groupCreating table auth_userCreating table auth_messageCreating table django_content_typeCreating table django_sessionCreating table django_siteCreating table website_tweet
You just installed Django's auth system, which means you don't have any superusers defined.Would you like to create one now? (yes/no): yesUsername (Leave blank to use 'neo'): admin E-mail address: [email protected]: Password (again): Superuser created successfully.Installing index for auth.Permission modelInstalling index for auth.Message modelInstalling index for website.Tweet model
django.contrib.auth
¿Cuantos sistemas de Auten0cación habéis programado?
¿Alguno era mejor que el anterior? ;-‐)
contrib.auth puede ser el úl0mo :D
syncdb$ python manage.py syncdbCreating table auth_permissionCreating table auth_groupCreating table auth_userCreating table auth_messageCreating table django_content_typeCreating table django_sessionCreating table django_siteCreating table website_tweet
You just installed Django's auth system, which means you don't have any superusers defined.Would you like to create one now? (yes/no): yesUsername (Leave blank to use 'neo'): admin E-mail address: [email protected]: Password (again): Superuser created successfully.Installing index for auth.Permission modelInstalling index for auth.Message modelInstalling index for website.Tweet model
website.tweet
syncdb$ python manage.py syncdbCreating table auth_permissionCreating table auth_groupCreating table auth_userCreating table auth_messageCreating table django_content_typeCreating table django_sessionCreating table django_siteCreating table website_tweet
You just installed Django's auth system, which means you don't have any superusers defined.Would you like to create one now? (yes/no): yesUsername (Leave blank to use 'neo'): admin E-mail address: [email protected]: Password (again): Superuser created successfully.Installing index for auth.Permission modelInstalling index for auth.Message modelInstalling index for website.Tweet model
django.contrib.auth
BD Lista para usarse
BD Lista para usarse
Previo: Clases del ORM
ts = Publisher.objects.all()
Model
Manager
QuerySet
INSERT
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()
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)
UPDATE
UPDATE
>>> ...>>> p.id52>>> p.name = 'Apress Publishing'>>> p.save()
o.save()
1
UPDATE
>>> Publisher.objects.all().update(country='USA')2
>>> ...>>> p.id52>>> p.name = 'Apress Publishing'>>> p.save()
o.save()
queryset.update(...)
1
n
DELETE
DELETE
>>> ...>>> p.id52>>> p.delete()
o.delete()
1
DELETE
>>> ps = Publisher.objects.all()>>> ps.delete()
>>> ...>>> p.id52>>> p.delete()
o.delete()
queryset.delete()
1
n
SELECT de 1 resultado
SELECT de 1 resultado
>>> Publisher.objects.get(name="Apress")<Publisher: Apress>
.get(...)
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.
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.
SELECT de N resultados
SELECT de N resultados
>>> Publisher.objects.all()[<Publisher: Apress>, <Publisher: O'Reilly>]
.all()
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(...)
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(...)
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, n
o
listas!
get(), filter() y exclude()
get(), filter() y exclude()
Modelo.objects.filter(campo1="valor1", campo2="valor2")
Los parámetros pueden indicar mucho más que igualdad (=)
get(), filter() y exclude()
Modelo.objects.filter(campo1="valor1", campo2="valor2")
Los parámetros pueden indicar mucho más que igualdad (=)
campo__exact=''
campo__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
ORDER BY
ORDER BY
>>> Publisher.objects.order_by("name")[<Publisher: Apress>, <Publisher: O'Reilly>]
.order_by(...)
ORDER BY
>>> Publisher.objects.order_by("name")[<Publisher: Apress>, <Publisher: O'Reilly>]
.order_by(...)
>>> Publisher.objects.order_by("-name")[<Publisher: O'Reilly>, <Publisher: Apress>]
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úl0ples campos:
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úl0ples campos:
¡También
devuelve
QuerySets!
Slicing
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>]
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
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
Related Objects
Related ObjectsOneToOneField
class Coche(models.Model): motor = OneToOneField(Motor)
class Motor(models.Model): ...
1
1
Related ObjectsOneToOneField
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
Related ObjectsOneToOneField
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
Related Objects
Related ObjectsForeignKeyField
class Blog(models.Model): ...
class Post(models.Model): blog = ForeignKeyField(Blog)
1
n
Related ObjectsForeignKeyField
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
Related Objects
Related ObjectsManyToManyField
class Post(models.Model): tags = ManyToManyField(Tag)
class Tag(models.Model): ...
n
m
Related ObjectsManyToManyField
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
Related Objects
Related ObjectsEn todas ellas podemos renombrar el puntero inverso
class Blog(models.Model): ...
class Post(models.Model): blog = ForeignKeyField(Blog, related_name='posts')
1
n
Related ObjectsEn 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
Related ObjectsEn 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
Y la guinda final: ¡Todo es LAZY!
Laziness
Laziness• Las consultas sólo se ejecutarán cuando realmente se necesite obtener los objetos. En las siguientes situaciones:
• Iteraciones
• 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'):
CRUD: Create, Retrieve, Update & Delete
django.contrib.admin
1
2
3
django.contrib.admin
1
2
3
django.contrib.admin
1
Django admin: Instalación
from django.conf.urls.defaults import *
# Uncomment the next two lines to enable the admin:# from django.contrib import admin# admin.autodiscover()
urlpatterns = patterns('',
...
# url(r'^admin/', include(admin.site.urls)),
...
)
1
2
urls.py
Django admin: Instalación
from django.conf.urls.defaults import *
# Uncomment the next two lines to enable the admin:from django.contrib import adminadmin.autodiscover()
urlpatterns = patterns('',
...
url(r'^admin/', include(admin.site.urls)),
...
)
1
2
urls.py
Django admin: Instalación
INSTALLED_APPS = ( 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.sites', 'django.contrib.admin', ...)
seungs.py
1
Actualizando la BD
Actualizando la BD
$ python manage.py syncdb
Creating table django_admin_log
Installing index for admin.LogEntry model
Admin lista para usar
¿Y nuestra app?
?
¿Y nuestra app?
admin.py• Cada app debe de tener el suyo.
• Define qué modelos serán visibles desde el admin y permite personalizar su aspecto.
from django.contrib import admin
from website.models import Tweet
class TweetAdmin(admin.ModelAdmin):
list_display = ('id','user','message','timestamp')
admin.site.register(Tweet, TweetAdmin)
1,2,3 Borrar la BD.... 1,2,3... Borrar la BD
Fixtures
Fixtures• Es muy aburrido crear juegos de datos cada vez que se elimina una tabla / BD.• No nos gustan las cosas aburridas.• Ficheros (json/xml/yaml) para inicializar una Tabla.• Pueden crearse una vez dispongamos de la información:
Fixtures• Es muy aburrido crear juegos de datos cada vez que se elimina una tabla / BD.• No nos gustan las cosas aburridas.• Ficheros (json/xml/yaml) para inicializar una Tabla.• Pueden crearse una vez dispongamos de la información:
python manage.py dumpdata <appName appName appName.model ...>
Fixtures• Es muy aburrido crear juegos de datos cada vez que se elimina una tabla / BD.• No nos gustan las cosas aburridas.• Ficheros (json/xml/yaml) para inicializar una Tabla.• Pueden crearse una vez dispongamos de la información:
python manage.py dumpdata <appName appName appName.model ...>
• Se cargan u0lizando:
python manage.py loaddata <fixture fixture ...>
• Si se llaman ini<al_data y están dentro de la carpeta fixtures de la app, se cargan al ahcer el syncdb.
Formularios
Clases involucradas
Clases involucradas
Widget Componente visual equivalente a HTMLTextInput
CheckboxInput
<input type='text'...>
<input type='checkbox'...>
Clases involucradas
Widget Componente visual equivalente a HTMLTextInput
CheckboxInput
<input type='text'...>
<input type='checkbox'...>
Field Lógica de un campo, asociado a un WidgetEmailField
IPAddressFieldwidget, initial, error, ...
Clases involucradas
Widget Componente visual equivalente a HTMLTextInput
CheckboxInput
<input type='text'...>
<input type='checkbox'...>
Field Lógica de un campo, asociado a un WidgetEmailField
IPAddressFieldwidget, initial, error, ...
Form Conjunto de Fields de un formularioContactForm [nombre, email, telefono, mensaje, ...]
Fields
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
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
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
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
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
Pa_ern
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
Pa_ern
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
Pa_ern
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>:
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>:
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:
Forms a par0r de Models: El COLMO del DRY
Forms a par-r de Modelsfrom 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
Magia avanzada
ROSA
NUNCA
ROSA
NUNCAINFRAVALORÉIS
ROSA
NUNCAINFRAVALORÉIS
EL PODER
ROSA
NUNCAINFRAVALORÉIS
EL PODERDE UN PONYROSA
Views avanzadasGeneric 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 = patterns('', url(r'^foo/$', views.foobar_view, {'template_name': 'template1.html'}), url(r'^bar/$', views.foobar_view, {'template_name': 'template2.html'}),)
Las tuplas de pa>erns() pueden tener 3 elementos
Views avanzadas
Renderiza directamente la template indicada
from django.conf.urls.defaults import *from django.views.generic.simple import direct_to_template
urlpatterns = patterns('', url(r'^about/$', direct_to_template, {'template': 'about.html'}))
from django.views.generic.simple import direct_to_template
Es la Generic View más simple y más u+lizada
Template LibraryNos permite extender el sistema de templates
de Django con Filters y Tags propios
Template LibraryNos permite extender el sistema de templates
de Django con Filters y Tags propios
Uso
{% load milibreria %}
...
{{ variable|mifiltro:"param" }}
...
{% mitag param1 param2 %}
Template LibraryNos permite extender el sistema de templates
de Django con Filters y Tags propios
Uso
{% load milibreria %}
...
{{ variable|mifiltro:"param" }}
...
{% mitag param1 param2 %}
Creación
Custom FiltersUn Filter es una función Python que:
• Recibe 1 o 2 argumentos: (value [, arg]).
• Siempre devuelve algo: el resultado, value o "".
• Falla silenciosamente: no lanza excepciones.
Custom FiltersUn Filter es una función Python que:
• Recibe 1 o 2 argumentos: (value [, arg]).
• Siempre devuelve algo: el resultado, value o "".
• Falla silenciosamente: no lanza excepciones.
from django import template
register = template.Library()
def cut(value, arg=' '): return value.replace(arg, '') register.filter('cut', cut)
Ejemplo
Custom FiltersUn Filter es una función Python que:
• Recibe 1 o 2 argumentos: (value [, arg]).
• Siempre devuelve algo: el resultado, value o "".
• Falla silenciosamente: no lanza excepciones.
from django import template
register = template.Library()
@register.filter(name='cut')def cut(value, arg=' '): return value.replace(arg, '')
Python
2.4 se hizo
sexy
Custom FiltersUn Filter es una función Python que:
• Recibe 1 o 2 argumentos: (value [, arg]).
• Siempre devuelve algo: el resultado, value o "".
• Falla silenciosamente: no lanza excepciones.
from django import template
register = template.Library()
@register.filter(name='cut')def cut(value, arg=' '): return value.replace(arg, '')
Custom TagsEl 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
SimpleTagsEjemplo: Devolver la hora actual formateada.
{% current_time "%Y-%m-%d %I:%M %p" %}
SimpleTagsEjemplo: Devolver la hora actual formateada.
{% current_time "%Y-%m-%d %I:%M %p" %}
from django import template
register = template.Library()
@register.simple_tagdef current_time(format): try: return datetime.datetime.now().strftime(str(format)) except UnicodeEncodeError: return ''
InclusionTagsEjemplo: Mostar anuncios si el usuario no es premium.
{% show_adverts user %}
{% for advert in adverts %} <img src='{{ advert.image }}' />{% endfor %}
adverts.html
milibreria.py
InclusionTagsEjemplo: 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
MiddlewareNos permite escribir funcionalidad reu0lizable que se inserta en el flujo de ejecución de Django
Middlewareclass MyMiddleware(object):
def process_request(self, request): """Se ejecuta antes de que Django decida a qué View llamar. -> HttpRequest(): Se corta el flujo de middleware. -> None: El flujo sigue con el siguiente middleware.""" # ... def process_view(self, request, view_func, view_args, view_kwargs): """Se ejecuta antes de que se llame a la View. -> HttpRequest(): Se corta el flujo de middleware. -> None: El flujo sigue con el siguiente middleware.""" # ...
def process_response(self, request, response): """Se ejecuta después de que la View devuelva una response. -> HttpResponse()""" # ...
def process_exception(self, request, exception): """Se ejecuta cuando una View lanza una excepción. -> HttpResponse(). -> None: La excepción se propaga hasta el cliente.""" # ...
MiddlewareTenemos que incluir nuestro middleware en el lugar que nos convenga, teniendo en cuenta el orden de
ejecución en la Request y en la Response:
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
)
Middleware1. Sistema de BETA
1. Nos aseguramos de controlar todas páginas.
2. Si el usuario +ene una IP o un User o...
2. Si6o en Mantenimiento
1. Todo el Site muestra un splash excepto...
3. Cache Middleware
1. Si la vista cumple un patrón (User no logeado,...)
cacheamos la página.
4. etc...
Ofrece integración con la librería GNU ge>ext 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
Internacionalización
• ¿Cómo indicar qué strings deben ser traducidos?
• Ges+ón cómoda de singulares y plurales
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
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
caching
•Si queremos escalar nuestro proyecto rápidamente.... Cache!
•Recomendado = memcached
•Acceder a la BD es caro, muy caro.
•El Hardware es “gra0s” en comparación con op0mizar código op0mizado.
•Ejemplo (Facebook):
caching
•Si queremos escalar nuestro proyecto rápidamente.... Cache!
•Recomendado = memcached
•Acceder a la BD es caro, muy caro.
•El Hardware es “gra0s” en comparación con op0mizar código op0mizado.
•Ejemplo (Facebook):
300+Tb Memcached
caching
from django.views.decorators.cache import cache_page
@cache_page(60 * 15)def my_view(request): ...
views
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
caching
low level
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 0po de objeto que se pueda serializar.
• QuerySets• Listas• ...
Deploying Django
1. h_p://virtualenv.openplans.org/
2. h_p://pip.openplans.org/
Deploying Django
Virtualenv + PIP 1. h_p://virtualenv.openplans.org/
2. h_p://pip.openplans.org/
Virtualenv
•Independencia completa de las librerías del sitema.
•Cada proyecto 0ene su juego de librerías en la versión que necesita•Sin miedo a actualizar
•Sin miedo a migrar
•etc...
Virtualenv
•Independencia completa de las librerías del sitema.
•Cada proyecto 0ene su juego de librerías en la versión que necesita•Sin miedo a actualizar
•Sin miedo a migrar
•etc...
$ virtualenv mi_entorno
crear
Virtualenv
•Independencia completa de las librerías del sitema.
•Cada proyecto 0ene su juego de librerías en la versión que necesita•Sin miedo a actualizar
•Sin miedo a migrar
•etc...
$ virtualenv mi_entorno
crear
$ source mi_entorno/bin/activate
ac-var
PIP
•Gestor de paquetes del siglo 21 :D•Permite especificar un fichero de REQUIREMENTS con un listado de paquetes a instalar.
PIP
•Gestor de paquetes del siglo 21 :D•Permite especificar un fichero de REQUIREMENTS con un listado de paquetes a instalar.
Django==1.4psycopg2feedparser==4.1stripogram==1.5GChartWrapper==0.8
pip install -E mi_entorno -r REQUIREMENTS
El Stack
nginx + Gunicorn
nginx
gunicorn
• nginx [engine x] is a HTTP and reverse proxy server.• Con una configuración muy sencilla podremos u0lizarlo como proxy inverso a gunicorn.
• hSp://gunicorn.org/
• Servidor Web WSGI implementado en Python• Facilidades de puesta en marcha de proyectos django• Fácilmente configurable usando nginx• hSp://nginx.org/
nginx :80
gunicorn
Django
WSGI Server
Frontend
Deploysencillo
worker 1 worker 2 worker n
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
Deployno tan sencillo
Fabric
Repe00on leads to boredom,boredom to horrifying mistakes,horrifying mistakes to God-‐I-‐wish-‐I-‐was-‐s0ll-‐bored.
“
$ fab deploy -R test
$ fab deploy -R www
Magia avanzada
1. Views avanzadas
2. Context Processors
3. Custom Template Filters & Tags
4.Middleware
5. Internacionalización
6. Caching
7. Despliegue
8. Apps recomendadas
Apps
django-‐south
django-‐south
• Sistema inteligente para realizar de manera automá0ca migraciones de esquemas.
•¿Que sucede si tengo un Modelo con 100.000 filas y quiero añadir una columna? ... south!
•Necesito migrar el contenido desde mi an0guo Modelo a uno nuevo... south!
•Necesito que ... south!
hSp://south.aeracode.org/
django-‐south
$ python manage.py schemamigration website --initial
crear primer schema
$ python manage.py schemamigration website --auto
crear 2-‐* migración
$ python manage.py migrate
aplicar migraciones
django-‐southhSp://south.aeracode.org/
$ python manage.py schemamigration website --initial
crear primer schema
$ python manage.py schemamigration website --auto
crear 2-‐* migración
$ python manage.py migrate
aplicar migraciones
django-‐haystack
h>p://haystacksearch.org
django-‐haystack
• “EL” Sistema de búsquedas para Django
• Funciona con varios sistemas de Indexación
• Solr, Xapian, Whoosh
• Features:
• ‘More like this’
•Face0ng
•Highligh0ng
• Spelling Sugges0on
• etc...
h>p://haystacksearch.org
django-‐registra-on
h>p://bitbucket.org/ubernostrum/django-‐registra-on/
django-‐registra-on
•Sistema completo para la ges0ón de usuarios.
•Desde el registro, ac0vación etc...
•DRY!!
•Instalación muy sencilla.
h>p://bitbucket.org/ubernostrum/django-‐registra-on/
django-‐registra-on
h>p://bitbucket.org/ubernostrum/django-‐registra-on/
django-‐registra-on/ac0vate/complete//ac0vate/<ac0va0on_key>// register// register/complete// register/closed// login// logout// password/change// password/change/done// password/reset// password/reset/confirm/<token>/ password/reset/complete// password/reset/done// reac0vate/
h>p://bitbucket.org/ubernostrum/django-‐registra-on/
django-‐debug-‐toolbar
h>p://github.com/robhudson/django-‐debug-‐toolbar
Celery
h>p://celeryproject.org
•Sistema de Tareas Asíncronas distribuidas.
•Features: Colas, Concurrencia, Distribuido...
•Muy fácil implementación y escalable.
•Casos prác-cos:
•Enviar un email
•Calcular el karma de de los usuarios del sistema.
•Tareas programadas (Limpieza, Post-‐procesado, etc...)
Celery
h>p://celeryproject.org
from celery.decorators import task
@taskdef add(x, y): return x + y
>>> result = add.delay(4, 4)>>> result.wait() # wait for and return the result8
Celery
h>p://celeryproject.org
from celery.decorators import task
@taskdef add(x, y): return x + y
>>> result = add.delay(4, 4)>>> result.wait() # wait for and return the result8
• Las Task son simples funciones (O class si queremos)
• Python 100% el retorno será el resultado
• Usamos el decorador @task para registrarla
• El método .delay sobre cualquier Task lo
ejecuta en background.
• Podemos esperar a que un Worker ejecute
la tarea o seguir haciendo otras acciones.
Celery
h>p://celeryproject.org
Sublime Text 2
h>p://www.sublimetext.com/2
Pycharm
h>p://www.jetbrains.com/pycharm
La punta del iceberg
h>p://www.djangobook.com
How to ... using Django?