Taller Django: de 0 a CRUD - Miguel González (@migonzalvar) GDG Vigo, 5 de abril de 2013

Página creada Federica Maura
 
SEGUIR LEYENDO
Taller Django: de 0 a CRUD - Miguel González (@migonzalvar) GDG Vigo, 5 de abril de 2013
Taller Django: de 0 a CRUD
     Miguel González (@migonzalvar)

      GDG Vigo, 5 de abril de 2013
Taller Django: de 0 a CRUD - Miguel González (@migonzalvar) GDG Vigo, 5 de abril de 2013
Crear un proyecto de Django

Urls y vistas

Modelos

Plantillas

Baterías incluidas: administración

Formularios

Edición de objetos

Autenticación
Taller Django: de 0 a CRUD - Miguel González (@migonzalvar) GDG Vigo, 5 de abril de 2013
Este obra está bajo una licencia de Creative Commons
Reconocimiento 3.0 España.
Taller Django: de 0 a CRUD - Miguel González (@migonzalvar) GDG Vigo, 5 de abril de 2013
Taller Django: de 0 a CRUD - Miguel González (@migonzalvar) GDG Vigo, 5 de abril de 2013
Información de interés

  • Contraseña WiFi
  • Repositorio: https:
    //code.google.com/p/gdg-vigo-django-crud/
  • Documentación:
    https://docs.djangoproject.com/en/1.5/
  • Back channel: #gdgvigo
Taller Django: de 0 a CRUD - Miguel González (@migonzalvar) GDG Vigo, 5 de abril de 2013
Prerrequisitos
   • Versión de Pyhton correcta
     $ python --version
     Python 2.7.3
   • Virtualenv instalado
     $ virtualenv --version
     1.9.1
   • Clonado el repositorio (opcional)
     $ git clone \
     > https://code.google.com/p/gdg-vigo-django-crud/
     $ cd gdg-vigo-django-crud
Crear un proyecto de Django
Conceptos

  • 3 niveles de carpeta:
      • Proyecto = repositorio
      • Proyecto Django
      • Aplicaciones

  • Entorno virtual: aislar dependencias
E1: Preparación del entorno

   1.   Crea una carpeta para trabajar con el proyecto, por
        ejemplo gdg-vigo-django-crud. (Si has clonado el
        repositorio, se trata de la carpeta raíz) Pista: mkdir.
   2.   Crea un entorno virtual dentro de la carpeta principal del
        proyecto. Un buen nombre para la carpeta puede ser
        .venv. Pista: virtualenv.
   3.   Instala Django dentro del entorno virtual recién creado.
        Pistas: source, pip.
Solución E1

   1.   Crear carpeta para el proyecto
        $ mkdir gdg-vigo-django-crud
        $ cd gdg-vigo-django-crud
   2.   Crear entorno virtual de Python
        $ virtualenv .venv --distribute
   3.   Instalar Django dentro del entorno virtual
        $ source .venv/bin/activate
        $ pip install Django
E2: Inicialización de un proyecto
Django

   1.   Inicializar un proyecto Django. Un buen nombre puede ser
        taller. Pista: django-admin.py.
   2.   Lanzar servidor HTTP de desarrollo sobre proyecto recién
        creado. Pista: runserver.
   3.   Crear y activar una aplicación Django. Un buen nombre
        puede ser contacts.
Solución E2
   1.   Inicializar un proyecto Django
        $ django-admin.py startproject taller
        Este comando crea esta estructura:
             ��� taller
                  ��� manage.py
                  ��� taller
                       ��� __init__.py
                       ��� settings.py
                       ��� urls.py
                       ��� wsgi.py
2.   Lanza el servidor
     $ cd taller
     $ python manage.py runserver
     Levanta servidor en http://127.0.0.1:8000/
3.   Crear app y activarla
     $ python manage.py startapp contacts
          ���   contacts
          �      ��� __init__.py
          �      ��� models.py
          �      ��� tests.py
          �      ��� views.py
     Para activar hay que editar settings.py
     # taller/settings.py
     INSTALLED_APPS = (
         ...
         'contacts',
     )
¿Dónde estamos?
¿Dónde vamos?
Urls y vistas
Historia de una petición

  • convierte la petición en un objeto HttpRequest
  • enruta la petición a la función que le corresponde
  • la función devuelve un objeto HttpResponse
E3: Hola mundo

  1.   Crea una vista que devuelva la cadena "Hola mundo".
       Pista: views.py, HttpResponse.
  2.   Mapea la URL http://localhost:8000/hola/ con la
       vista recién creada. Pista: urls.py
  3.   EXTRA Crea la URL /extra que devuelve el User Agent
       de la petición en formato JSON. Pista:
       HttpRequest.META
Solución E3
   1.   Vista hola mundo
        # contacts/views.py
        from django.http import HttpResponse

        def my_view(request):
            return HttpResponse("Hola mundo")
   2.   Mapea la URL
        # taller/urls.py
        urlpatterns = patterns('',
            url(r'^hola/$', 'contacts.views.my_view'),
            ...
        $ python manage.py runserver
3.   EXTRA: manipula petición y respuesta
     from django.http import HttpResponse
     import json

     def extra(request):
         user_agent = request.META['HTTP_USER_AGENT']
         response = HttpResponse(json.dumps(user_agent),
                 content_type='application/json')
         return response
Modelos
ORM

 • Django incluye un ORM para interactuar con base de
     datos
 •   Se crean los modelos programáticamente
 •   Comandos para inicializar y sincronizar base de datos
 •   Métodos para validar y grabar objetos
 •   API para consultas
E4: ORM

  1.   Configura base de datos SQLite3 e inicializarla. Pista:
       settings.py, syncdb
  2.   Crear un modelo de datos para el objeto Person que
       tenga los siguientes campos:
         • name, texto, 80 caracteres máximo, obligatorio.
         • email, dirección de correo electrónico, opcional.
         • birthday, fecha, opcional.

       No te olvides de sincronizar al terminar para que se cree
       la tabla en la base de datos.
Solución E4
   1.   Configurar en settings.py
        # settings.py
        DATABASES = {
            'default': {
                'ENGINE': 'django.db.backends.sqlite3',
                'NAME': 'database.sqlite',
                ...
        Y sincronizar
        $ python manage.py syncdb
        Se puede ver el esquema creado con el comando sqlite3
        database.sqlite
2.   Crear modelo programáticamente
     # contacts/models.py
     from django.db import models

     class Person(models.Model):
         name = models.CharField(max_length=80)
         email = models.EmailField(blank=True)
         birthday = models.DateField(null=True, blank=Tr

         def __unicode__(self):
             return self.name
     Más https://docs.djangoproject.com/en/1.5/
     topics/db/models/
2.   (cont) No te olvides de sincronizar!
     $ python manage.py syncdb
     $ sqlite3 database.sqlite
     sqlite> .schema contacts_person
     CREATE TABLE "contacts_person" (
         "id" integer NOT NULL PRIMARY KEY,
         "name" varchar(80) NOT NULL,
         "email" varchar(75) NOT NULL,
         "birthday" date
     );
E5: La API de models
  1.   A través de un shell interactivo crear 3 objetos Person
       y grabarlos en base de datos.
        • Nacido en 1970 sin email
        • Nacido en 1990 con email
        • Sin fecha de nacimiento con email

  2.   EXTRA Genera un archivo en JSON con datos inciales
       para insertar en la tabla de Person cada vez que se
       sincronice. Pista: initial_data.json
  3.   EXTRA EXTRA Programa un generador de datos de
       prueba ficticios que sirva para poblar una base de datos
       en un entorno de test.
Solución E5
   1.   Crear objetos:
        $ python manage.py shell
        >>> from contacts.models import Person
        >>> me = Person()
        >>> me.full_clean()
        Traceback (most recent call last):
          ...
            raise ValidationError(errors)
        ValidationError: {'name': [u'This field cannot be b
        >>> me.name = u'Miguel González'
        >>> me.full_clean()
        >>> me.save()
2.   Crear un archivo
     contacts/fixtures/initial_data.json
     [
         {
             "pk": 1,
             "model": "contacts.person",
             "fields": {
               "birthday": "1976-05-12",
               "name": "Miguel Gonz\u00e1lez",
               "email": "migonzalvar@gmail.com"
             }
         }
     ]
3.   Ummm
E6: Querys

  1.   Averigua
        • Personas mayores que tú
        • Personas menores que tú
        • Personas sin fecha de nacimiento registrada

       Pista: filter
Solución E6

   1.   Desde la shell
        >>> from contacts.models import Person
        >>> people = Person.objects.all()
        >>> for p in people: print p
        >>> olders = Person.objects.filter(birthday__lt='197
        >>> youngers = Person.objects.filter(birthday__gt='1
        >>> unknown = Person.objects.filter(birthday__isnull

 Más https://docs.djangoproject.com/en/1.5/topics/
 db/queries/
Plantillas
Django templates

  • Variables: sustitución por el valor entre {{ }}
  • Tags: comandos, bucles, lógica… entre {% %}
  • Filters: modificadores de las variables dentro de variables
    se concatenan usando |
  • Permite herencia

 https:
 //docs.djangoproject.com/en/1.5/topics/templates/
YATL

 from contacts.models import Person
 from django.template import Template, Context

 me = Person.objects.get(pk=1)
 t = Template("Me llamo {{ person.name }}")
 c = Context({'person': me})
 print t.render(c)
people = Person.objects.all()
t = Template("""
{% for p in people %}

  {{ p.name }}
  ({{ p.birthday|date:"j-F"|default:"n/a" }})

{% endfor %}""")
c = Context({'people': people})
print t.render(c)
E7: All together now

   1.   Crea una vista accesible a través de la URL /list/ que
        muestre una lista de todos los objetos Person en la base
        de datos.
   2.   Crea una vista accesible a través de la URL
        /person// siendo pk un entero que muestre en
        pantalla los detalles del objeto Person correspondiente.
Solución E7
   1.   Lista
        # taller/urls.py
        urlpatterns = patterns('',
              url(r'^list/$', 'contacts.views.my_list_view'),
        # contacts/views.py
        def my_list_view(request):
              people = Person.objects.all()
              t = Template("""
              {% for p in people %}
              
              {{ p.name }}
              ({{ p.birthday|date:"j-F"|default:"n/a" }})
              
              {% endfor %}""")
              c = Context({'people': people})
              return HttpResponse(t.render(c))
2.   Detalles
     # taller/urls.py
     urlpatterns = patterns('',
         url(r'^person/(?P\d+)/$',
         'contacts.views.my_view'),
     ...
     # contacts/views.py
     def my_view(request, pk):
         person = Person.objects.get(pk=pk)
         t = Template("Me llamo {{ person.name }}")
         c = Context({'person': person})
         return HttpResponse(t.render(c))
Necesita mejorar

   1.   Plantillas en archivo independiente
   2.   Reutilizar código
Plantillas separadas
  $ mkdir --parents contacts/templates/contacts

  #contacts/templates/contacts/person_detail.html
  Me llamo {{ person.name }}

  #contacts/templates/contacts/person_list.html
  {% for p in object_list %}
  
  {{ p.name }}
  ({{ p.birthday|date:"j-F"|default:"n/a" }})
  
  {% endfor %}
Vistas genéricas
  # contacts/views.py
  from django.views.generic.detail import DetailView
  from django.views.generic.list import ListView

  from .models import Person

  class PersonDetailView(DetailView):
      model = Person

  class PersonListView(ListView):
      model = Person
Enrutado

 # taller/urls.py
 from contacts.views import (PersonDetailView,
     PersonListView)

 urlpatterns = patterns('',
     url(r'^person/(?P\d+)/$',
         PersonDetailView.as_view()),

    url(r'^list/$', PersonListView.as_view()),
    ...
¿Magia?
  1.   dispatch()
  2.   http_method_not_allowed()
  3.   get_template_names()
  4.   get_slug_field()
  5.   get_queryset()
  6.   get_object()
  7.   get_context_object_name()
  8.   get_context_data()
  9.   get()
  10
   .   render_to_response()

 https://docs.djangoproject.com/en/1.5/ref/
 class-based-views/generic-display/
Baterías incluidas: administración
E8: Activar módulo administración

   1.   Activa el módulo de administración que incluye Django de
        serie. Pista: django.contrib.admin, miras los
        comentarios…
Solución E8
   1.   Activar aplicación de administración
        # settings.py
        INSTALLED_APPS = (
             ...
             'django.contrib.admin',
        )
   2.   Mapear las URL
        # urls.py
        from django.contrib import admin
        admin.autodiscover()

        urlpatterns = patterns('',
            ...
            url(r'^admin/', include(admin.site.urls)),
        )
3.   También hay que activar cada modelo
     # contacts/admin.py
     from django.contrib import admin
     from .models import Person

     admin.site.register(Person)
Al final hay que sincronizar la base de datos.

$ python manage.py syncdb

Necesitas un superusuario.

$ python manage.py createsuperuser --username=admin

Prueba: http://127.0.0.1:8000/admin/
Formularios
Para que sirven…

  • Renderizar HTML
  • Limpiar y chequear la entrada de usuario
  • Renderizar HTML de un formulario con datos erróneos
  • ¡Grabar en base de datos!
Ciclo de vida

  3 posibles estados de un formulario:

    1.   Formulario vacío y sin enviar (GET)
    2.   Formulario enviado pero con datos erróneos (POST)
    3.   Formulario enviado con datos incorrectos (POST…
         redirige a)
Demo: Formularios
  1.   Nueva aplicación: feedback
       $ python manage.py startapp feedback
  2.   Archivo forms.py, Feedback
       from django import forms

       KIND_OF_REQUEST = (
           ('info', u'Información'),
           ('complaint', u'Queja'),
       )

       class ContactForm(forms.Form):
           kind = forms.ChoiceField(choices=KIND_OF_REQUES
           sender = forms.EmailField()
           subject = forms.CharField(max_length=80)
           text = forms.CharField(required=False)
3.   Formulario en blanco
     from feedback.forms import ContactForm

     form = ContactForm()
     form.is_bound
     form.as_p()
4.   Formulario con datos erróneos
     data = {'subject': "OLA K ASE",
         'kind': 'info',
         'text': "TRABAJA O K ASE"}
     form = ContactForm(data)
     form.is_bound
     form.is_valid()
     form.cleaned_data
     form.errors
     form.as_p()
5.   Formulario correcto
     data = {'subject': "OLA K ASE",
         'kind': 'info',
         'text': "TRABAJA O K ASE",
         'sender': 'hoygan@example.com'}
     form = ContactForm(data)
     form.is_bound
     form.is_valid()
     form.cleaned_data
     form.errors
     form.as_p()
6.   Vista clásica

from django.shortcuts import render
from django.http import HttpResponseRedirect

def contact(request):
    if request.method == 'POST':
        form = ContactForm(request.POST)
        if form.is_valid():
            form.send_email()
            return HttpResponseRedirect('/thanks/')
    else:
        form = ContactForm()

      return render(request, 'contact.html', {
          'form': form,
      })
5.   DRY

from django.views.generic.edit import FormView

from .forms import ContactForm

class ContactView(FormView):
    template_name = 'contact.html'
    form_class = ContactForm
    success_url = '/thanks/'

      def form_valid(self, form):
          form.send_email()
          return super(ContactView, self).form_valid(form
Edición de objetos
Model + Form = ModelForm
Demo: ModelForm
 # contacts/views.py
 from django.views.generic.edit import CreateView, Updat
 from django.core.urlresolvers import reverse_lazy

 class PersonCreate(CreateView):
         model = Person

 class PersonUpdate(UpdateView):
         model = Person

 class PersonDelete(DeleteView):
     model = Person
     success_url = reverse_lazy('person-list')
# contacts/models.py
class Person(models.Model):
    ...
    def get_absolute_url(self):
        return reverse("person_detail", kwargs={"pk": s

{# person_form.html #}

    {% csrf_token %}
    {{ form.as_p }}
Autenticación
Explicación
   1.   Crear usuario a través de interfaz admin
   2.   Demostrar flujo en shell
  from django.contrib.auth import authenticate
  user = authenticate(username='fulano', password='secret
  if user is not None:
      # Usuario y contraseña correctos
      if user.is_active:
          print(u"Usuario válido, activo y autenticado")
      else:
          print(u"Contraseña válida pero usuario desactiv
  else:
      # Contraseña incorrecta o usuario inexistente
      print(u"Contraseña y/o usuarios incorrectos")
   3.   En una vista hay que guardar sesión
Módulos de terceros
django-taggit

 Añade etiquetas a tus modelos

   1.   Instalar
        $ pip install django-taggit
   2.   Activar app
3.   Añadir al modelo
     # contacts/models.py
     ...

     from taggit.managers import TaggableManager

     class Person(models.Model):
         ...

         tags = TaggableManager()
4.   Sincronizar base de datos
5.   Comprobar en admin

                          ]
En el tintero
AJAX: 2 aproximaciones

  • Ligera, hay que implmentar la lógica (django-braces,
    dajaxproject)
  • Construye una API REST desde el modelo
    (rest-framework, tastypie)
Despliegue en producción

  • Servidor web WSGI implmentado en Pythyon: gunicorn
  • Servidor HTTP nginx como proxy inverso
Fin
Por donde seguir…

  • Documentación: https:
    //docs.djangoproject.com/en/1.5/contents/
  • Tutorial: http:
    //effectivedjango.com/tutorial/forms.html
  • Paquetes: aplicaciones y meta frameworsks
    https://www.djangopackages.com/
  • Blogs: http://www.planetdjango.org/
Gracias!
También puede leer