Tutorial Django

Embed Size (px)

DESCRIPTION

Tutorial de Django

Citation preview

  • Tutorial de

    Tutorial escrito por Jos Plana

  • Tuto

    rial D

    jang

    o ndice Introduccin: Cmo iniciar una aplicacin con Django; lbum de fotos.

    Modelos y BBDD: Donde guardar la informacin.

    Vistas y Urls: Procesar los datos

    Formularios y Templates: Guardar y ensear nuestras fotos.

    Cmo usar Git y Bootstrap con Django

  • Tuto

    rial D

    jang

    o Introduccin: Cmo iniciar una aplicacin con Django; lbum de fotos. Si an no conoces Django, el framework de Python que nos permite crear

    aplicaciones web de forma rpida, no te puedes perder este tutorial en el que iremos

    creando un lbum de fotos, para ver de forma prctica los conceptos bsicos. Como

    punto de inicio es una buena prctica trabajar sobre un entorno virtual, que nos

    permita tener instalaciones especficas del proyecto en el que estamos y para

    hacerlo vamos a usar virtualenvwrapper. Comprobamos que lo tenemos instalado.

    (Aqu puedes ver como instalarlo)

    openwebinars@~/aplicaciones: pip show virtualenvwrapper --- Name: virtualenvwrapper Version: 4.2 Location: /usr/local/lib/python2.7/dist-packages Requires: virtualenv, virtualenv-clone, stevedore openwebinars@~/aplicaciones:

    Ahora podemos crear el entorno virtual en el que vamos a trabajar, que llamaremos tutorial

    openwebinars@~/aplicaciones: mkvirtualenv tutorial New python executable in tutorial/bin/python Installing setuptools, pip...done. (tutorial)openwebinars@~/aplicaciones:

    Podemos ver que ahora tenemos delante del prompt el nombre de nuestro entorno entre parntesis, esto nos indica que estamos dentro. Otros comandos tiles son: deactivate: Para salir del entorno. workon: Para ver los entornos disponibles. workon [entorno]: Para activar un entorno; workon tutorial en nuestro caso. rmvirtualenv [entorno]: Para borrar un entorno. Recuerda! antes tienes que haber salido de l. Con nuestro entorno listo, podemos empezar a prepararlo, para ello vamos a instalar Django y, como nuestra aplicacin va a trabajar con imgenes, tambin necesitamos Pillow.

    2

  • Tuto

    rial D

    jang

    o

    (tutorial)openwebinars@~/aplicaciones: pip install Django==1.7, Pillow Downloading/unpacking Django==1.7 Downloading Django-1.7-py2.py3-none-any.whl (7.4MB): 7.4MB downloaded Downloading/unpacking Pillow Downloading Pillow-2.6.1.tar.gz (7.3MB): 7.3MB downloaded --- Successfully installed Django Pillow Cleaning up... (tutorial)openwebinars@~/aplicaciones: (tutorial)openwebinars@~/aplicaciones: pip list argparse (1.2.1) Django (1.7) ipython (2.3.0) Pillow (2.6.1) pip (1.5.6) setuptools (3.6) wsgiref (0.1.2) (tutorial)openwebinars@~/aplicaciones:

    Con el proceso de instalacin terminado podemos crear nuestro proyecto que

    llamamos myapps, usa el comando:

    (tutorial)openwebinars@~/aplicaciones: django-admin.py startproject myapps (tutorial)openwebinars@~/aplicaciones:

    Ya tenemos el proyecto creado y sobre este podremos ir aadiendo aplicaciones a

    parte de las que ya vienen con Django, pero esto lo veremos ms adelante, antes

    vamos a ver qu aspecto tiene; El comando tree nos muestra la estructura.

    (tutorial)openwebinars@~/aplicaciones: tree myapps myapps manage.py myapps __init__.py settings.py urls.py wsgi.py

    1 directory, 5 files (tutorial)openwebinars@~/aplicaciones:

    En este primer post vamos a usar solo dos de estos ficheros, ./manage.py

    y./myapps/settings.py. El primero nos va a permitir realizar acciones sobre el

    3

  • Tuto

    rial D

    jang

    o

    proyecto desde la lnea de comandos, el segundo es el fichero de configuracin

    propio del proyecto. En este punto ya podemos crear la aplicacin, vamos al

    directorio ./myapps y ejecutamos el siguiente comando:

    (tutorial)openwebinars@~/aplicaciones/myapps: python manage.py startapp album (tutorial)openwebinars@~/aplicaciones/myapps: (tutorial)openwebinars@~/aplicaciones/myapps: tree album album admin.py __init__.py migrations __init__.py models.py tests.py views.py 1 directory, 6 files (tutorial)openwebinars@~/aplicaciones/myapps:

    Aqu podemos ver como es el directorio de nuestra aplicacin lbum. Vamos ahora al directorio ./myapps y editamos el fichero de configuracin settings.py para aadir nuestra aplicacin en la tupla INSTALLED_APPS; Debera tener este aspecto.

    INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'album',

    )

    Antes de guardar los cambios en el fichero de configuracin, buscamos el

    diccionario DATABASES, en este tutorial usaremos SQLite, la base de datos que nos

    ofrece Django por defecto.

    DATABASES = { 'default': {

    'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),

    } }

    4

  • Tuto

    rial D

    jang

    o Y por ltimo establecemos la zona horaria en la que nos encontramos, aqu puedes verlas todas, Europa/Madrid en nuestro caso.

    TIME_ZONE = 'Europe/Madrid'

    Ya podemos guardar los cambios en settings.py. Una de las aplicaciones que nos

    ofrece Django por defecto es un administrador desde el que podremos aadir o

    editar contenidos en nuestra aplicacin, esto nos va a facilitar mucho las cosas.

    Para iniciarlo necesitamos crear las tablas necesarias y posteriormente podremos

    crear el usuario con el que tendremos acceso. Para el primer paso ejecutamos el

    siguiente comando.

    (tutorial)openwebinars@~/aplicaciones/myapps: python manage.py migrate Operations to perform: Apply all migrations: admin, contenttypes, auth, sessions Running migrations: Applying contenttypes.0001_initial... OK Applying auth.0001_initial... OK Applying admin.0001_initial... OK Applying sessions.0001_initial... OK (tutorial)openwebinars@~/aplicaciones/myapps:

    Con esto lo que hacemos es recorrer la lista de aplicaciones que tenemos en

    nuestro proyecto, en INSTALLED_APPS, dentro del fichero settings.py e ir creando

    las tablas necesarias en la base de datos. Tambin podemos ver que se ha creado

    un fichero db.sqlite3 que ser nuestra base de datos.

    (tutorial)openwebinars@~/aplicaciones/myapps: ll -rt total 56 -rwxrwxr-x 1 jose jose 249 oct 21 20:24 manage.py* drwxrwxrwx 4 jose jose 4096 oct 22 19:43 ../ drwxrwxr-x 2 jose jose 4096 oct 22 20:22 myapps/ drwxrwxr-x 3 jose jose 4096 oct 22 20:22 album/ -rw-r--r-- 1 jose jose 36864 oct 22 20:22 db.sqlite3 drwxrwxr-x 4 jose jose 4096 oct 22 20:22 ./ (tutorial)openwebinars@~/aplicaciones/myapps:

    5

  • Tuto

    rial D

    jang

    o Con la base de datos lista, vamos a crear el usuario.

    (tutorial)openwebinars@~/aplicaciones/myapps: python manage.py createsuperuser Username (leave blank to use 'administrador'): admin Email address: [email protected] Password: ***** Password (again): ***** Superuser created successfully. (tutorial)openwebinars@~/aplicaciones/myapps:

    Ya tenemos nuestro proyecto listo para empezar a desarrollar nuestra aplicacin,

    para probarlo iniciamos el servidor de desarrollo.

    (tutorial)openwebinars@~/aplicaciones/myapps: python manage.py runserver Performing system checks... System check identified no issues (0 silenced). October 22, 2014 - 20:32:42 Django version 1.7, using settings 'myapps.settings' Starting development server at http://127.0.0.1:8000/ Quit the server with CONTROL-C.

    En un navegador buscamos la direccin http://127.0.0.1:8000/

    6

  • Tuto

    rial D

    jang

    o

    Para visitar el administrador vamos a http://127.0.0.1:8000/admin/

    Django nos ofrece mucho trabajo hecho para que solo tengamos que pensar en

    nuestra aplicacin.

    7

  • Tuto

    rial D

    jang

    o Modelos y BBDD: Donde guardar la informacin. En el captulo anterior vimos cmo poner en marcha nuestro proyecto Django y

    cmo arrancar una aplicacin. Estamos creando un lbum de fotos, hemos

    preparado un entorno virtual en el que estamos trabajando y tenemos instalado

    Django y Pillow. Tambin creamos nuestra base de datos con SQLite y un usuario de

    administracin para la aplicacin.

    En este nuevo post vamos a crear el modelo de datos y lo incluiremos en el

    administrador que nos ofrece Django para poder gestionarlo sin tener que recurrir a

    la consola.

    Si recordamos la estructura de carpetas que creaba Django para nuestra aplicacin,

    tenemos lo siguiente.

    (tutorial)openwebinars@~/aplicaciones/myapps: tree album album admin.py __init__.py migrations __init__.py models.py tests.py views.py

    1 directory, 6 files (tutorial)openwebinars@~/aplicaciones/myapps:

    Es en el fichero models.py donde vamos a definir el modelo de datos para nuestro

    lbum, lo editamos para dejarlo as:

    from django.db import models

    class Category(models.Model): """ Categorias para clasificar las fotos """

    name = models.CharField(max_length=50)

    def __unicode__(self): return self.name

    8

  • Tuto

    rial D

    jang

    o class Photo(models.Model): """ Fotos del album """

    category = models.ForeignKey(Category, null=True, blank=True) title = models.CharField(max_length=50, default='No title') photo = models.ImageField(upload_to='photos/') pub_date = models.DateField(auto_now_add=True) favorite = models.BooleanField(default=False) comment = models.CharField(max_length=200, blank=True)

    def __unicode__(self): return self.title

    Lo primero que hacemos es importar el mdulo models ya que cada una de nuestras

    clases ser una subclase de models.Model.

    Para nuestra aplicacin hemos definido dos clases, Category que representar las

    distintas categoras en las que podemos clasificar nuestras fotos y Photo que

    representa las fotos de nuestro lbum. Si las clases que definimos en models.py

    representan las tablas en nuestra base de datos, las columnas estn representadas

    por las instancias de la clase Field. Nosotros hemos usado los siguientes campos:

    CharField: para campos de caracteres. Tiene un argumento obligatorio, max_length.

    ImageField: para ficheros con extensiones de imagen. Aqu usamos el argumento

    upload_to para especificarle en que directorio queremos que se guarden las

    imgenes de nuestra aplicacin.

    DateField: para fechas. Al indicarle auto_now_add como True, estamos

    almacenando la fecha en la que la foto se ha guardado por primera vez.

    BooleanField: para valores booleanos, indicndole que el valor por defecto es false,

    en caso de no definirlo estaramos usando None como valor por defecto.

    ForeignKey: para establecer relaciones entre clases. null y blank para especificar que

    este campo puede estar vaco.

    Adems de esto, definimos en cada una de las clases el mtodo __unicode__() de

    esta forma le podemos indicar como queremos que quede representado cada uno

    9

  • Tuto

    rial D

    jang

    o

    de los objetos, en nuestro caso usaremos el nombre para las categoras y el ttulo

    para las fotos.

    Con el modelo de datos definido podemos trasladarlo a nuestra base de datos,

    primero ejecutamos el siguiente comando.

    (tutorial)openwebinars@~/aplicaciones/myapps: python manage.py makemigrations Migrations for 'album': 0001_initial.py: - Create model Category - Create model Photo (tutorial)openwebinars@~/aplicaciones/myapps:

    Veremos una salida como esta, que nos indica que se ha creado un fichero,

    0001_initial.py en el que estn las modificaciones que se harn en la base de datos

    al ejecutar el siguiente comando.

    (tutorial)openwebinars@~/aplicaciones/myapps: python manage.py migrate Operations to perform: Apply all migrations: admin, album, contenttypes, auth, sessions Running migrations: Applying album.0001_initial... OK (tutorial)openwebinars@~/aplicaciones/myapps:

    Con esto tendremos en la base de datos el modelo que acabamos de definir. Pero

    antes de probarlo tenemos que editar el fichero settings.py para definir

    MEDIA_ROOT como:

    MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')

    Lo hacemos porque Django no guarda en la base de datos el fichero si no la ruta

    donde est el fichero, de forma relativa a esta configuracin; As, nuestras fotos se

    guardarn en./media/photos/.

    Ahora ya podemos abrir el shell y probar a grabar la primera imagen.

    (tutorial)openwebinars@~/aplicaciones/myapps: python manage.py shell

    from album.models import Category, Photo from django.core.files import File

    10

  • Tuto

    rial D

    jang

    o c = Category(name='Lagos') c.save() p = Photo(category=c, title='Maly') f = open('/home/jose/Escritorio/maly.jpg') p.photo.save('maly.jpg', File(f))

    c.name Out: 'Lagos'

    p.title Out: 'Maly'

    p.photo.url Out: 'photos/maly.jpg'

    exit

    Podemos ver que se ha creado un nuevo directorio ./media/photos/ que contiene

    nuestra imagen.

    (tutorial)openwebinars@~/aplicaciones/myapps: tree media media photos maly.jpg

    1 directory, 1 file

    Aunque vemos que funciona correctamente, esta forma de trabajar es lenta si se

    trata de alimentar la base de datos con ms de un registro, para hacerlo ms

    llevadero vimos en el captulo anterior que Django nos ofreca un administrador con

    el que poder gestionar el contenido de nuestra app. Vamos a prepararlo.

    Lo primero es decirle que queremos que nuestra aplicacin, lbum, aparezca en l.

    Editamos el fichero ./album/admin.py para dejarlo as.

    from django.contrib import admin from album.models import Category, Photo

    admin.site.register(Category) admin.site.register(Photo)

    11

  • Tuto

    rial D

    jang

    o

    Iniciamos el servidor de pruebas y vamos a la direccin http://127.0.0.1:8000/admin,

    entramos con el usuario que creamos en el captulo anterior y vemos la pgina

    principal del administrador.

    Ahora es ms fcil crear una categora nueva y mucho ms fcil aadir imgenes. A

    la derecha de Photos tenemos el botn Add.

    En Category podemos elegir entre las que tenemos creadas o directamente crear

    una nueva, Montaas en nuestro caso. Abajo a la derecha podemos decidir si

    guardar y crear otra, guardar y continuar editando o guardar.

    Tambin podemos borrar las fotos que tenemos cargadas, con el botn que aparece

    abajo a la izquierda.

    12

  • Tuto

    rial D

    jang

    o

    Al hacerlo detectamos un problema, aunque el registro se ha borrado de nuestra

    base de datos, vemos que el fichero que contiene la imagen sigue estando en

    nuestro directorio./media/photos/; Como dijimos antes lo que almacena Django en

    la base de datos solo es el directorio donde est la imagen.

    Para solucionarlo podemos usar las seales. Estas nos informan de cundo est

    ocurriendo una determinada accin. A nosotros nos interesa saber cuando se est

    llamando al mtodo delete() de nuestro objeto Photo, de esta forma una vez borrado

    el registro de la base de datos, podremos borrar la imagen a la que hace referencia.

    Volvemos a nuestro fichero models.py y lo editamos.

    from django.db.models.signals import post_delete from django.dispatch import receiver

    @receiver(post_delete, sender=Photo) def photo_delete(sender, instance, **kwargs): """ Borra los ficheros de las fotos que se eliminan. """ instance.photo.delete(False)

    Con esto queda solucionado nuestro problema.

    Vistas y Urls: Procesar los datos En los post anteriores vimos cmo se iniciaba una aplicacin, creamos la base de

    datos y los modelos; y vimos como podamos introducir las imgenes de nuestro

    lbum de fotos de dos formas, usando el shell y a travs del administrador que nos

    ofrece Django por defecto. Hoy usaremos las vistas para mostrar nuestra galera.

    13

  • Tuto

    rial D

    jang

    o

    Para ver como gestiona Django las vistas, las relaciona con el modelo de datos y

    enva esa informacin al navegador vamos a empezar creando una vista sencilla,

    simplemente vamos a mostrar un mensaje por pantalla.

    Editamos el fichero ./album/views.py

    from django.http import HttpResponse

    def first_view(request): return HttpResponse('Esta es mi primera vista!')

    Una vista es una funcin o un mtodo que bsicamente hace dos cosas, toma como

    argumento un objeto HttpRequest, en el que va la informacin referente a la solicitud

    que estamos haciendo, como por ejemplo si el mtodo empleado es POST o GET o

    el directorio donde est la pgina solicitada; y devuelve un objeto HttpResponse con

    la informacin de la pgina que va a mostrar o una excepcin si algo ha ido mal.

    Ahora tenemos que asociar la vista que acabamos de definir con una direccin, para

    hacerlo vamos a manejar dos ficheros, uno lo crea Django al iniciar el proyecto y

    est en ./myapps/urls.py, el otro lo tendremos que crear nosotros dentro del

    directorio de nuestra aplicacin,./album/urls.py.

    Vamos a editar el primero ./myapps/urls.py.

    from django.conf.urls import patterns, include, url from django.contrib import admin

    urlpatterns = patterns('', url(r'^admin/', include(admin.site.urls)),

    )

    Si nos olvidamos de las lneas que tiene comentadas vemos que tiene una relacin

    entre la direccin /admin y el mdulo admin.site.urls. Esta es la forma que tiene

    Django de enlazar ladireccin con el fichero urls.py propio de la aplicacin admin

    que ya hemos usado en los captulos anteriores. De esta forma al dirigirnos a

    http://127.0.0.1:8000/admin/ lo que hacemos es empezar a usar dicho fichero para

    14

  • Tuto

    rial D

    jang

    o

    los siguientes enlaces que usemos, como por ejemplo

    http://127.0.0.1:8000/admin/album/photo/.

    Vamos a hacer lo mismo con nuestra aplicacin lbum. Aadimos la siguiente lnea

    como nuevo argumento de la funcin patterns() para dejarla de la siguiente forma.

    from django.conf.urls import patterns, include, url from django.contrib import admin

    urlpatterns = patterns('', url(r'^album/', include('album.urls')), url(r'^admin/', include(admin.site.urls)),

    )

    Ahora ya sabemos que al incluir en el navegador una direccin que comience por

    /albumenviaremos el resto de la cadena como argumento a la funcin patterns que

    tenemos en el fichero./album/urls.py.

    Creamos y editamos este fichero para dejarlo as.

    from django.conf.urls import patterns, url from album import views

    urlpatterns = patterns('', url(r'^$', views.first_view, name='first-view'), )

    De esta forma, la direccin /album estar apuntando a la vista first_view().

    La funcin url() necesita dos argumentos, el primero ser una expresin regular

    (regex) que utiliza para identificar la direccin que escribimos en el navegador, el

    segundo es la funcin a la que llamar, first_view() para nosotros, pasndole como

    primer argumento el objeto HttpRequest que mencionbamos antes. Adems se

    pueden pasar tres argumentos opcionales, name lo usaremos para identificar

    nuestra url de forma nica y nos servir para poder cambiar la url sin tener que

    modificar las partes del proyecto donde hacemos referencia a ella. Los otros dos

    argumentos son kwargs y prefix que no usaremos en nuestra aplicacin.

    15

  • Tuto

    rial D

    jang

    o

    Si arrancamos el servidor de pruebas y buscamos en el navegador la direccin

    http://127.0.0.1:8000/album/ veremos lo siguiente.

    Con esto hemos visto cmo unir la direccin del navegador con nuestras vistas,

    veamos ahora cmo relacionar la vista con el modelo de datos y devolver esta

    informacin al navegador. Para hacerlo vamos a crear un nuevo directorio dentro de

    nuestra aplicacin./myapps/album/templates/album/ de modo que tengamos esto.

    (tutorial)openwebinars@~/aplicaciones/myapps: tree album album admin.py __init__.py migrations 0001_initial.py 0001_initial.pyc __init__.py models.py templates album tests.py urls.py views.py

    En l incluiremos los ficheros html propios de nuestra aplicacin. Creamos el fichero

    category.html de la siguiente forma.

    {{ object_list }}

    16

  • Tuto

    rial D

    jang

    o

    Ahora veremos que es object_list.

    Editamos de nuevo el fichero ./album/views.py

    from django.http import HttpResponse from django.shortcuts import render from album.models import Category, Photo

    def first_view(request): return HttpResponse('Esta es mi primera vista')

    def category(request): category_list = Category.objects.all() context = {'object_list': category_list} return render(request, 'album/category.html', context)

    category_list contiene todas las categoras disponibles y las pasamos como

    argumento a la funcin render(). Esta funcin es un atajo que nos proporciona

    Django para devolver el objeto HttpResponse a partir de una plantilla (category.html)

    y la informacin necesaria para componerla (context).

    Lo unimos con ./album/urls.py

    from django.conf.urls import patterns, url from album import views

    urlpatterns = patterns('', url(r'^$', views.first_view, name='first-view'), url(r'^category/$', views.category, name='category-list'), )

    y buscamos la nueva direccin en el navegador,

    http://127.0.0.1:8000/album/category/

    17

  • Tuto

    rial D

    jang

    o

    Como vemos, con object_list hemos incluido la lista de objetos Category dentro de

    nuestra plantilla category.html, por tanto ya tenemos toda la informacin relativa a

    las categoras.

    Vamos a incluir una nueva vista que nos muestre el detalle de una de las categoras;

    editamos de nuevo el fichero ./album/views.py

    def category_detail(request, category_id):

    category = Category.objects.get(id=category_id) context = {'object': category} return render(request, 'album/category_detail.html', context)

    Ahora la funcin category_detail() recibe dos argumentos, request y el identificador

    de la categora que queremos mostrar.

    En el directorio de ./album/templates/album creamos una nueva plantilla

    category_detail.html

    {{ object.id }}, {{ object.name }}, {{ object.photo_set.all }}

    De forma similar a la vista anterior, en la variable context que pasamos a la funcin

    render() tenemos un objeto Category del que podemos extraer su id, name y las

    fotos que pertenecen a dicha categora entre otras cosas.

    Por ltimo conectamos la vista con una url, esta vez tenemos que indicar de qu

    categora queremos extraer el detalle, para conseguirlo usaremos (?P\d+) siendo

    category_id el segundo parmetro que hemos pasado a la funcin category_detail().

    18

  • Tuto

    rial D

    jang

    o from django.conf.urls import patterns, url from album import views urlpatterns = patterns('',

    url(r'^$', views.first_view, name='first-view'), url(r'^category/$', views.category, name='category-list'), url(r'^category/(?P\d+)/detail/$', views.category_detail,

    name='category-detail'), )

    Si abrimos el enlace http://127.0.0.1:8000/album/category/2/detail/ en el

    navegador veremos el resultado.

    Ya vimos en posts anteriores que Django nos ofrece soluciones para facilitarnos el

    trabajo y en esta ocasin podemos aprovecharnos de las vistas genricas, como

    ListView y DetailView para obtener una lista de todos los objetos pertenecientes a un

    modelo y el detalle de uno de ellos. Vamos a hacerlo para la clase Photo.

    Abrimos ./album/views.py e incluimos este cdigo.

    from django.views.generic import ListView, DetailView

    class PhotoListView(ListView): model = Photo

    class PhotoDetailView(DetailView): model = Photo

    Como podemos ver solamente tenemos que decirle sobre que modelo queremos

    trabajar.

    19

  • Tuto

    rial D

    jang

    o

    Creamos dos nuevos templates, photo_list.html para el listado de fotos y

    photo_detail.html para el detalle. Las vistas genricas usan por defecto el siguiente

    sistema a la hora de buscar la plantilla html, /_list.html y

    /_detail.html, paraListView y DetailView

    respectivamente. Si queremos especificar un nombre de plantilla distinto podemos

    usar el atributo template_name.

    Creamos ./album/templates/album/photo_list.html

    {{ object_list }}

    y ./album/templates/album/photo_detail.html

    {{ object.id }}, {{ object.title }}

    Por ltimo, unimos la vista con urls editando ./album/urls.py para dejarlo as.

    from django.conf.urls import patterns, url from album import views

    urlpatterns = patterns('', url(r'^$', views.first_view, name='first-view'), url(r'^category/$', views.category, name='category-list'), url(r'^category/(?P\d+)/detail/$', views.category_detail, name='category-detail'),

    url(r'^photo/$', views.PhotoListView.as_view(), name='photo-list'),

    url(r'^photo/(?P\d+)/detail/$', views.PhotoDetailView.as_view(),

    name='photo-detail'), )

    Aqu tenemos que tener en cuenta dos cosas, al usar el sistema de vistas genricas

    estamos trabajando con clases no con funciones por lo que tenemos que llamar al

    mtodo as_view(), tambin hemos dejado de usar (?P\d+) y lo hemos sustituido por

    (?P\d+).

    Ya podemos ver en el navegador que el resultado es el mismo aunque esta vez

    nuestras vistas son mucho ms sencillas.

    20

  • Tuto

    rial D

    jang

    o

    http://127.0.0.1:8000/album/photo/

    http://127.0.0.1:8000/album/photo/1/detail/

    Esto es solo una parte ya que el sistema de vistas genricas es mucho ms potente

    y lo veremos con ms detalle en el siguiente captulo.

    Como ejercicio podemos cambiar las funciones category() y category_detail() para

    usar generic views, teniendo en cuenta que estamos trabajando con la plantilla

    category.html y no es lo que usar por defecto la vista ListView.

    Formularios y Templates: Guardar y ensear nuestras fotos. En este nuevo captulo vamos trabajar con las plantillas que utilizamos en el post

    anterior para mostrar la informacin de forma ms visual. Continuaremos viendo las

    21

  • Tuto

    rial D

    jang

    o

    vistas genricas para crear formularios de forma que podamos modificar o aadir

    registros a nuestra base de datos.

    Como punto de partida vamos a modificar la plantilla category_list.html que

    tenamos en el captulo anterior para dejarla as:

    ALBUM

    Category

    {% for c in object_list %}

    {{ c.name }}

    {% endfor %}

    De nuestra nueva plantilla podemos destacar dos elementos, las variables que estn

    identificadas por {{ }} y ya usamos en el captulo anterior y los tags que estn

    representados por {% %}.

    Las variables son evaluadas y sustituidas por su valor en la representacin de la

    plantilla. La forma en que se muestran las variables puede ser modificada mediante

    el uso de filtros que veremos ms adelante.

    Los tags nos ofrecen la posibilidad de incluir lgica o control de flujo dentro de las

    plantillas entre otras cosas.

    En nuestra plantilla estamos usando {% for %} para recorrer las distintas categorias

    que tenemos y poder mostrar su nombre con la variable {{ c.name }}, el valor name

    del objeto c extraido de la lista object_list.

    {% url %} es otro tag que usaremos muy a menudo, en este caso le pasamos el

    nombre de la url a la que queremos apuntar y el parmetro que necesita.

    Si vemos el resultado en el navegador http://127.0.0.1:8000/album/category/,

    tenemos lo siguiente:

    22

  • Tuto

    rial D

    jang

    o

    Si lo pensamos bien, vemos que el ttulo Album y la cabecera que indica si estamos

    en la seccin Category o Photo se van a repetir para el resto de plantillas. Para evitar

    tener que duplicar cdigo y seguir el principio DRY de Django, tenemos a nuestra

    disposicin dos tags que nos van a permitir usar una nica plantilla como esqueleto

    de nuestra aplicacin e ir insertando en esta las partes propias del resto de

    plantillas, esto se conoce como Template inheritance. Vamos a usarlo.

    Lo primero que haremos es modificar la plantilla category_list.html para dejarla as:

    {% extends 'base.html' %}

    {% block section %} Category {% endblock section %}

    {% block maincontent %}

    {% for c in object_list %}

    {{ c.name }}

    {% endfor %} {% endblock maincontent %}

    Aqu tenemos los dos nuevos tags, {% extends %} y {% block %}. El primero va a

    cargar nuestra plantilla base.html, que ser la plantilla esqueleto e incluir las

    secciones contenidas en los tags block donde se lo indiquemos.

    23

  • Tuto

    rial D

    jang

    o

    Ahora vamos a crear un nuevo directorio ./templates en el que incluiremos la

    plantilla base.html

    (tutorial)openwebinars@~/aplicaciones/myapps: tree templates templates base.html

    0 directories, 1 file (tutorial)openwebinars@~/aplicaciones/myapps:

    base.html quedar de la siguiente forma:

    Album Album

    Category

    Photo

    {% block section %} {% endblock section %}

    {% block maincontent %} {% endblock maincontent %}

    Hemos incluido dos nuevos links para poder navegar entre categoras y fotos.

    Vamos a modificar la que era nuestra url principal, para que deje de mostrar la

    primera vista que hicimos y la usaremos como pgina de inicio. Editamos

    ./album/views.py y ./album/urls.py

    En la ./album/views.py aadimos:

    24

  • Tuto

    rial D

    jang

    o EnOpenWebinars.nettenemostodosestoscursosatuenteradisposicin

    LinuxLPIC-1Examen101

    LinuxLPIC-1Examen102

    NodeJS,ExpressJSyMongoDB

    AngularJSyTypeScript

    AppsmvilesconPhoneGap

    ServidoresVoIPconAsterisk

    DesarrolloFrontend

    Profesional

    VirtualizacindeServidorescon

    Promox

    AppsMvilesconTitaniumAlloy

    DesarrolloBackendcon

    Django

  • Tuto

    rial D

    jang

    o from django.shortcuts import render def base(request): return render(request, 'base.html')

    y en ./album/urls.py:

    from django.conf.urls import patterns, url from album import views

    urlpatterns = patterns('', url(r'^$', views.base, name='base'), url(r'^category/$', views.CategoryListView.as_view(),

    name='category-list'), url(r'^category/(?P\d+)/detail/$',

    views.CategoryDetailView.as_view(), name='category-detail'),

    url(r'^photo/$', views.PhotoListView.as_view(), name='photo-list'),

    url(r'^photo/(?P\d+)/detail/$', views.PhotoDetailView.as_view(),

    name='photo-detail'), )

    Adems, vamos a indicar la nueva ruta donde estar la plantilla base.html aadiendo

    en./myapps/settings.py

    TEMPLATE_DIRS = ( os.path.join(BASE_DIR, 'templates/'),

    )

    Comprobamos el resultado en el navegador, http://127.0.0.1:8000/album/.

    25

  • Tuto

    rial D

    jang

    o

    y http://127.0.0.1:8000/album/category/

    Ahora ya podemos practicar con category_detail.html para que herede de base.html

    y experimentar con las distintas etiquetas html. Nosotros lo hemos dejado as,

    http://127.0.0.1:8000/album/category/1/detail/

    26

  • Tuto

    rial D

    jang

    o

    {% extends 'base.html' %} {% load static %}

    {% block section %} {{ object.name }} {% endblock section %}

    {% block maincontent %}

    {% for p in object.photo_set.all %}

    {{ p.title }}

    {% endfor %}

    27

  • Tuto

    rial D

    jang

    o {% endblock maincontent %}

    Vemos que en cada categora se muestra una miniatura con los enlaces a las

    distintas fotos que pertenecen, para mostrar las imagenes necesitamos incluir

    STATICFILES_DIRS en ./album/settings.py

    STATICFILES_DIRS = ( os.path.join(BASE_DIR, 'media'),

    )

    Ahora que tenemos los enlaces al detalle de las fotos, vamos a completar la

    navegacin modificando photo_detail.html para que nos muestre la foto y los

    detalles.

    Editamos photo_detail.html.

    {% extends 'base.html' %} {% load static %}

    {% block section %}

    {{ object.title }} {% if object.favorite %}

    {% else %}

    {% endif %} {% if object.category_id %} ( {{

    object.category }} ) {% endif %}

    comments: {{ object.comment|default:"no comments" }} edit delete

    {% endblock section %}

    {% block maincontent %}

    28

  • Tuto

    rial D

    jang

    o {% endblock maincontent %}

    En esta nueva plantilla hemos incluido varias cosas interesantes. Con la etiqueta

    load estamos cargando el modulo static.py que necesitamos para mostrar las

    imagenes. Para mostrar los comentarios usamos la variable {{ object.comment }}

    con un filtro default para incluir un comentario por defecto cuando el valor es una

    cadena vaca , adems tenemos dos nuevos enlaces para editar y borrar.

    Como ya hemos visto, estos enlaces apuntan a una vista a travs de ./album/urls.py.

    Con el primero modificaremos las fotos mientras que con el segundo vamos a poder

    borrar un registro de nuestra base de datos.

    Vamos a crear estas nuevas funcionalidades y aprovechamos para recordar como

    se trabajaba con las vistas genricas.

    Editamos ./album/views.py para aadir lo siguiente.

    from django.core.urlresolvers import reverse_lazy from django.views.generic.edit import UpdateView, CreateView, DeleteView

    class PhotoUpdate(UpdateView): model = Photo

    class PhotoCreate(CreateView): model = Photo

    class PhotoDelete(DeleteView): model = Photo success_url = reverse_lazy('photo-list')

    Tambin hemos incluido la vista PhotoCreate que usaremos enseguida.

    Enlazamos las vistas con urls editando ./album/urls.py y aadiendo lo siguiente

    dentro de patterns.

    # Update url(r'^photo/(?P\d+)/update/$', views.PhotoUpdate.as_view(), name='photo-update'), #Create url(r'^photo/create/$', views.PhotoCreate.as_view(), name='photo-create'), #Delete url(r'^photo/(?P\d+)/delete/$', views.PhotoDelete.as_view(),

    29

  • Tuto

    rial D

    jang

    o name='photo-delete'),

    Ahora bien, para las dos primeras vistas, update y create, necesitaremos un

    formulario desde el que podamos interactuar bien modificando los valores de

    nuestros registros o bien creando uno nuevo. Para crearla usaremos el nombre que

    buscar Django por defecto, photo_form.html, esta plantilla es comn para las dos

    vistas PhotoUpdate y PhotoCreate ya que muestra todos los campos definidos en el

    modelo y dependiendo de la llamada que se haga, desde el modo Update o Create

    mostrar los campos con los valores o vacos respectivamente.

    Este es el aspecto que tendr photo_form.html

    {% extends "base.html" %}

    {% block maincontent %} {% csrf_token %}

    {{ form.as_p }} Save Cancel

    {% endblock maincontent%}

    Volvemos a usar como plantilla principal base.html. Dentro de la etiqueta form

    usamos el atributo method como POST en lugar de GET ya que en update y create

    estamos modificando la informacin contenida en la base de datos. Tambin es

    importante destacar el uso del tag {% csrf_token %}; usaremos este tag dentro de las

    etiquetas form con atributos POST para evitar ataques CSRF. Bsicamente estos

    ataques usan los datos de conexin de un usuario conocido y de confianza para

    realizar acciones no autorizadas sobre el servidor.

    La variable form contiene los campos de nuestro modelo y para representarlos

    podemos usar as_p para mostrarlos entre etiquetas en html, as_table para usar

    etiquetas o as_ul para usar etiquetas

    Tenemos que tener en cuenta una cosa ms, cuando queramos cancelar la edicin

    de un registro estamos redirigiendo la navegacin hacia la vista nombrada como

    photo-list, de igual modo tenemos que definir hacia dnde iremos cuando grabemos

    30

  • Tuto

    rial D

    jang

    o

    los datos usando el botn save, para ello editamos ./album/models.py y aadimos el

    siguiente mtodo dentro de la clase Photo.

    def get_absolute_url(self): return reverse('photo-list')

    Como estamos usando reverse es necesario importarlo desde

    django.core.urlresolvers

    Si abrimos el detalle de una foto y pulsamos sobre el enlace edit veremos esto:

    donde podemos modificar los valores que tenamos.

    Con estos pasos que acabamos de hacer tenemos lista tambin la opcin de crear

    un nuevo registro para aadir fotos, solo tenemos que incluir el enlace en la plantilla

    que queramos. Nosotros lo hemos hecho en base.html como otro elemento ms de

    la lista.

    31

  • Tuto

    rial D

    jang

    o

    Vamos a ver como preparar la opcin de borrado. Aunque ya tenemos enlazados las

    vistas con la url y aparentemente no es necesaria ninguna plantilla para borrar un

    registro de la base de datos, si intentamos borrar una foto veremos el error

    TemplateDoesNotExist, esto es as porque Django nos pide una plantilla para

    confirmar la accin, justo debajo del error podemos ver el nombre que espera

    encontrar Django.

    Vamos a crearla, en nuestro directorio ./album/templates/album incluimos una

    nueva plantillaphoto_confirm_delete.html

    {% extends 'base.html' %}

    32

  • Tuto

    rial D

    jang

    o {% block maincontent %} {% csrf_token %}

    Delete "{{ object.title }}"? Cancel

    {% endblock maincontent %}

    Igual que al crear o modificar un registro tenemos que decirle el enlace al que debe

    dirigirse una vez terminada la accin, al borrar tambin tenemos que hacerlo, ya lo

    incluimos en la propia clase con el atributo success_url.

    Con esto tenemos las herramientas necesarias para cambiar la plantilla

    photo_list.html y hacer que tenga mejor aspecto, tambin podemos generar nuevos

    formularios para crear, editar o eliminar categoras as como jugar con todas las

    opciones que nos ofrece html para personalizar nuestra aplicacin.

    En el siguiente captulo veremos cmo usar repositorios y mejoraremos la

    apariencia de nuestro lbum con Bootstrap.

    Cmo usar Git y Bootstrap con Django Continuando con nuestro lbum de fotos, y ahora que el proyecto va tomando forma,

    es buena idea empezar a usar un control de versiones de forma que queden

    reflejados los cambios que vamos haciendo, as podremos recuperar el proyecto en

    un estado anterior y tendremos control sobre las fechas en que se hicieron

    modificaciones, entre otras cosas. Adems, aunque en nuestro caso slo

    trabajamos nosotros en el lbum, en caso de formar parte de un equipo de

    desarrollo tendramos la posibilidad de trabajar de forma independiente sobre los

    mismos ficheros sin pisar el trabajo de nuestros compaeros.

    Tenemos a nuestra disposicin distintas herramientas que nos permiten trabajar de

    esta forma, en nuestro caso usaremos Git, as podemos trabajar en un repositorio

    propio y una vez tengamos los cambios hechos, hacer push de nuestro repositorio a

    un repositorio compartido.

    33

  • Tuto

    rial D

    jang

    o

    Lo primero que vamos a hacer es crear un repositorio local, en el que incluiremos

    nuestro proyecto con el comando git init .

    (tutorial)openwebinars@~/aplicaciones/myapps: git init Initialized empty Git repository in /home/jose/aplicaciones/myapps/.git/ (tutorial)openwebinars@~/aplicaciones/myapps:

    Vemos que se ha creado un nuevo directorio .git.

    Para ver el estado actual de nuestro repositorio usaremos git status; es conveniente

    revisar el estado de nuestro proyecto para tener identificados qu ficheros se han

    aadido para la siguiente subida al repositorio comn.

    (tutorial)openwebinars@~/aplicaciones/myapps: git status En la rama master

    Commit inicial

    Archivos sin seguimiento: (use git add ... para incluir lo que se ha de ejecutar)

    .idea/ album/ db.sqlite3 manage.py media/ myapps/ templates/

    no se ha agregado nada al commit pero existen archivos sin seguimiento (use git add para darle seguimiento) (tutorial)openwebinars@~/aplicaciones/myapps:

    Se ha creado una rama de trabajo llamada master, adems git ha identificado todos

    los archivos que forman nuestro proyecto y nos informa de que no se han incluido

    para el siguiente commit. Para incluir los archivos usaremos el comando git add

    o git add. Para incluir todo, pero antes vamos a ver si queremos compartir

    todo lo que hay en el directorio, por ejemplo en nuestro proyecto tenemos muchos

    ficheros del tipo *.pyc que no queremos subir, tampoco queremos subir las fotos ni

    la base de datos, de esta forma al repositorio llegarn copias limpias de nuestro

    proyecto. Para descartar este tipo de ficheros usamos un archivo .gitignore en el que

    podemos decir qu debe dejar sin seguimiento.

    34

  • Tuto

    rial D

    jang

    o

    (tutorial)openwebinars@~/aplicaciones/myapps: cat .gitignore *.jpg *.pyc .idea db.sqlite3 (tutorial)openwebinars@~/aplicaciones/myapps:

    Si volvemos a consultar el estado

    (tutorial)openwebinars@~/aplicaciones/myapps: git status En la rama master

    Commit inicial

    Archivos sin seguimiento: (use git add ... para incluir lo que se ha de ejecutar)

    .gitignore album/ manage.py myapps/ templates/

    no se ha agregado nada al commit pero existen archivos sin seguimiento (use git add para darle seguimiento) (tutorial)openwebinars@~/aplicaciones/myapps:

    Vemos que ya no est incluido el archivo db.sqlite3, tampoco estarn dentro de los

    directorios los ficheros .pyc y .jpg.

    Ahora ya podemos decir a Git que inicie el seguimiento de los ficheros de nuestro

    proyecto.

    (tutorial)openwebinars@~/aplicaciones/myapps: git add . (tutorial)openwebinars@~/aplicaciones/myapps: git status En la rama master

    Commit inicial

    Cambios para hacer commit: (use git rm --cached ... para eliminar stage)

    new file: .gitignore new file: album/__init__.py new file: album/admin.py

    35

  • Tuto

    rial D

    jang

    o new file: album/migrations/0001_initial.py new file: album/migrations/__init__.py new file: album/models.py new file: album/templates/album/category_detail.html new file: album/templates/album/category_list.html new file: album/templates/album/photo_confirm_delete.html new file: album/templates/album/photo_detail.html new file: album/templates/album/photo_form.html new file: album/templates/album/photo_list.html new file: album/tests.py new file: album/urls.py new file: album/views.py new file: manage.py new file: myapps/__init__.py new file: myapps/settings.py new file: myapps/urls.py new file: myapps/wsgi.py new file: templates/base.html

    (tutorial)openwebinars@~/aplicaciones/myapps:

    Aqu podemos ver qu ficheros se han incluido en el primer commit que podemos

    ejecutar con el comando git commit -m "Initial commit".

    (tutorial)openwebinars@~/aplicaciones/myapps: git commit -m "Initial commit" [master (root-commit) e300e4a] Initial commit 21 files changed, 439 insertions(+) create mode 100644 .gitignore create mode 100644 album/__init__.py create mode 100644 album/admin.py create mode 100644 album/migrations/0001_initial.py create mode 100644 album/migrations/__init__.py create mode 100644 album/models.py create mode 100644 album/templates/album/category_detail.html create mode 100644 album/templates/album/category_list.html create mode 100644 album/templates/album/photo_confirm_delete.html create mode 100644 album/templates/album/photo_detail.html create mode 100644 album/templates/album/photo_form.html create mode 100644 album/templates/album/photo_list.html create mode 100644 album/tests.py create mode 100644 album/urls.py create mode 100644 album/views.py create mode 100755 manage.py create mode 100644 myapps/__init__.py create mode 100644 myapps/settings.py create mode 100644 myapps/urls.py create mode 100644 myapps/wsgi.py create mode 100644 templates/base.html (tutorial)openwebinars@~/aplicaciones/myapps:

    36

  • Tuto

    rial D

    jang

    o Ahora que hemos hecho el primer commit en nuestro repositorio local podemos pasar nuestro proyecto a un repositorio compartido. En este captulo usaremos

    GitHub para gestionar nuestro repositorio remoto. Una vez hayamos creado nuestra

    cuenta en GitHub veremos la opcin Create Repository, nosotros lo hemos

    nombrado como my_album por lo que GitHub asigna la direccin

    https://github.com/usuario/my_album.git, donde usuario ser el nombre de usuario

    de nuestra cuenta GitHub. Con el siguiente comando podemos crear un repositorio

    remoto, que normalmente se llama origin, asociado a esta direccin.

    (tutorial)openwebinars@~/aplicaciones/myapps: git remote add origin https://github.com/usuario/my_album.git (tutorial)openwebinars@~/aplicaciones/myapps:

    Ya podemos enviar nuestro repositorio local al repositorio remoto, origin, que

    acabamos de crear.

    (tutorial)openwebinars@~/aplicaciones/myapps: git push -u origin master Username for 'https://github.com': usuario Password for 'https://[email protected]': ******* Counting objects: 27, done. Delta compression using up to 2 threads. Compressing objects: 100% (23/23), done. Writing objects: 100% (27/27), 6.03 KiB | 0 bytes/s, done. Total 27 (delta 1), reused 0 (delta 0) To https://github.com/usuario/my_album.git *[new branch] master -> master Branch master set up to track remote branch master from origin. (tutorial)openwebinars@~/aplicaciones/myapps:

    Con este comando estamos diciendo que pase el contenido de la rama local, que

    por defecto Git llama mster al repositorio origin que hemos creado, el parmetro -u

    le dice a Git que recuerde estos dos nombres, por lo que la prxima vez slo

    tendremos que usar git push y ya sabr que tiene que pasar el contenido de master a

    origin. Si volvemos a la direccin https://github.com/usuario/my_album.git veremos

    el contenido de nuestro proyecto.

    37

  • Tuto

    rial D

    jang

    o

    Ahora que ya tenemos nuestro repositorio remoto, volvamos a trabajar sobre la

    copia local que tenemos.

    Aunque en el captulo anterior vimos cmo mejorar el aspecto de nuestra aplicacin,

    en esta ocasin vamos a ir un paso ms all y vamos a usar Bootstrap, que aparte

    de ofrecernos un diseo preestablecido es web responsive, es decir veremos cmo

    podemos hacer que nuestra aplicacin mantenga un buen aspecto

    independientemente del dispositivo que estemos usando para verla. Lo primero que

    tenemos que hacer es indicar a nuestra aplicacin que tiene que cargar Bootstrap,

    para hacerlo podemos descargarlo e incluirlo en nuestro proyecto o simplemente

    referenciar al CDN, esto ltimo es lo que haremos nosotros. Editamos el fichero

    ./templates/base.html para dejarlo de la siguiente forma.

    Album

    Toggle navigation

    Album

    38

  • Tuto

    rial D

    jang

    o

    Category(current) Photo

    Action

    Upload

    Log In

    {% block section %} {% endblock section %}

    {% block maincontent %} {% endblock maincontent %}

    Tambin hemos aadido una barra de navegacin como men principal, que est

    bajo el comentario . Vemos que las etiquetas que estbamos usando

    hasta ahora tienen clases del tipo collapse o navbar-header, stas son clases

    propias de Bootstrap. Si refrescamos nuestra aplicacin en el navegador veremos

    que ha cambiado la fuente, el color del texto y nuestro men principal.

    39

  • Tuto

    rial D

    jang

    o

    Para ver con ms detalle lo que nos ofrece Bootstrap vamos a construir nuestra

    plantilla de fotos ./album/templates/photo_list.html. Partimos de esta plantilla

    {% extends 'base.html' %}

    {% load static %}

    {% block section %} Photo {% endblock section %}

    {% block maincontent %} {{ object_list }} {% endblock maincontent %}

    y sobre ella vamos a incluir el sistema de grid de Bootstrap para dejarla as.

    {% extends 'base.html' %}

    {% load static %}

    {% block section %} Photo {% endblock section %}

    {% block maincontent %}

    {{ object_list }}

    {% endblock maincontent %}

    40

  • Tuto

    rial D

    jang

    o

    Aqu lo importante est en las etiquetas div, vemos tres tipos de clases, row,

    col-md-6 y well.

    row: Siempre tiene que estar incluida en una clase container, en nuestro caso en

    ./templates/base.html. Se usa para organizar grupos de columnas.

    col-md-6: Con esta clase creamos una columna (col-), adaptada a terminales

    medianos (col-md-), de tamao 6 (col-md-6); debemos saber que Bootstrap divide el

    terminal en doce unidades, por tanto nuestra columna ocupar la mitad del terminal

    siempre que este sea mediano o grande, en terminales pequeos como tablets o

    mviles ocupar el total del terminal. De igual forma podramos incluir una columna

    de dos unidades, adaptada a terminales pequeos y separada una unidad del

    margen izquierdo agrupando las clases .col-xs-2 y .col-xs-offset-1 o usar columnas

    de tamao 3 para terminales medianos y tamao 7 para terminales pequeos

    agrupando .col-sm-7 .col-md-3

    well: Simplemente pone el fondo de nuestras etiquetas div en un tono ms oscuro.

    Para verlo en accin solo tenemos que refrescar la pantalla y veremos esto en

    nuestro porttil.

    Vemos que la columna ocupa la mitad del espacio de la fila que la contiene, y

    nuestro men aparece tal y como lo dejamos.

    Esto sera lo que veramos en un mvil

    41

  • Tuto

    rial D

    jang

    o

    Ahora vemos que la columna ocupa todo el espacio dentro de la fila, adems el

    men ha cambiado, como no hay espacio suficiente para mostrar todas las

    opciones con claridad ahora aparece un desplegable a la derecha.

    Con esto podemos dejar la lista de fotos de nuestro lbum de la siguiente forma.

    {% extends 'base.html' %}

    {% load static %}

    {% block section %} Photo

    42

  • Tuto

    rial D

    jang

    o

    {% endblock section %}

    {% block maincontent %}

    {% for p in object_list.all %}

    {{ p.title }}

    {% if p.comment %} {{ p.comment }}

    {% else %} edit

    comments {% endif %}

    {% endfor %}

    {% endblock maincontent %}

    Donde tambin hemos usado Panels, uno de los componentes de Bootstrap.

    43

  • Tuto

    rial D

    jang

    o

    Como habis podido ver, este framework nos est facilitando mucho las cosas y hay

    que tener en cuenta que lo que hemos visto es una mnima parte de lo que nos

    ofrece, os animo a que lo exploris a fondo.

    Con esto podemos ver los cambios que tiene Git identificados respecto a la ltima

    versin que tenemos en el repositorio local.

    (tutorial)openwebinars@~/aplicaciones/myapps: git status En la rama master Your branch is up-to-date with 'origin/master'.

    Cambios no preparados para el commit: (use git add ... para actualizar lo que se ejecutar) (use git checkout -- ... para descartar cambios en le directorio de trabajo)

    modificado: album/templates/album/photo_list.html modificado: templates/base.html

    no hay cambios agregados al commit (use git add o git commit -a) (tutorial)openwebinars@~/aplicaciones/myapps:

    Los aadimos para el siguiente commit, hacemos commit y lo volcamos al

    repositorio remoto.

    (tutorial)openwebinars@~/aplicaciones/myapps: git add . (tutorial)openwebinars@~/aplicaciones/myapps: git commit -m "Bootstrap" [master 77dadc0] Bootstrap 2 files changed, 75 insertions(+), 44 deletions(-) rewrite album/templates/album/photo_list.html (79%) (tutorial)openwebinars@~/aplicaciones/myapps: git push -u origin master Username for 'https://github.com': usuario Password for 'https://[email protected]': Counting objects: 15, done. Delta compression using up to 2 threads. Compressing objects: 100% (6/6), done. Writing objects: 100% (8/8), 1.45 KiB | 0 bytes/s, done. Total 8 (delta 4), reused 0 (delta 0) To https://github.com/usuario/my_album.git e300e4a..77dadc0 master -> master Branch master set up to track remote branch master from origin. (tutorial)openwebinars@~/aplicaciones/myapps:

    y podemos ver los cambios incluidos en el repositorio remoto.

    44

  • Tuto

    rial D

    jang

    o

    Hasta aqu hemos dado una vuelta por lo ms bsico de Bootstrap y Git, pero queda

    mucho para investigar y mejorar vuestro lbum experimentando.

    En el siguiente post veremos cmo mejorarlo an ms usando el trabajo de la

    comunidad Django.

    45

  • Tuto

    rial D

    jang

    o EnOpenWebinars.nettenemostodosestoscursosatuenteradisposicin

    LinuxLPIC-1Examen101

    LinuxLPIC-1Examen102

    NodeJS,ExpressJSyMongoDB

    AngularJSyTypeScript

    AppsmvilesconPhoneGap

    ServidoresVoIPconAsterisk

    DesarrolloFrontend

    Profesional

    VirtualizacindeServidorescon

    Promox

    AppsMvilesconTitaniumAlloy

    DesarrolloBackendcon

    Django