Taller básico de Django

¿Quienes somos?

DjangoQuilla es una comunidad de desarrolladores de django, emprendedores y estudiantes y entusiastas de Python y Django.

Nos reunimos 1 vez al mes en ÁreaDos.

Requisitos para el taller

  • Python
  • Virtualenv y virtualenwrapper
  • Git
  • Crear cuenta en GitHub
  • Editor de texto (Sublime Text, Atom)

Contenido del taller

  1. Introducción a Python
  2. ¿Qué es Django?
  3. Instalando Django
  4. Primer proyecto
  5. Modelos
  6. Administrador
  7. Despliegue
  8. URLs
  9. Vistas

10. ORM de Django

11. Datos dinámicos en las plantillas

12. Plantillas

13. CSS

14. Extendiendo las plantillas

15. Extendiendo la app

16. Formularios

¿Qué es Django?

Imagen tomada de la presentación de David Whitton

¿Qué sucede cuando solicitan una página web?

Imágen tomada de devcode

Instalación de Django

mkdir tutorial-blog
cd tutorial-blog

# Para los que tienen instalado virtualenvwrapper
mkvirtualenv env-blog
workon env-blog

pip install django==1.9.7

Primer proyecto de Django


django-admin startproject blogproject


# En el archivo settings.py

TIME_ZONE = 'America/Colombia'
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

# Correr en consola 

python manage.py migrate
python manage.py runserver

Modelos en Django

La programación orientada a objetos consiste que en lugar de escribir todo como una aburrida secuencia de instrucciones de programación podemos modelar cosas y definir cómo interactúan con las demás.

Entonces ¿Qué es un objeto? Es un conjunto de propiedades y acciones.

Imagen tomada de wikibooks

Objetos

Imagen tomada de csit

Gato
---------
color 
edad 
humor 
dueño 
ronronear() 
rasguñar() 
alimentarse(comida_de_gato) 

ComidaDeGato
----------
sabor

Modelos en Django

python manage.py startapp blog


blogproject
├── blogproject
|       __init__.py
|       settings.py
|       urls.py
|       wsgi.py
├── manage.py
└── blog
    ├── migrations
    |       __init__.py
    ├── __init__.py
    ├── admin.py
    ├── models.py
    ├── tests.py
    └── views.py

# Agrega la linea 'blog',
# En INSTALLED_APPS dentro del archivo settings.py

Creando el modelo Post

from django.db import models
from django.utils import timezone

class Post(models.Model):
    author = models.ForeignKey('auth.User')
    title = models.CharField(max_length=200)
    text = models.TextField()
    created_date = models.DateTimeField(
            default=timezone.now)
    published_date = models.DateTimeField(
            blank=True, null=True)

    def publish(self):
        self.published_date = timezone.now()
        self.save()

    def __str__(self):
        return self.title


# Luego creamos las tablas para el modelo
# Vamos a consola y corremos

python manage.py makemigrations blog
python manage.py migrate blog

Administrador de Django

# Vamos a abrir el archivo blog/admin.py 
# y reemplazar su contenido con esto:

from django.contrib import admin
from .models import Post

admin.site.register(Post)


# Luego corremos en consola

python manage.py runserver

# Vamos a esta direccion en el navegador
# http://127.0.0.1:8000/admin/

Si quieres saber más información del administrador ve a la documentación de Django

Expresiones Regulares

# Para no repetir URLs creamos patrones de ellas usando
# expresiones regulares

^ denota el principio del texto
$ denota el final del texto
\d representa un dígito
+ indica que el ítem anterior debería ser repetido por lo menos una vez
() para encerrar una parte del patrón


# Ejemplo

http://www.mysite.com/post/12345/

# Su expresión regular sería

^post/(\d+)/$

URLs de Django

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

urlpatterns = [
    url(r'^admin/', include(admin.site.urls)),
    url(r'', include('blog.urls')),
]

# Crea un nuevo archivo vacío en blog/urls.py
# y agrega estas 2 líneas

from django.conf.urls import include, url
from . import views

urlpatterns = [
    url(r'^$', views.post_list),
]

Parte 2

Creando repositorio de GIT

# Abre la consola y ve a la carpeta del blogproject, luego escribe

git init

# Registra tu nombre y tu correo con los siguientes comandos

git config --global user.name "Tu Nombre"
git config --global user.email tu@correo.com

# Creamos un archivo llamado .gitignore con el sgte contenido

*.pyc
__pycache__
myvenv
db.sqlite3
/static
.DS_Store

# Luego
git status
git add --all .
git commit -m "Primer commit del taller con Django Barranquilla

# Vamos a github, creamos el repositorio y añadimos el remoto
git remote add origin https://github.com/<tu-usuario-github>/blogproject.git
git push -u origin master


Vistas de Django

# Abre el archivo blog/views.py


from django.shortcuts import render


def post_list(request):
    return render(request, 'blog/post_list.html', {})


# Dentro de blog, crea una carpeta que se llame templates
# Dentro de templates, crea otra carpeta llamada blog
# Por ultimo crea un archivo llamado post_list.html

¿Qué es HTML?

HyperText significa que es un tipo de texto que soporta hipervínculos entre páginas. Markup significa que hemos tomado un documento y lo hemos marcado con código para decirle a algo (en este caso, un navegador) cómo interpretar la página. El código HTML está construido con etiquetas, cada una comenzando con < y terminando con >. Estas etiquetas de marcado son elementos.

Etiquetas HTML útiles



<h1>Un título</h1> - para tu título más importante

<h2>Un subtítulo</h2> - para el título del siguiente nivel

<h3>Un subsubtítulo</h3> - ... y así hasta <h6>

<em>texto</em> - pone en cursiva tu texto

<strong>texto</strong> - pone en negrita tu texto

<br /> - un salto de línea (no puedes colocar nada dentro de br)

<a href="https://djangoquilla.com">link</a> - crea un vínculo

<ul><li>primer elemento</li><li>segundo elemento</li></ul> - crea una lista

<div></div> - define una sección de la página

Plantilla HTML

<!DOCTYPE html>
<html>
    <head>
        <title>Django blog</title>
    </head>
    <body>
        <div>
            <h1><a href="">Django Blog</a></h1>
        </div>
        <div>
            <p>publicado el: 14.06.2014, 12:14</p>
            <h2><a href="">Mi primer artículo</a></h2>
            <p>Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis 
            vestibulum. Donec id elit non mi porta gravida at eget metus. Fusce dapibus,
             tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa
              justo sit amet risus.</p>
        </div>
        <div>
            <p>publicado el: 14.06.2014, 12:14</p>
            <h2><a href="">Mi segundo artículo</a></h2>
            <p>Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis
             vestibulum. Donec id elit non mi porta gravida at eget metus. Fusce dapibus,
              tellus ac cursus commodo, tortor mauris condimentum nibh, ut f.</p>
        </div>
    </body>
</html>

Recuerda actualizar tu repo

# Recuerda hacer commit de los cambios importantes que hayas hecho

git status
git add --all .
git status
git commit -m "Cambie el HTML del sitio web"
git push

Curso sugerido de GIT básico

ORM de Django

python manage.py shell

# Todos los objetos
Post.objects.all()
from blog.models import Post

# Crear objetos
Post.objects.create(author=me, title='Sample title', text='Test')
from django.contrib.auth.models import User
User.objects.all()
me = User.objects.get(username='Bruce')
Post.objects.create(author=me, title='Sample title', text='Test')
Post.objects.all()

# Añade 2 ó 3 posts más y avanza a la siguiente parte.

# Filtrar objetos
Post.objects.filter(author=me)
Post.objects.filter(title__contains='title')

# Publicando un post
from django.utils import timezone
Post.objects.filter(published_date__lte=timezone.now())
post = Post.objects.get(id=1)
post.publish()

Datos dinámicos en plantillas

# Finalmente nuestro archivo blog/views.py debería verse así:

from django.shortcuts import render
from django.utils import timezone
from .models import Post

def post_list(request):
    posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
    return render(request, 'blog/post_list.html', {'posts': posts})

Si quieres leer un poco más acerca de QuerySets en Django, puedes darle un vistazo a la documentación

Plantillas de Django

# Variable
{{ posts }}

# Bucle for

{% for post in posts %}
    {{ post }}
{% endfor %}

# Así debe quedar la plantilla post_list.html

<div>
    <h1><a href="/">Django Blog</a></h1>
</div>

{% for post in posts %}
    <div>
        <p>publicado el: {{ post.published_date }}</p>
        <h1><a href="">{{ post.title }}</a></h1>
        <p>{{ post.text|linebreaks }}</p>
    </div>
{% endfor %}

Actualiza tu repo

git status
git add --all .
git status
git commit -m "Modifiqué las plantillas para mostrar artículos de la base de datos"
git push

¿Qué es CSS?

CSS (Cascading Style Sheets, que significa 'hojas de estilo en cascada') es un lenguaje utilizado para describir el aspecto y el formato de un sitio web escrito en lenguaje de marcado (como HTML). Trátalo como maquillaje para nuestra página web

Instalación de Bootstrap

# Agrega estas lineas dentro del <head> de tu archivo .html

<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">


# Crea una carpeta static dentro de la aplicación blog

# Crea una carpeta llamada css dentro de static y dentro de ella 
# un archivo que se llave blog.css

# En tu archivo blog/static/css/blog.css deberías añadir el siguiente código

h1 a {
    color: #FCA205;
}

# Abre el archivo post_list.html y añade esta linea justo al principio

{% load staticfiles %}

# Luego, entre el <head> y </head>, después de los enlaces a los archivos CSS de Bootstrap

<link rel="stylesheet" href="{% static 'css/blog.css' %}">

Nueva tipografía y clases

# Añande a blog.css
body {
    padding-left: 15px;
}

# Nueva tipografía al título. Añade en el head de post_list.html
<link href="http://fonts.googleapis.com/css?family=Lobster&subset=latin,latin-ext" rel="stylesheet" type="text/css">

# Ahora añadiremos la la familia de la fuente a nuestro CSS
h1 a {
    color: #FCA205;
    font-family: 'Lobster';
}

# Añadiremos una clase llamada page-header al div del encabezado
<div class="page-header">
    <h1><a href="/">Django Girls Blog</a></h1>
</div>

# Añade la clase post al div que contiene una entrada del blog
<div class="post">
    <p>published: {{ post.published_date }}</p>
    <h1><a href="">{{ post.title }}</a></h1>
    <p>{{ post.text|linebreaks }}</p>
</div>

Más clases CSS

.page-header {
    background-color: #ff9400;
    margin-top: 0;
    padding: 20px 20px 20px 40px;
}

.page-header h1, .page-header h1 a, .page-header h1 a:visited, .page-header h1 a:active {
    color: #ffffff;
    font-size: 36pt;
    text-decoration: none;
}

.content {
    margin-left: 40px;
}

h1, h2, h3, h4 {
    font-family: 'Lobster', cursive;
}

.date {
    float: right;
    color: #828282;
}

.save {
    float: right;
}

.post-form textarea, .post-form input {
    width: 100%;
}

.top-menu, .top-menu:hover, .top-menu:visited {
    color: #ffffff;
    float: right;
    font-size: 26pt;
    margin-right: 20px;
}

.post {
    margin-bottom: 70px;
}

.post h1 a, .post h1 a:visited {
    color: #000000;
}

Agregando un contenedor

# Agregamos unos div mas rodeando las etiquetas for, así:


<div class="content container">
    <div class="row">
        <div class="col-md-8">
            {% for post in posts %}
                <div class="post">
                    <div class="date">
                        {{ post.published_date }}
                    </div>
                    <h1><a href="">{{ post.title }}</a></h1>
                    <p>{{ post.text|linebreaks }}</p>
                </div>
            {% endfor %}
        </div>
    </div>
</div>

Extender plantillas

# Vamos a crear un archivo base.html en blog/templates/blog/

blog
└───templates
    └───blog
            base.html
            post_list.html


# Luego ábrelo y copia todo lo que hay en post_list.html al archivo base.html
# Asegurate de pegar esta linea al inicio
{% load staticfiles %}

# Luego, en base.html reemplaza por completo tu <body> con esto:

<body>
    <div class="page-header">
        <h1><a href="/">Django Girls Blog</a></h1>
    </div>
    <div class="content container">
        <div class="row">
            <div class="col-md-8">
            {% block content %}
            {% endblock %}
            </div>
        </div>
    </div>
</body>

Extender plantillas

# Abre tu archivo blog/templates/blog/post_list.html
# Elimina todo lo que no esté dentro del body

{% for post in posts %}


    <div class="post">
        <div class="date">
            {{ post.published_date }}
        </div>
        <h1><a href="">{{ post.title }}</a></h1>
        <p>{{ post.text|linebreaks }}</p>
    </div>

{% endfor %}

# Agrega esta linea al inicio del archivo

{% extends 'blog/base.html' %}


# Coloca todo entre {% block content %} y {% endblock content %}

Creando enlaces y vista detalle

# Agregamos una etiqueta <a> alrededor del <h1>
<h1><a href="{% url 'blog.views.post_detail' pk=post.pk %}">{{ post.title }}</a></h1>

# Agregamos esta linea al archivo blog/urls.py
url(r'^post/(?P<pk>[0-9]+)/$', views.post_detail),

# Crea la vista en el archivo blog/views.py

from django.shortcuts import render, get_object_or_404
def post_detail(request, pk):
    post = get_object_or_404(Post, pk=pk)
    return render(request, 'blog/post_detail.html', {'post': post})

# Crea la plantilla para post_detail.py

{% extends 'blog/base.html' %}
{% block content %}
    <div class="post">
        {% if post.published_date %}
            <div class="date">
                {{ post.published_date }}
            </div>
        {% endif %}
        <h1>{{ post.title }}</h1>
        <p>{{ post.text|linebreaks }}</p>
    </div>
{% endblock %}

Actualiza tu repo

git status
git add --all .
git status
git commit -m "Agregué la vista y la plantilla para el detalle de un artículo, así como el CSS del sitio."
git push

Formularios en Django 1

# Creamos el archivo forms.py dentro de la carpeta de blog

# Pega las sgtes lines en el archivo forms.py

from django import forms
from .models import Post

class PostForm(forms.ModelForm):

    class Meta:
        model = Post
        fields = ('title', 'text',)

# Abre base.html para agregar un enlace en el div llamado page-header

<a href="{% url 'blog.views.post_new' %}" class="top-menu">
  <span class="glyphicon glyphicon-plus">
  </span>
</a>

# Luego creamos una la nueva URL en urls.py

url(r'^post/new/$', views.post_new, name='post_new'),

Formularios en Django 2

# Abre el archivo blog/views.py

from .forms import PostForm

def post_new(request):
    form = PostForm()
    return render(request, 'blog/post_edit.html', {'form': form})

# Creamos el archivo post_edit.html

{% extends 'blog/base.html' %}

{% block content %}
    <h1>New post</h1>
    <form method="POST" class="post-form">{% csrf_token %}
        {{ form.as_p }}
        <button type="submit" class="save btn btn-default">Save</button>
    </form>
{% endblock %}

# Abre tu navegador y prueba que aparezca el formulario

Formularios en Django 3

# Guardando desde el formulario

from .forms import PostForm
from django.shortcuts import redirect

def post_new(request):
    if request.method == "POST":
        form = PostForm(request.POST)
        if form.is_valid():
            post = form.save(commit=False)
            post.author = request.user
            post.published_date = timezone.now()
            post.save()
            return redirect('blog.views.post_detail', pk=post.pk)
    else:
        form = PostForm()
    return render(request, 'blog/post_edit.html', {'form': form})

# Comprueba que funcione. Debe crear un nuevo post y luego redireccionar
# a la pagina post_detail

Formularios en Django 4

# Editando desde el formulario
# Agrega esta url en tu archivo post_detail.html dentro del if post.published_date

<a class="btn btn-default" href="{% url 'post_edit' pk=post.pk %}">
  <span class="glyphicon glyphicon-pencil">
  </span>
</a>

# Agrega la url en blog/urls.py

url(r'^post/(?P<pk>[0-9]+)/edit/$', views.post_edit, name='post_edit'),

#Abramos el archivo blog/views.py y añadamos al final esto

def post_edit(request, pk):
    post = get_object_or_404(Post, pk=pk)
    if request.method == "POST":
        form = PostForm(request.POST, instance=post)
        if form.is_valid():
            post = form.save(commit=False)
            post.author = request.user
            post.save()
            return redirect('blog.views.post_detail', pk=post.pk)
    else:
        form = PostForm(instance=post)
    return render(request, 'blog/post_edit.html', {'form': form})

Algo de seguridad


# Ahora mismo cualquiera puede crear un artículo. Hagamos que el botón de crear solo aparezca para ti
# Busca el enlace que crea nuevos post y coloca este bloque if alrededor de el


{% if user.is_authenticated %}
    <a href="{% url 'post_new' %}" class="top-menu">
        <span class="glyphicon glyphicon-plus">
        </span>
    </a>
{% endif %}


# Repite lo mismo para el enlace que permite editarlos

{% if user.is_authenticated %}
    <a class="btn btn-default" href="{% url 'post_edit' pk=post.pk %}">
        <span class="glyphicon glyphicon-pencil">
        </span>
    </a>
{% endif %}

Actualiza tu repo

git status
git add --all .
git status
git commit -m "Agregué vistas para crear/editar artículos del blog dentro del sitio web."
git push

¿Qué sigue?

Mantente en contacto

Síguenos en:

 

twitter:          @djangoquilla

facebook:        djangoquilla

web:                 http://djangoquilla.com/

Slack:   

https://django-python-quilla.slack.com/signup

Made with Slides.com