Professional Documents
Culture Documents
Tutorial Django
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
Tutorial Django
openwebinars@~/aplicaciones: pip
showvirtualenvwrapper
--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
intutorial/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.
Tutorial Django
(tutorial)openwebinars
@~/aplicaciones: pip install Django==1.7, Pillow
Downloading/unpacking Django==
1.7
Downloading Django-
1.7
-py2.py3-none-any.whl (
7.4
MB):
7.4
MB downloaded
Downloading/unpacking Pillow
Downloading Pillow-
2.6.1
.tar.gz (
7.3
MB):
7.3
MB 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:
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
Tutorial Django
__init__.py
models.py
tests.py
views.py
1directory,
6files
(tutorial)openwebinars@~
/aplicaciones/my
apps:
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'
,
)
DATABASES = {
'default'
:{
'ENGINE'
:
'django.db.backends.sqlite3'
,
'NAME'
: os.path.
join
(BASE_DIR,
'db.sqlite3'
),
}
}
Tutorial Django
aqu puedes
Y por ltimo establecemos la zona horaria en la que nos encontramos,
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/my
apps: 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/my
apps:
(tutorial)openwebinars@~/aplicaciones/myapps: ll -rt
total
56
-rwxrwxr-
x
1jose jose
249
oct
21
20
:
24manage.py*
drwxrwxrwx
4jose jose
4096
oct
22
19
:
43../
drwxrwxr-
x
2jose jose
4096
oct
22
20
:
22myapps/
drwxrwxr-
x
3jose jose
4096
oct
22
20
:
22album/
-rw-r--r--
1jose jose
36864
oct
22
20
:
22db.sqlite3
drwxrwxr-
x
4jose jose
4096
oct
22
20
:
22./
(tutorial)openwebinars@~/aplicaciones/myapps:
Tutorial Django
(tutorial)openwebinars
@~/aplicaciones/myapps: python manage.py createsuperuser
Username (leave blank to use
'administrador'
): admin
Email address: admin
@admin.com
Password: *****
Password (again): *****
Superuser created successfully.
(tutorial)openwebinars
@~/aplicaciones/myapps:
Tutorial Django
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.
Tutorial Django
__init__.py
models.py
tests.py
views.py
1directory,
6files
(tutorial)openwebinars@~
/aplicaciones/my
apps:
fromdjango.db
importmodels
classCategory(models.Model):
""" Categorias para clasificar las fotos """
name = models.CharField(max_length=
50
)
def
__unicode__
(self)
:
returnself.name
Tutorial Django
classPhoto(models.Model):
""" Fotos del album """
__unicode__
(self)
:
returnself.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.
Tutorial Django
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/my
apps: python manage.py makemigrations
Migrations
for
'album'
:
0001
_initial.py:
- Create model Category
- Create model Photo
(tutorial)openwebinars@~
/aplicaciones/my
apps:
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/my
apps: 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/my
apps:
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/'
)
(
tutorial
)
openwebinars
@
~/aplicaciones/myapps:python manage.py shell
from album.models import Category, Photo
from django.core.files import File
10
Tutorial Django
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
11
Tutorial Django
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
Tutorial Django
instance.photo.delete(
False
)
13
Tutorial Django
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
fromdjango.http
importHttpResponse
def
first_view
(request)
:
returnHttpResponse(
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.
fromdjango.conf.urls
importpatterns, include, url
fromdjango.contrib
importadmin
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
Tutorial Django
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.
fromdjango.conf.urls
importpatterns, include, url
fromdjango.contrib
importadmin
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.
fromdjango.conf.urls
importpatterns, url
fromalbum
importviews
urlpatterns = patterns(
''
,
url(
r'^$'
, views.first_view, name=
'first-view'
),
)
15
Tutorial Django
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
{{ object_list }}
16
Tutorial Django
'album/category.html'
, context)
buscamos
la
nueva
direccin
en
el
navegador,
http://127.0.0.1:8000/album/category/
17
Tutorial Django
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}
returnrender(request,
'album/category_detail.html'
, context)
18
Tutorial Django
fromdjango.conf.urls
importpatterns, url
fromalbum
importviews
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'
),
)
en el
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.
fromdjango.views.generic
importListView, DetailView
classPhotoListView(ListView):
model = Photo
classPhotoDetailView(DetailView):
model = Photo
Como podemos ver solamente tenemos que decirle sobre que modelo queremos
trabajar.
19
Tutorial Django
paraListView
DetailView
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.
fromdjango.conf.urls
importpatterns, url
fromalbum
importviews
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
Tutorial Django
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.
21
Tutorial Django
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:
<
h1
>ALBUM</
h1
>
<
h2
>Category</
h2
>
<
div
>
{% for c in object_list %}
<
a
href
=
"{% url 'category-detail' c.pk %}"
>
{{ c.name }}
</
a
>
{% endfor %}
</
div
>
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
Tutorial Django
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 %}
<
h2
>Category</
h2
>
<
hr
>
{% endblock section %}
{% block maincontent %}
<
div
>
{% for c in object_list %}
<
a
href
=
"{% url 'category-detail' c.pk %}"
>
{{ c.name }}
</
a
>
{% endfor %}
</
div
>
{% 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
Tutorial Django
<!DOCTYPE html>
<
html
>
<
head
lang
=
"en"
>
<
meta
charset
=
"UTF-8"
>
<
title
>Album</
title
>
</
head
>
<
body
>
<
h1
>Album</
h1
>
<
ul
>
<
li
>
<
a
href
=
"{% url 'category-list' %}"
>Category</
a
>
</
li
>
<
li
>
<
a
href
=
"{% url 'photo-list' %}"
>Photo</
a
>
</
li
>
</
ul
>
<
hr
>
<
div
>
{% block section %}
{% endblock section %}
</
div
>
<
div
>
{% block maincontent %}
{% endblock maincontent %}
</
div
>
</
body
>
</
html
>
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
Tutorial Django
EnOpenWebinars.nettenemostodosestos
cursosatuenteradisposicin
LinuxLPIC-1
Examen101
LinuxLPIC-1
Examen102
NodeJS,
ExpressJSy
MongoDB
AngularJSy
TypeScript
Appsmvilescon
PhoneGap
ServidoresVoIP
conAsterisk
Desarrollo
Frontend
Profesional
Virtualizacinde
Servidorescon
Promox
AppsMvilescon
TitaniumAlloy
Desarrollo
Backendcon
Django
Tutorial Django
fromdjango.shortcuts
importrender
def
base
(request)
:
returnrender(request,
'base.html'
)
y en ./album/urls.py:
fromdjango.conf.urls
importpatterns, url
fromalbum
importviews
urlpatterns = patterns(
''
,
url(
r'^$'
, views.base, name=
'base'
),
url(
r'^category/$'
, views.CategoryListView.as_view(),
name=
'category-list'
),
url(
r'^category/(?P<pk>\d+)/detail/$'
,
views.CategoryDetailView.as_view(),
name=
'category-detail'
),
url(
r'^photo/$'
, views.PhotoListView.as_view(),
name=
'photo-list'
),
url(
r'^photo/(?P<pk>\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/'
),
)
25
Tutorial Django
y http://127.0.0.1:8000/album/category/
26
Tutorial Django
{% extends 'base.html' %}
{% load static %}
{% block section %}
<
h2
>{{ object.name }}</
h2
>
<
hr
>
{% endblock section %}
{% block maincontent %}
<
div
>
<
table
border
=
"1px"
>
<
tr
>
{% for p in object.photo_set.all %}
<
td
>
<
div
>{{ p.title }}</
div
>
<
div
>
<
a
href
=
"{% url "photo-detail"
p.id%}">
<
img
src
=
"{% static p.photo.url %}"
style
=
"width:200px;height:200px"
/>
</
a
>
</
div
>
</
td
>
{% endfor %}
</
tr
>
27
Tutorial Django
</
table
>
</
div
>
{% 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 %}
<
h2
>
{{ object.title }}
{% if object.favorite %}
★
{% else %}
☆
{% endif %}
{% if object.category_id %}
( <
a
href
=
"{% url "category-detail"
object.category_id%}">{{
object.category }}</
a
>)
{% endif %}
</
h2
>
<
p
><
strong
>comments: </
strong
>{{ object.comment|default:"no comments" }}</
p
>
<
a
href
=
"{% url "photo-update"
object.id%}">edit</
a
>
<
a
href
=
"{% url "photo-delete"
object.id%}">delete</
a
>
<
hr
>
{% endblock section %}
{% block maincontent %}
<
div
>
<
div
>
<
img
src
=
"{% static object.photo.url %}"
style
=
"width:550px;height:420px"
/>
</
div
>
28
Tutorial Django
</
div
>
{% 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.
fromdjango.core.urlresolvers
importreverse_lazy
fromdjango.views.generic.edit
importUpdateView, CreateView, DeleteView
classPhotoUpdate(UpdateView):
model = Photo
classPhotoCreate(CreateView):
model = Photo
classPhotoDelete(DeleteView):
model = Photo
success_url = reverse_lazy(
'photo-list'
)
29
Tutorial Django
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 %}
<
form
enctype
=
"multipart/form-data"
method
=
"post"
>{% csrf_token %}
{{ form.as_p }}
<
button
type
=
"submit"
>Save</
button
>
<
a
class
=
'btn'
href
=
"{% url 'photo-list' %}"
>Cancel</
a
>
</
form
>
{% endblock maincontent%}
30
Tutorial Django
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)
:
returnreverse(
'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:
31
Tutorial Django
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.
{% extends 'base.html' %}
32
Tutorial Django
{% block maincontent %}
<
form
action
=
""
method
=
"post"
>{% csrf_token %}
<
p
>Delete "{{ object.title }}"?</
p
>
<
input
type
=
"submit"
value
=
"Confirm"/>
<
a
class
=
'btn'
href
=
"{% url 'photo-list' %}"
>Cancel</
a
>
</
form
>
{% 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.
33
Tutorial Django
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
<nombre> 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
Tutorial Django
(tutorial)openwebinars@~
/aplicaciones/my
apps: cat .gitignore
*.jpg
*.pyc
.idea
db.sqlite3
(tutorial)openwebinars@~
/aplicaciones/my
apps:
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/my
apps: git add .
(tutorial)openwebinars@~
/aplicaciones/my
apps: git status
En la rama master
Commit inicial
Cambios para hacer commit:
(use git rm --cached <archivo>... para eliminar stage)
newfile:
newfile:
newfile:
.gitignore
album/__init__.py
album/admin.py
35
Tutorial Django
newfile:
newfile:
newfile:
newfile:
newfile:
newfile:
newfile:
newfile:
newfile:
newfile:
newfile:
newfile:
newfile:
newfile:
newfile:
newfile:
newfile:
newfile:
album/migrations/
0001
_initial.py
album/migrations/__init__.py
album/models.py
album/templates/album/category_detail.html
album/templates/album/category_list.html
album/templates/album/photo_confirm_delete.html
album/templates/album/photo_detail.html
album/templates/album/photo_form.html
album/templates/album/photo_list.html
album/tests.py
album/urls.py
album/views.py
manage.py
myapps/__init__.py
myapps/settings.py
myapps/urls.py
myapps/wsgi.py
templates/base.html
(tutorial)openwebinars@~
/aplicaciones/my
apps:
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
21files
changed
,
439insertions(+)
create
mode
100644.gitignore
create
mode
100644album/__init__.py
create
mode
100644album/admin.py
create
mode
100644album/migrations/
0001
_initial.py
create
mode
100644album/migrations/__init__.py
create
mode
100644album/models.py
create
mode
100644album/templates/album/category_detail.html
create
mode
100644album/templates/album/category_list.html
create
mode
100644album/templates/album/photo_confirm_delete.html
create
mode
100644album/templates/album/photo_detail.html
create
mode
100644album/templates/album/photo_form.html
create
mode
100644album/templates/album/photo_list.html
create
mode
100644album/tests.py
create
mode
100644album/urls.py
create
mode
100644album/views.py
create
mode
100755manage.py
create
mode
100644myapps/__init__.py
create
mode
100644myapps/settings.py
create
mode
100644myapps/urls.py
create
mode
100644myapps/wsgi.py
create
mode
100644templates/base.html
(tutorial)openwebinars@~/aplicaciones/myapps:
36
Tutorial Django
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
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
Tutorial Django
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.
<!DOCTYPE html>
<
html
>
<
head
lang
=
"en"
>
<
meta
charset
=
"UTF-8"
>
<
title
>Album</
title
>
<!-- CDN Bootstrap -->
<
link
rel
=
"stylesheet"
href
=
"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css"
>
<
link
rel
=
"stylesheet"
href
=
"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap-theme.min.css
"
>
<
script
src
=
"https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"
></
script
>
<
script
src
=
"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js"
></
scrip
t
>
</
head
>
<
body
>
<!-- NavBar -->
<
nav
class
=
"navbar navbar-default"
>
<
div
class
=
"container-fluid"
>
<
div
class
=
"navbar-header"
>
<
button
type
=
"button"
class
=
"navbar-toggle collapsed"
data-toggle
=
"collapse"
data-target
=
"#bs-example-navbar-collapse-1"
>
<
span
class
=
"sr-only"
>Toggle navigation</
span
>
<
span
class
=
"icon-bar"
></
span
>
<
span
class
=
"icon-bar"
></
span
>
<
span
class
=
"icon-bar"
></
span
>
</
button
>
<
a
class
=
"navbar-brand"
href
=
"{% url "base"%}">Album</
a
>
</
div
>
38
Tutorial Django
<
div
class
=
"collapse navbar-collapse"
id
=
"bs-example-navbar-collapse-1"
>
<
ul
class
=
"nav navbar-nav"
>
<
li
><
a
href
=
"{% url "category-list"%}">Category<
span
class
=
"sr-only"
>(current)</
span
></
a
></
li
>
<
li
><
a
href
=
"{% url "photo-list"%}">Photo</
a
></
li
>
</
ul
>
<
ul
class
=
"nav navbar-nav navbar-right"
>
<
li
class
=
"dropdown"
>
<
a
href
=
"#"
class
=
"dropdown-toggle"
data-toggle
=
"dropdown"
role
=
"button"
aria-expanded
=
"false"
>Action
<
span
class
=
"caret"
></
span
>
</
a
>
<
ul
class
=
"dropdown-menu"
role
=
"menu"
>
<
li
><
a
href
=
"{% url "photo-create"
%}">Upload</
a
></
li
>
<
li
class
=
"divider"
></
li
>
<
li
><
a
href
=
"#"
>Log In</
a
></
li
>
</
ul
>
</
li
>
</
ul
>
</
div
>
</
div
>
</
nav
>
<
div
class
=
"container"
>
{% block section %}
{% endblock section %}
</
div
>
<
div
class
=
"container"
>
{% block maincontent %}
{% endblock maincontent %}
</
div
>
</
body
>
</
html
>
39
Tutorial Django
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 %}
<
h2
>Photo</
h2
>
<
hr
>
{% endblock section %}
{% block maincontent %}
{{ object_list }}
{% endblock maincontent %}
rid
y sobre ella vamos a incluir el sistema de g
de Bootstrap para dejarla as.
{% extends 'base.html' %}
{% load static %}
{% block section %}
<
h2
>Photo</
h2
>
<
hr
>
{% endblock section %}
{% block maincontent %}
<
div
class
=
"row well"
>
<
div
class
=
"col-md-6 well"
>
{{ object_list }}
</
div
>
</
div
>
{% endblock maincontent %}
40
Tutorial Django
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
Tutorial Django
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 %}
<
h2
>Photo</
h2
>
42
Tutorial Django
<
hr
>
{% endblock section %}
{% block maincontent %}
<
div
class
=
"row well"
>
{% for p in object_list.all %}
<
div
class
=
"col-md-4 well"
>
<
div
class
=
"panel panel-primary"
>
<
div
class
=
"panel-heading"
>
<
h3
class
=
"panel-title"
>{{ p.title }}</
h3
>
</
div
>
<
div
class
=
"panel-body"
>
<
a
href
=
"{% url "photo-detail"
p.id%}">
<
img
src
=
"{% static p.photo.url %}"
style
=
"width:200px;height:200px;"
/>
</
a
>
</
div
>
<
div
class
=
"panel-footer"
>
{% if p.comment %}
{{ p.comment }}
{% else %}
<
a
href
=
"{% url "photo-update"
p.id%}">edit
comments</
a
>
{% endif %}
</
div
>
</
div
>
</
div
>
{% endfor %}
</
div
>
{% endblock maincontent %}
43
Tutorial Django
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.
changed
,
75insertions(+),
44deletions(-)
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://usuario@github.com'
:
Counting objects:
15
, done.
Delta compression
usingup
to
2threads.
Compressing objects:
100
% (
6
/
6
), done.
Writing objects:
100
% (
8
/
8
),
1.45KiB |
0bytes/s, done.
Total
8(delta
4
), reused
0(delta
0
)
Tohttps://github.com/usuario/my_album.git
e300e4a.
.77
dadc0
master->
master
Branch
master
setup
totrack remote branch
master
fromorigin.
(tutorial)openwebinars@~/aplicaciones/myapps:
44
Tutorial Django
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
Tutorial Django
EnOpenWebinars.nettenemostodosestos
cursosatuenteradisposicin
LinuxLPIC-1
Examen101
LinuxLPIC-1
Examen102
NodeJS,
ExpressJSy
MongoDB
AngularJSy
TypeScript
Appsmvilescon
PhoneGap
ServidoresVoIP
conAsterisk
Desarrollo
Frontend
Profesional
Virtualizacinde
Servidorescon
Promox
AppsMvilescon
TitaniumAlloy
Desarrollo
Backendcon
Django