pip install django
django-admin startproject mysite
cd mysite
python manage.py startapp blog
Comandos comunes
runserver
Iniciar servidor de desarrollo en el puerto 8000
makemigrations
Generar archivos de migración desde cambios en modelos
migrate
Aplicar migraciones a la base de datos
createsuperuser
Crear superusuario de administración
shell
Shell interactivo de Python con Django
test
Ejecutar suite de pruebas
Estructura del proyecto
manage.py
Punto de entrada de la CLI
settings.py
Configuración del proyecto
urls.py
Configuración de URLs raíz
wsgi.py / asgi.py
Puntos de entrada del servidor
apps/models.py
Modelos de base de datos
apps/views.py
Manejadores de solicitudes
Modelos
Definir un modelo
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=200)
body = models.TextField()
created = models.DateTimeField(auto_now_add=True)
published = models.BooleanField(default=False)
from django.views.generic import ListView, DetailView
class PostListView(ListView):
model = Post
template_name = 'blog/list.html'
context_object_name = 'posts'
paginate_by = 10
CBVs comunes
ListView
Mostrar lista de objetos
DetailView
Mostrar un solo objeto
CreateView
Formulario para crear objeto
UpdateView
Formulario para editar objeto
DeleteView
Confirmar y eliminar objeto
TemplateView
Renderizar plantilla (sin modelo)
Respuesta JSON
from django.http import JsonResponse
def api_posts(request):
data = list(Post.objects.values('id', 'title'))
return JsonResponse(data, safe=False)
Plantillas
Sintaxis de plantilla
{{ variable }}
{{ post.title|truncatewords:30 }}
{% if user.is_authenticated %}
from django.urls import path, include
urlpatterns = [
path('', views.index, name='index'),
path('post//', views.detail, name='detail'),
path('blog/', include('blog.urls')),
]
Conversores de path
<int:pk>
Entero (ej. 42)
<str:slug>
Cadena sin barras
<slug:slug>
Slug (letras, números, guiones)
<uuid:id>
Formato UUID
<path:rest>
Ruta completa incluyendo barras
URLs inversas
from django.urls import reverse
url = reverse('detail', kwargs={'pk': 1})
# En plantillas: {% url 'detail' pk=post.pk %}
Formularios
ModelForm
from django import forms
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['title', 'body', 'published']
Procesar formulario en vista
def create_post(request):
form = PostForm(request.POST or None)
if form.is_valid():
post = form.save(commit=False)
post.author = request.user
post.save()
return redirect('detail', pk=post.pk)
return render(request, 'blog/form.html', {'form': form})
Formulario en plantilla
Validación
def clean_title(self):
title = self.cleaned_data['title']
if len(title) < 5:
raise forms.ValidationError("Title too short.")
return title
Admin
Registrar modelo
from django.contrib import admin
from .models import Post
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
list_display = ['title', 'author', 'created', 'published']
list_filter = ['published', 'created']
search_fields = ['title', 'body']
Opciones de admin
list_display
Columnas en la vista de lista
list_filter
Opciones de filtro en la barra lateral
search_fields
Campos buscables
prepopulated_fields
Autocompletar (ej. slug desde título)
readonly_fields
No editables en el admin
ordering
Orden de clasificación por defecto
Consultas ORM
Consultas básicas
Post.objects.all() # todos los registros
Post.objects.get(pk=1) # único (lanza error si falta)
Post.objects.filter(published=True) # queryset
Post.objects.exclude(draft=True) # excluir coincidencias
Post.objects.count() # total de registros
Lookups de campo
field__exact
Coincidencia exacta (por defecto)
field__icontains
Contiene sin distinguir mayúsculas
field__gt / __lt
Mayor / menor que
field__gte / __lte
Mayor/menor o igual que
field__in=[1,2,3]
Valor en la lista
field__isnull=True
Es NULL
field__startswith
Empieza con cadena
field__range=(a,b)
Entre a y b inclusive
Encadenamiento y agregación
from django.db.models import Q, Count, Avg
Post.objects.filter(
Q(title__icontains='django') | Q(body__icontains='django')
).order_by('-created')[:10]
Post.objects.aggregate(avg_views=Avg('views'))
Crear, actualizar, eliminar
post = Post.objects.create(title='New', body='...')
post.title = 'Updated'
post.save()
Post.objects.filter(draft=True).update(published=False)
post.delete()
Autenticación
Login / Logout
from django.contrib.auth import authenticate, login, logout
user = authenticate(request, username='admin', password='pw')
if user is not None:
login(request, user)
Proteger vistas
from django.contrib.auth.decorators import login_required
@login_required
def dashboard(request):
return render(request, 'dashboard.html')