Django: Disfruta programando.

Post on 18-Dec-2014

11.983 views 1 download

description

Curso de Python y Django impartido con Jaime Irurzun en los cursos de verano del e-ghost en la Universidad de Deusto, septiembre 2010.

Transcript of Django: Disfruta programando.

Disfruta  programando.

Jorge  Bas4da  [neo]neo2001@gmail.com

Jaime  Irurzun  [etox]  jaime.irurzun@gmail.com

@jorgebas4da @jaimeirurzun

Disfruta  programando.

Í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

Í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

• Legible

• Produc/vo

• Portable

• Extenso

• Integrable

• ...  y  Diver/do

Sintaxis  intui4va  y  estricta

Entre  1/3  y  1/5  más  conciso  que  Java  o  C++

GNU/Linux,  Windows,  Mac  OS  X,  ...

Standard  Library,  Third  par4es

C,  C++,  Java,  .NET,  COM,  WS,  CORBA,  ...

Instalación

$ sudo apt-get install python

http://www.python.org/download/

Snow  Leopard  incluye  las  versiones  2.5.4  y  2.6.1

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  Interac4vo

$ python holamundo.py hola mundo!$

Modo  Batch

#!/usr/bin/env pythonprint "hola mundo!"

holamundo.py

Í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

Tipos  de  datos

+  info:  h\p://docs.python.org/library/stdtypes.html

object

Tipos  de  datos

+  info:  h\p://docs.python.org/library/stdtypes.html

object

1234 3.1415int float35Llong

Tipos  de  datos

+  info:  h\p://docs.python.org/library/stdtypes.html

object

1234 3.1415int float35Llong

True Falsebool

Tipos  de  datos

+  info:  h\p://docs.python.org/library/stdtypes.html

object

1234 3.1415int float35Llong

True Falsebool

'spam' "guido's" """n lines"""str

Tipos  de  datos

+  info:  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

+  info:  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

+  info:  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

+  info:  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!

Í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

Operadores

+  info:  h\p://docs.python.org/library/operator.html

Operadores

+  info:  h\p://docs.python.org/library/operator.html

numéricosa + b a - b a * b a / b

a % b -a +a a ** b

Operadores

+  info:  h\p://docs.python.org/library/operator.html

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

Operadores

+  info:  h\p://docs.python.org/library/operator.html

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

Í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

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

>>> nums.count()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

>>> user.has_key('nick')True

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

>>> user['age']24

>>> user.get('age', 20)24

>>> user.has_key('nick')True

>>> 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'

sound/ __init__.py formats/ __init__.py wavread.py wavwrite.py aiffread.py aiffwrite.py auread.py auwrite.py ... effects/ __init__.py echo.py surround.py reverse.py ... filters/ __init__.py equalizer.py vocoder.py karaoke.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  conNene  un  fichero  con  

nombre  __init__.py

sound/ __init__.py formats/ __init__.py wavread.py wavwrite.py aiffread.py aiffwrite.py auread.py auwrite.py ... effects/ __init__.py echo.py surround.py reverse.py ... filters/ __init__.py equalizer.py vocoder.py karaoke.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  conNene  un  fichero  con  

nombre  __init__.py

1

2

3

Módulos

En  la  lista  de  directorios  que  conNene  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.6/site-packages

/usr/lib/python2.6/

$ env | grep PYTHONPATH

Módulossound/ __init__.py formats/ __init__.py wavread.py wavwrite.py aiffread.py aiffwrite.py auread.py auwrite.py ... effects/ __init__.py echo.py surround.py reverse.py ... filters/ __init__.py equalizer.py vocoder.py karaoke.py ...

import sound.effects.echosound.effects.echo.echofilter(...)

Módulossound/ __init__.py formats/ __init__.py wavread.py wavwrite.py aiffread.py aiffwrite.py auread.py auwrite.py ... effects/ __init__.py echo.py surround.py reverse.py ... filters/ __init__.py equalizer.py vocoder.py karaoke.py ...

import sound.effects.echosound.effects.echo.echofilter(...)

from sound.effects import echoecho.echofilter(...)

Módulossound/ __init__.py formats/ __init__.py wavread.py wavwrite.py aiffread.py aiffwrite.py auread.py auwrite.py ... effects/ __init__.py echo.py surround.py reverse.py ... filters/ __init__.py equalizer.py vocoder.py karaoke.py ...

import sound.effects.echosound.effects.echo.echofilter(...)

from sound.effects import echoecho.echofilter(...)

from sound.effects.echo import echofilterechofilter(...)

Módulossound/ __init__.py formats/ __init__.py wavread.py wavwrite.py aiffread.py aiffwrite.py auread.py auwrite.py ... effects/ __init__.py echo.py surround.py reverse.py ... filters/ __init__.py equalizer.py vocoder.py karaoke.py ...

import sound.effects.echosound.effects.echo.echofilter(...)

from sound.effects import echoecho.echofilter(...)

from sound.effects.echo import echofilterechofilter(...)

from sound.effects.echo import *echofilter(...)

Módulossound/ __init__.py formats/ __init__.py wavread.py wavwrite.py aiffread.py aiffwrite.py auread.py auwrite.py ... effects/ __init__.py echo.py surround.py reverse.py ... filters/ __init__.py equalizer.py vocoder.py karaoke.py ...

import sound.effects.echosound.effects.echo.echofilter(...)

from sound.effects import echoecho.echofilter(...)

from sound.effects.echo import echofilterechofilter(...)

from sound.effects.echo import *echofilter(...)

from sound.effects import echo as revrev.echofilter(...)

Í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

{}Estructuras

{}Estructuras

>>> from __future__ import braces File "<stdin>", line 1 SyntaxError: not a chance

Identación

>>> from __future__ import braces File "<stdin>", line 1 SyntaxError: not a chance

4  Espacios  para  indicar  la  identaciónPEP 8

Identación

h\p://www.python.org/dev/peps/pep-­‐0008/

•  Guido  van  Rossum  (2001)

•  Recomendaciones  de  esNlo

•  “Readability  counts”

•  “Code  is  read  much  more  oZen  than  it  is  wri\en.”

•  Muy  recomendable  importante  seguirlo.

PEP 8¿PEP  8?

def my_first_function(p1, p2): return "Hello World!"

Funciones

def my_first_function(p1, p2): return "Hello World!"

1

Funciones

def my_first_function(p1, p2): return "Hello World!"

12

Funciones

def my_first_function(p1, p2): return "Hello World!"

12

3

Funciones

def my_first_function(p1, p2): return "Hello World!"

Recomendaciones:•  Minúsculas•  Palabras  separadas  por  _•  Evitar  camelCase

12

3

PEP 8

Funciones

Conversión  de  /pos

+info:  h\p://docs.python.org/library/func4ons.html

Conversión  de  /pos

+info:  h\p://docs.python.org/library/func4ons.html

>>> int(1.3)1

Conversión  de  /pos

>>> str(2)'2'

+info:  h\p://docs.python.org/library/func4ons.html

>>> int(1.3)1

Conversión  de  /pos

>>> str(2)'2'

+info:  h\p://docs.python.org/library/func4ons.html

>>> int(1.3)1

>>> float(1)1.0

Conversión  de  /pos

>>> str(2)'2'

+info:  h\p://docs.python.org/library/func4ons.html

>>> int(1.3)1

>>> float(1)1.0

>>> tuple([1,2,3])(1, 2, 3)

Conversión  de  /pos

>>> str(2)'2'

+info:  h\p://docs.python.org/library/func4ons.html

>>> int(1.3)1

>>> float(1)1.0

>>> list((1,2,3))[1, 2, 3]

>>> tuple([1,2,3])(1, 2, 3)

Funciones  comunes

+info:  h\p://docs.python.org/library/func4ons.html

Funciones  comunes

>>> len("Python Mola")11>>> len([1,2,3,4])4

+info:  h\p://docs.python.org/library/func4ons.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]

+info:  h\p://docs.python.org/library/func4ons.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'>

+info:  h\p://docs.python.org/library/func4ons.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...

+info:  h\p://docs.python.org/library/func4ons.html

Funciones  interesantes

Son  sólo  un  ejemplo...

+info:  h\p://docs.python.org/library/func4ons.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...

+info:  h\p://docs.python.org/library/func4ons.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...

+info:  h\p://docs.python.org/library/func4ons.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...

+info:  h\p://docs.python.org/library/func4ons.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...

+info:  h\p://docs.python.org/library/func4ons.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)

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

Clases

s = Student("Jorge", 24)

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

Clases

s = Student("Jorge", 24)

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

Clases

s = Student("Jorge", 24)

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

Clases

s = Student("Jorge", 24)

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)

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

Recomendaciones:•  CamelCase

PEP 8

Clases

s = Student("Jorge", 24)

El  operador  ()

• Es  importante  diferenciar:

funcion      vs      funcion()

Clase              vs        Clase()

• El  operador  ()  permite:

• Invocar  funciones:

• Instanciar  clases:

resultado = funcion()

objeto = Clase("param1")

Í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

$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.

•  ProtoNpado...  UNlizado  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.

•  ProtoNpado...  UNlizado  por  grandes  empresas.

etc...

Conclusiones

Ejemplo  &  Ejercicio

Í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

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)

FilosoXa

•  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.”“

FilosoXa

•  Explicit  is  be\er  than  implicit.

•  Este  es  un  principio  de  Python.•  Django  no  debe  hacer  demasiada  “Magia”.

•  Si  algo  es  “Mágico”  ha  de  haber  una  buena  razón.

•  Consistencia•  Ha  de  ser  consistente  a  todos  los  niveles.

•  Eficiencia,  Seguridad,  Flexibilidad  y  Simplicidad.

h\p://docs.djangoproject.com/en/dev/misc/design-­‐philosophies/

FilosoXa

La  comunidad

La  comunidad

• django-­‐users

18.000  miembros

La  comunidad

• django-­‐users

18.000  miembros

• django-­‐developers

5.900  miembros

La  comunidad

• django-­‐users

18.000  miembros

• django-­‐developers

5.900  miembros

• djangoproject.com

500.000  visitas  únicas  mensuales

¿Quién  usa  Django?

etc...

¿Quién  usa  Django?

1.  Instalación  Python

$ sudo apt-get install python

http://www.python.org/download/

Snow  Leopard  incluye  las  versiones  2.5.4  y  2.6.1

Configurar  un  motor  de  Base  de  Datos:

•  Oficiales:  •  PostgreSQL•  MySQL

•  Oracle•  SQLite

•  Comunidad:  

•  Sybase  SQL  Anywhere•  IBM  DB2

•  MicrosoZ  SQL  Server  2005

•  Firebird•  ODBC

2.  Instalación  SGBD

Configurar  un  motor  de  Base  de  Datos:

•  Oficiales:  •  PostgreSQL•  MySQL

•  Oracle•  SQLite

•  Comunidad:  

•  Sybase  SQL  Anywhere•  IBM  DB2

•  MicrosoZ  SQL  Server  2005

•  Firebird•  ODBC

2.  Instalación  SGBD

•  Vamos  a  uNlizar  SQLite  por  comodidad

•  Desde  Python  2.5  podemos  uNlizar  sqlite    sin  instalar  nada.

2.  Instalación  SGBD

•  Vamos  a  uNlizar  SQLite  por  comodidad

•  Desde  Python  2.5  podemos  uNlizar  sqlite    sin  instalar  nada.

2.  Instalación  SGBD

A:  Paquetes  de  cada  distro

• apt-get install python-django

B:  Official  Release

• h\p://www.djangoproject.com/download/

• python setup.py install

C:  Trunk

• h\p://code.djangoproject.com/svn/django/trunk/

3.  Instalación  Django

All  Right?

All  Right?

>>> import django>>> django.VERSION(1, 1, 0, 'final', 0)

>>> import djangoTraceback (most recent call last): File "<stdin>", line 1, in <module>ImportError: No module named 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

4

1

Ficheros

Carpetas

¿Es  Django  tán  simple  y  fácil  de  usar?

Let’s  enjoy

Crear  nuestro  proyectode  4  ficheros  ;-­‐)

Crear  nuestro  proyecto

$ django-admin.py startproject dwitter

de  4  ficheros  ;-­‐)

Crear  nuestro  proyecto

$ django-admin.py startproject dwitter

__init__.py

manage.py

settings.py

urls.py

de  4  ficheros  ;-­‐)

Crear  nuestro  proyecto

$ django-admin.py startproject dwitter

-­‐  ¿Esto  es  un  proyecto...  ?      Si  os  ve  mi  jefe...

__init__.py

manage.py

settings.py

urls.py

de  4  ficheros  ;-­‐)

Crear  nuestro  proyecto

$ django-admin.py startproject dwitter

-­‐  ¿Esto  es  un  proyecto...  ?      Si  os  ve  mi  jefe...

__init__.py

manage.py

settings.py

urls.py

-­‐  Sí,  disponemos  de  un  proyecto  ‘funcional’  en  django.

de  4  ficheros  ;-­‐)

senngs.py

Arrancar  nuestro  proyectode  4  ficheros  ;-­‐)

Arrancar  nuestro  proyectode  4  ficheros  ;-­‐)

$ cd dwitter$ python manage.py runserver

Validating models...0 errors found

Django version 1.1, using settings 'dwitter.settings'Development server is running at http://127.0.0.1:8000/Quit the server with CONTROL-C.

Arrancar  nuestro  proyectode  4  ficheros  ;-­‐)

$ cd dwitter$ python manage.py runserver

Validating models...0 errors found

Django version 1.1, using settings 'dwitter.settings'Development server is running at http://127.0.0.1:8000/Quit the server with CONTROL-C.

Í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

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  pe4ciones  HTTP

• Se  definen  URLs  elegantes  mediante  expresiones  regulares  que  redirigen  a  funciones  de  views.py

urls.py

views.py

h\p://mysite.com/about/

html ...

¿urlpa\erns?

URLs  y  Vistas

• La  función  de  views.py  recibe  como  parámetros  un  objeto  

HhpRequest  y  todos  los  parámetros  de  la  URL  capturados,  

teniendo  que  devolver  siempre  un  objeto  HhpResponse

views.py

HhpRequest(),  ...

HhpResponse()

URLs  y  VistasEjemplo  1:    http://mysite.com/time

from django.conf.urls.defaults import *from mysite.views import hora_actual

urlpatterns = patterns('', (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('', (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('', (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

Í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

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  4pos  de  objetos:  Template()  y  Context().

• Un  objeto  Template()  con4ene  el  string  de  salida  que  queremos  devolver  en  el  H\pResponse  (normalmente  HTML),  pero  incluyendo  e4quetas  especiales  de  Django.

• Un  objeto  Context()  con4ene  un  diccionario  con  los  valores  que  dan  contexto  a  una  plan4lla,  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  obje4vo:  Template  +  Context

Templates• Segunda  aproximación  al  obje4vo:  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  obje4vo:  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  obje4vo:  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  obje4vo:  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',)

sezngs.py

Templates• Tercera  aproximación  al  obje4vo:  get_template()

TEMPLATE_DIRS = ( '/home/django/templates',)

sezngs.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  obje4vo:  get_template()

TEMPLATE_DIRS = ( '/home/django/templates',)

sezngs.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)

S4ll  

boring...

Templates• Obje4vo  alcanzado:  render_to_response()

from django.shortcuts import render_to_responsefrom datetime import datetime

def hora_actual(request): now = datetime.now() return render_to_response('hora.html', {'hora': now})

Templates• Obje4vo  alcanzado:  render_to_response()

from django.shortcuts import render_to_responsefrom datetime import datetime

def hora_actual(request): now = datetime.now() return render_to_response('hora.html', {'hora': now})

Boring...?

Templates• Obje4vo  alcanzado:  render_to_response()

from django.shortcuts import render_to_responsefrom datetime import datetime

def hora_actual(request): now = datetime.now() return render_to_response('hora.html', {'hora': now})

AWESOME!

Templates:  Tip

TEMPLATE_DIRS = ( '/home/django/templates',)

sezngs.pya)

Templates:  Tip

TEMPLATE_DIRS = ( '/home/django/templates',)

sezngs.py Reusable  

apps?a)

Templates:  Tip

TEMPLATE_DIRS = ( '/home/django/templates',)

sezngs.py Reusable  

apps?a)

b)

• La  carpeta  /templates  es  buscada  dentro  de  cada  app.

• Conviene  incluir  una  carpeta  con  el  nombre  de  la  app  por  claridad.

TEMPLATE_LOADERS = ( 'django.template.loaders.filesystem.load_template_source', 'django.template.loaders.app_directories.load_template_source',)

return render_to_response('website/index.html')

Alterna4va  reu4lizable:

¡Empieza  nuestro  primer  proyecto!

a) Crear  la  app  dwi\er.website.b) Incluir  la  app  en  senngs.py.c) Definir  URLs  en  urls.py:‣ user/<username>/status/<tweet_id>/‣ user/<username>/follow/‣ user/<username>/unfollow/‣ user/<username>/‣ search/‣ users/

d) Crear  una  vista  para  “/”  que  renderice  un  Nmeline  de  twi\er  en  una  template  index.html  a  parNr  de  datos  hardcodeados  en  un  diccionario.

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

FilosoXa  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

 

Tarea  1:  Tagsa) UNlizar  tags  para  que  el  Nmeline  se  muestre  con  el  siguiente  formato:• <username>:  <tweet>• <username>:  <tweet>• ...

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

{'url': 'Visitad http://www.djangoproject.com'}

{{ url|urlize }}urlize

Visitad <a href=”http://www.djangoproject.com”> http://www.djangoproject.com </a>

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>

Templates:  Filters{'lista': ['States', ['Kansas', ['Lawrence', 'Topeka'], 'Illinois']]}

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>

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

 

Tarea  2:  Filtersa) Añadir  a  cada  tweet  del  Nmeline  el  Nempo  transcurrido:• <username>:  <tweet>

<n>  seconds  ago• <username>:  <tweet>

<n>  minutes  ago• ...

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 %}

 

Tarea  3:  Tags  avanzadosa) Hacer  que  el  Nmeline  muestre  el  mensaje  “No  hay  tweets.”  si  el  diccionario  recibido  está  vacío.

extend  y  block

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 %}

 

Tarea  4:  Herencia  de  templatesa) Descargar  nuestra  template  base.html.b) Incluirla  en  vuestra  app.c) Hacer  que  vuestro  index.html  herede  de  base.html  y  exNenda  el  bloque  ‘content’  con  su  contenido.

Í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

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})

1

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

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

3

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

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

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-­‐RelaNonal  mapping)

ORM  (Object-­‐RelaNonal  mapping)

Ejemplo  ORM

def book_list(request):

names = Books.objects.all().order_by('name')

return render_to_response('book_list.html', {'names':names})

Ejemplo  ORM

def book_list(request):

names = Books.objects.all().order_by('name')

return render_to_response('book_list.html', {'names':names})

1

Ejemplo  ORM

def book_list(request):

names = Books.objects.all().order_by('name')

return render_to_response('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)

1

•  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

•  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

•  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

•  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

•  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

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

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;

¿Es  magia?  No.

•  Nombres  de  tablas  generados  automáNcamente.

•  <app_name>_lower(<model_name>)

•  id  como  Primary  Key  (Personalizable)

•  Las  Foreing  Key  terminan  en  _id  (Personalizable)

•  Los  Npos  de  datos  se  ajustan  en  función  del  SGBD

Configurar  sesngs.py

DATABASE_ENGINE = 'sqlite3'

DATABASE_NAME = 'db.sqlite'

DATABASE_USER = ''

DATABASE_PASSWORD = ''

DATABASE_HOST = ''

DATABASE_PORT = ''

Configurar  sesngs.py

DATABASE_ENGINE = 'sqlite3'

DATABASE_NAME = 'db.sqlite'

DATABASE_USER = ''

DATABASE_PASSWORD = ''

DATABASE_HOST = ''

DATABASE_PORT = ''

1

Configurar  sesngs.py

DATABASE_ENGINE = 'sqlite3'

DATABASE_NAME = 'db.sqlite'

DATABASE_USER = ''

DATABASE_PASSWORD = ''

DATABASE_HOST = ''

DATABASE_PORT = ''

1

2

Configurar  sesngs.py

DATABASE_ENGINE = 'sqlite3'

DATABASE_NAME = 'db.sqlite'

DATABASE_USER = ''

DATABASE_PASSWORD = ''

DATABASE_HOST = ''

DATABASE_PORT = ''

1

2

3

Creando  Tablas

•  Crea  las  tablas  para  todos  los  modelos  de  las  apps  instaladas  

en  el  fichero  senngs.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  senngs.py

•  No  actualiza  esquemas  si  la  tabla  existe.

•  Eliminar  tabla  y  volver  a  ejecutar  syncdb

Nuestro  primer  modelo

a)Crear  modelo  Tweetb)Configurar  senngs.pyc) Ver  el  SQL  generado  con  sqlall

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: user@example.comPassword: Password (again): Superuser created successfully.Installing index for auth.Permission modelInstalling index for auth.Message modelInstalling index for website.Tweet model

syncdb$ python manage.py syncdbCreating table auth_permissionCreating table auth_groupCreating table auth_userCreating table auth_messageCreating table django_content_typeCreating table django_sessionCreating table django_siteCreating table website_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: user@example.comPassword: 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  AutenNcación  habéis  programado?

¿Alguno  era  mejor  que  el  anterior?  ;-­‐)

contrib.auth  puede  ser  el  úlNmo  :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: user@example.comPassword: 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: user@example.comPassword: 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

Nuestro  primer  modelo

a)Hacer  syncdb

Previo:  Clases  del  ORM

ts = Publisher.objects.all()

Model

Manager

QuerySet

Previo:  __unicode__()

Previo:  __unicode__()>>> Publisher.objects.all()[<Publisher: Publisher object>]

Previo:  __unicode__()>>> Publisher.objects.all()[<Publisher: Publisher object>]

Previo:  __unicode__()>>> Publisher.objects.all()[<Publisher: Publisher object>]

Previo:  __unicode__()

class Publisher(models.Model): ... def __unicode__(self): return self.name

>>> Publisher.objects.all()[<Publisher: Publisher object>]

Previo:  __unicode__()

class Publisher(models.Model): ... def __unicode__(self): return self.name

>>> Publisher.objects.all()[<Publisher: Publisher object>]

>>> Publisher.objects.all()[<Publisher: Apress>]

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úlNples  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úlNples  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'):

Usando  el  ORM

a) Insertar  varios  Tweets  desde  la  shellb)Modificar  views.index  para  que  uNlice  los  Tweets  reales  de  la  BD

c) Implementar  URL  y  View  para  ofrecer  permalinks  a  los  tweets:‣ URL:    user/<username>/status/<tweet_id>

‣ View:    tweet_page

‣ Template:    tweet_page.html    (Bajar)

d)shortcut!:  get_object_or_404()

Profiles

Profile

•  Problema:  El  modelo  User  de  django.contrib.auth  no  puede  

contener  toda  la  información  que  necesitamos.

•  Username,  Password,  Name....  y  poco  más.

•  Solución:  Definir  un  Profile  (Un  Modelo  Agregado)  para  

guardar  esa  información.

Profilemodels.py

Profile

class Profile(models.Model): user = models.OneToOneField(User, unique=True)

models.py

Profile

class Profile(models.Model): user = models.OneToOneField(User, unique=True) bio = models.CharField(blank=True, max_length=200)

models.py

Profile

class Profile(models.Model): user = models.OneToOneField(User, unique=True) bio = models.CharField(blank=True, max_length=200) ...

models.py

Profile

class Profile(models.Model): user = models.OneToOneField(User, unique=True) bio = models.CharField(blank=True, max_length=200) ...

AUTH_PROFILE_MODULE = "website.Profile"

sesngs.py

models.py

Profile

class Profile(models.Model): user = models.OneToOneField(User, unique=True) bio = models.CharField(blank=True, max_length=200) ...

AUTH_PROFILE_MODULE = "website.Profile"

sesngs.py

models.py

•  Cada  objeto  User  de  django.contrib.auth  dispone  de  un  método  get_profile()  que  nos  permiNrá  acceder  al  Profile.

Profile

•Donde  tengamos  el  User  tendremos  el  Profile.•Donde  tengamos  el  Profile,  tendremos  el  User.

Profile

>>> from django.contrib.auth.models import User>>> u = User.objects.get(id=1)>>> type(u)<class 'django.contrib.auth.models.User'>

>>> profile = u.get_profile()>>> type(profile)<class 'website.models.Profile'>

•Donde  tengamos  el  User  tendremos  el  Profile.•Donde  tengamos  el  Profile,  tendremos  el  User.

1  User  =  1  Profile  ¿Cuándo  se  crea  un  User?

Signals

•  Django  incorpora  un  dispacher  de  señales  para  ayudar  a  crear  aplicaciones  reuNlizables.•  Permite  subscribirnos  a  “eventos”  a  lo  largo  de  todo  el  framework  y  actuar  frente  a  ellos.

•  Señales  interesantes:• pre_save, post_save• pre_delete, post_delete• m2m_changed• request_started, request_finished

h\p://docs.djangoproject.com/en/dev/ref/signals/

Signals

Signals

def profile_signal_callback(sender, **kwargs): if kwargs.get('created'): profile = Profile() profile.user = User.objects.get(id=kwargs.get('instance').id) profile.save()

from django.db.models.signals import post_save

post_save.connect(profile_signal_callback, sender=User, dispatch_uid="users-profilecreation-signal")

1

Signals

def profile_signal_callback(sender, **kwargs): if kwargs.get('created'): profile = Profile() profile.user = User.objects.get(id=kwargs.get('instance').id) profile.save()

from django.db.models.signals import post_save

post_save.connect(profile_signal_callback, sender=User, dispatch_uid="users-profilecreation-signal")

1

2

Signals

def profile_signal_callback(sender, **kwargs): if kwargs.get('created'): profile = Profile() profile.user = User.objects.get(id=kwargs.get('instance').id) profile.save()

from django.db.models.signals import post_save

post_save.connect(profile_signal_callback, sender=User, dispatch_uid="users-profilecreation-signal")

1

2

3

Signals

def profile_signal_callback(sender, **kwargs): if kwargs.get('created'): profile = Profile() profile.user = User.objects.get(id=kwargs.get('instance').id) profile.save()

from django.db.models.signals import post_save

post_save.connect(profile_signal_callback, sender=User, dispatch_uid="users-profilecreation-signal")

1

2

3

4

Signals

def profile_signal_callback(sender, **kwargs): if kwargs.get('created'): profile = Profile() profile.user = User.objects.get(id=kwargs.get('instance').id) profile.save()

from django.db.models.signals import post_save

post_save.connect(profile_signal_callback, sender=User, dispatch_uid="users-profilecreation-signal")

1

2

3

4

Puede  estar  en  cualquier  app  de  nuestro  proyecto.

Se  recomienda  models.py

Users  en  dwi\er

a)Crear  el  modelo  Profileb)Crear  trigger  de  agregación  con  User  mediante  signals

c) Eliminar  BDd)Hacer  syncdb

Followers

Profilemodels.py

Profile

class Profile(models.Model): user = models.OneToOneField(User, unique=True) bio = models.CharField(blank=True, max_length=200)

models.py

Profile

class Profile(models.Model): user = models.OneToOneField(User, unique=True) bio = models.CharField(blank=True, max_length=200) followers = models.ManyToManyField("self", blank=True,

models.py

Profile

class Profile(models.Model): user = models.OneToOneField(User, unique=True) bio = models.CharField(blank=True, max_length=200) followers = models.ManyToManyField("self", blank=True, symmetrical=False,

models.py

Profile

class Profile(models.Model): user = models.OneToOneField(User, unique=True) bio = models.CharField(blank=True, max_length=200) followers = models.ManyToManyField("self", blank=True, symmetrical=False, related_name="following")

models.py

Profile

class Profile(models.Model): user = models.OneToOneField(User, unique=True) 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  N,  tú  me  sigues  a  mi.

•  related_name  (en  este  caso)•  Limpieza  y  evitar  profile_set

Users  en  dwi\er

a)Añadir  ManyToMany  para  los  followersb)Eliminar  BD  c) Hacer  syncdb

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  uNlizando:

python manage.py loaddata <fixture fixture ...>

•  Si  se  llaman  iniAal_data  y  están  dentro  de  la  carpeta  fixtures  de  la  app,  se  cargan  al  ahcer  el  syncdb.

El  poder  de  los  fixtures

a)Crear  la  carpeta  website/fixturesb)Descargar  iniNal_data.json  y  meterlo  en  la  carpeta  fixtures

c) Hacer  syncdbd)Implementar  URL  y  View  para  ofrecer  páginas  de  usuario:‣ URL:    user/<username>/

‣ View:    user_page

‣ Template:    user_page.html    (Bajar)

Í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

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('',

...

# (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('',

...

(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', ...)

sezngs.py

Django  admin:  Instalación

INSTALLED_APPS = ( 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.sites', 'django.contrib.admin', ...)

sezngs.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)

Instalar  Admin

a)Configurar  urls.pyb)Configurar  senngs.pyc) Hacer  syncdbd)Comprobar  que  no  está  Tweete)Añadir  admin.pyf) Probar  Administración

Í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

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

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_to_response

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_to_response('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_to_response

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_to_response('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_to_response

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_to_response('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_to_response

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_to_response('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  parNr  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

Primer  Form  en  dwi\er

a)Crear  un  Form  que  permita  publicar  tweets  desde  index.html  al  usuario  que  esté  logueado  desde  django.contrib.admin  (no  tenemos  login  propio).

Í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

Magia  avanzada

Magia  avanzada

1. Context  Processors

2.Middleware

3. Caching

4. Deploying  Django

5. Apps  recomendadas

Magia  avanzada

1. Context  Processors

2.Middleware

3. Caching

4. Deploying  Django

5. Apps  recomendadas

Context  ProcessorsProblema

!

! ! !

!

!

!

!

Context  ProcessorsSolución:  el  objeto  RequestContext()

c = RequestContext(request, {'tweets': tweets})

• Sus4tuye  a  Context().

• Recibe  un  H\pRequest()  antes  del  diccionario.

• Automá4camente  alimenta  nuestro  diccionario  con  todos  

los  diccionarios  devueltos  por  los  Context  Processors  que  

tengamos  habilitados.

Context  Processors¿Context  Processors?  Son  funciones.

• Reciben  un  H\pRequest()  como  único  parámetro.

• Devuelven  un  diccionario  para  ser  usado  como  Context().

Context  Processors¿Context  Processors?  Son  funciones.

def ip_address_processor(request): return {'ip_address': request.META['REMOTE_ADDR']}

• Reciben  un  H\pRequest()  como  único  parámetro.

• Devuelven  un  diccionario  para  ser  usado  como  Context().

Context  Processors¿Context  Processors?  Son  funciones.

def ip_address_processor(request): return {'ip_address': request.META['REMOTE_ADDR']}

• Reciben  un  H\pRequest()  como  único  parámetro.

• Devuelven  un  diccionario  para  ser  usado  como  Context().

TEMPLATE_CONTEXT_PROCESSORS = ( "django.contrib.auth.context_processors.auth", "django.core.context_processors.debug", "django.core.context_processors.i18n", "django.core.context_processors.media", "django.contrib.messages.context_processors.messages", "website.context_processors.ip_address_processor",)

Context  Processors¿Qué  ocurre  con  render_to_response()?

def some_view(request):

# ...

return render_to_response('my_template.html',

my_data_dictionary,

context_instance=RequestContext(request))

Context  Processors¿Qué  ocurre  con  render_to_response()?

def some_view(request):

# ...

return render_to_response('my_template.html',

my_data_dictionary,

context_instance=RequestContext(request))

Context  Processors¿Qué  ocurre  con  render_to_response()?

def some_view(request):

# ...

return render_to_response('my_template.html',

my_data_dictionary,

context_instance=RequestContext(request))

from django.shortcuts import render_to_responsefrom django.template import RequestContext

def render_response(req, *args, **kwargs): kwargs['context_instance'] = RequestContext(req) return render_to_response(*args, **kwargs)

Consejo

Magia  avanzada

1. Context  Processors

2.Middleware

3. Caching

4. Deploying  Django

5. Apps  recomendadas

MiddlewareNos  permite  escribir  funcionalidad  reu4lizable  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',

)

Magia  avanzada

1. Context  Processors

2.Middleware

3. Caching

4. Deploying  Django

5. Apps  recomendadas

caching

•Si  queremos  escalar  nuestro  proyecto  rápidamente....  Cache!

•Recomendado  =  memcached

•Acceder  a  la  BD  es  caro,  muy  caro.

•El  Hardware  es  “gra4s”  en  comparación  con  op4mizar  código  op4mizado.

•Ejemplo  (Facebook):

caching

•Si  queremos  escalar  nuestro  proyecto  rápidamente....  Cache!

•Recomendado  =  memcached

•Acceder  a  la  BD  es  caro,  muy  caro.

•El  Hardware  es  “gra4s”  en  comparación  con  op4mizar  código  op4mizado.

•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  4po  de  objeto  que  se  pueda  serializar.

•  QuerySets•  Listas•  ...

memcached  DEMO

Magia  avanzada

1. Context  Processors

2.Middleware

3. Caching

4. Deploying  Django

5. Apps  recomendadas

Deploying  Django

Deploying  Django

Virtualenv  +  PIP  +  Fabric

Virtualenv

•Independencia  completa  de  las  librerías  del  sitema.

•Cada  proyecto  4ene  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  4ene  su  juego  de  librerías  en  la  versión  que  necesita•Sin  miedo  a  actualizar

•Sin  miedo  a  migrar

•etc...

$ virtualenv --no-site-packages mi_entorno

crear

Virtualenv

•Independencia  completa  de  las  librerías  del  sitema.

•Cada  proyecto  4ene  su  juego  de  librerías  en  la  versión  que  necesita•Sin  miedo  a  actualizar

•Sin  miedo  a  migrar

•etc...

$ virtualenv --no-site-packages 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.2.1psycopg2feedparser==4.1stripogram==1.5GChartWrapper==0.8

pip install -E mi_entorno -r REQUIREMENTS

Fabric

Repetition leads to boredom, boredom to horrifying mistakes, horrifying mistakes to God-I-wish-I-was-still-bored“

Fabric

env.user = "example"env.hosts = ["example.com"]def deploy(): run('svn up /home/example/') sudo('/etc/init.d/lighttpd restart')

fabfile.py

Repetition leads to boredom, boredom to horrifying mistakes, horrifying mistakes to God-I-wish-I-was-still-bored“

Fabric

env.user = "example"env.hosts = ["example.com"]def deploy(): run('svn up /home/example/') sudo('/etc/init.d/lighttpd restart')

fabfile.py

fabric deploy

uso

Repetition leads to boredom, boredom to horrifying mistakes, horrifying mistakes to God-I-wish-I-was-still-bored“

Magia  avanzada

1. Context  Processors

2.Middleware

3. Caching

4. Deploying  Django

5. Apps  recomendadas

Apps

django-­‐registra/on

h\p://bitbucket.org/ubernostrum/django-­‐registra4on/

django-­‐registra/on

h\p://bitbucket.org/ubernostrum/django-­‐registra4on/

•Sistema  completo  para  la  ges4ón  de  usuarios.

•Desde  el  registro,  ac4vación  etc...

•DRY!!

•Instalación  muy  sencilla.

•Recomedado  ++

django-­‐registra/on

h\p://bitbucket.org/ubernostrum/django-­‐registra4on/

django-­‐registra/on

h\p://bitbucket.org/ubernostrum/django-­‐registra4on/

/ac4vate/complete//ac4vate/<ac4va4on_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//  reac4vate/

django-­‐socialregistra/on

h\p://github.com/flashingpumpkin/django-­‐socialregistra4on

django-­‐socialregistra/on

h\p://github.com/flashingpumpkin/django-­‐socialregistra4on

•Configuración  sencilla

•Auten4cación  con:

•twi\er,  facebook,  oauth,  openid

•Integración  perfecta  con  contrib.auth

dajaxproject

h\p://dajaxproject.com

•Comunicación  AJAX  muy  sencilla

•CrossBrowsing

•Muy  ú4l  si  no  sabemos  demasiado  JS

django-­‐locale-­‐url

h\p://code.google.com/p/django-­‐localeurl/

django-­‐locale-­‐url

h\p://code.google.com/p/django-­‐localeurl/

•  Nos  permite  especificar  el  idioma  en  la  url

www.example.com/en/

www.example.com/es/

• Mejoras  en  el  SEO

• Cada  página  4ene  una  única  url.

• Configuración  no  tan  sencilla,  pero  interesante.

django-­‐piston

h\p://bitbucket.org/jespern/django-­‐piston/wiki/Home

django-­‐piston

h\p://bitbucket.org/jespern/django-­‐piston/wiki/Home

•  Framework  para  crear  APIs  RESTful

•  Muy  fácil  instalación

•  Serialización  a:

•JSON,  YAML,  Python  Pyckle,  XML  ...

•OAuth

•Recomendado  +++++

django-­‐sentry

h\p://github.com/dcramer/django-­‐sentry

django-­‐sentry

h\p://github.com/dcramer/django-­‐sentry

django-­‐debug-­‐toolbar

h\p://github.com/robhudson/django-­‐debug-­‐toolbar

django-­‐command-­‐extensions

h\p://code.google.com/p/django-­‐command-­‐extensions/

django-­‐command-­‐extensions

h\p://code.google.com/p/django-­‐command-­‐extensions/

•Extensión  para  “manage.py”

•Muchas  u4lidades  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.

django-­‐command-­‐extensions

django-­‐command-­‐extensions

django-­‐command-­‐extensions

django-­‐command-­‐extensions

Textmate  +  Django

h\ps://bitbucket.org/bkerr/django-­‐textmate-­‐bundles

Textmate  +  Django

h\ps://bitbucket.org/bkerr/django-­‐textmate-­‐bundles

•Shortcuts  para  crear:•Modelos

•Fields•Filters•TemplateTags

•Forms

•Admin

Durante  el  curso  lo  hemos  u4lizado.

La  punta  del  iceberg

h\p://www.djangobook.com/

Disfruta  programando.

Jorge  Bas4da  [neo]neo2001@gmail.com

Jaime  Irurzun  [etox]  jaime.irurzun@gmail.com

@jorgebas4da @jaimeirurzun