Django Es
Django Es
Django Es
#django
Tabla de contenido
Acerca de 1
Observaciones 2
Versiones 2
Examples 3
Comenzando un proyecto 3
Conceptos Django 5
Ambiente virtual 7
Python 3.3+ 7
Python 2 7
Dockerfile 11
Componer 11
Nginx 12
Uso 13
Examples 14
Capítulo 3: Administración 16
Examples 16
Lista de cambios 16
vistas.py 19
urls.py 19
forms.py 19
admin.py 20
Introducción 21
Examples 21
Capítulo 5: Ajustes 24
Examples 24
settings.py 25
Alternativa # 1 27
Alternativa # 2 27
Estructura 27
Sintaxis 31
Observaciones 31
Examples 31
Un ArrayField básico 31
Matrices de nidificación 32
Consultar a todos los modelos que contengan cualquier artículo en una lista con contenido 32
Examples 33
Introducción 34
Observaciones 34
Examples 34
Introducción 38
Examples 38
Examples 39
MySQL / MariaDB 39
PostgreSQL 40
sqlite 41
Accesorios 41
Examples 44
Observaciones 49
Examples 49
Examples 53
NGINX 56
GUNICORN 57
SUPERVISOR 57
Observaciones 60
Examples 60
Examples 61
Parámetros 63
Examples 64
Examples 70
Configuración de apio 70
APIO 70
Supervisor de carrera 71
Examples 74
Examples 76
Establecer el espacio de nombres de la URL para una aplicación reutilizable (Django 1.9+) 78
Examples 80
Examples 83
Filtros personalizados 83
Etiquetas simples 83
Examples 87
Examples 94
Examples 97
Modelo de usuario personalizado con correo electrónico como campo de inicio de sesión prin 97
Usa el `email` como nombre de usuario y deshazte del campo` username` 100
Amplíe el modelo de usuario de Django fácilmente 102
Introducción 107
Sintaxis 107
Examples 107
Examples 110
Examples 111
Examples 113
Sintaxis 119
Examples 119
Examples 121
Examples 125
Sintaxis 127
Examples 127
Configurando 127
settings.py 127
Sintaxis 134
Observaciones 134
Examples 134
Capítulo 34: Mapeo de cadenas a cadenas con HStoreField - un campo específico de PostgreSQ
137
Sintaxis 137
Examples 137
Observaciones 139
Examples 139
Introducción 140
Observaciones 140
Examples 140
Parámetros 144
Examples 144
Introducción 147
Parámetros 150
Observaciones 151
Examples 151
DateTimeField 154
Introducción 157
Examples 157
Herencia 167
Examples 168
Variables 168
Plantillas en vistas basadas en clase 169
resumen 171
Guía 172
Observaciones 174
Examples 174
Uso de un procesador de contexto para acceder a las entradas de blog más recientes en toda 175
Introducción 177
Examples 177
Introducción 178
Examples 178
Problema 179
Solución 180
Problema 181
Solución 182
Sintaxis 185
Examples 185
Examples 187
Examples 189
Parámetros 193
Observaciones 193
Examples 194
Observaciones 197
Examples 197
Ejemplo simple para sumar 2 números. 197
Examples 199
Problema 199
Solución 199
Observaciones 201
Examples 201
Observaciones 203
Examples 203
vistas.py 203
urls.py 203
vistas.py 204
libro.html 204
Introducción 211
Observaciones 211
Examples 211
Introducción 215
Examples 215
Creditos 218
Acerca de
You can share this PDF with anyone you feel could benefit from it, downloaded the latest version
from: django
It is an unofficial and free Django ebook created for educational purposes. All the content is
extracted from Stack Overflow Documentation, which is written by many hardworking individuals at
Stack Overflow. It is neither affiliated with Stack Overflow nor official Django.
The content is released under Creative Commons BY-SA, and the list of contributors to each
chapter are provided in the credits section at the end of this book. Images may be copyright of
their respective owners unless otherwise specified. All trademarks and registered trademarks are
the property of their respective company owners.
Use the content presented in this book at your own risk; it is not guaranteed to be correct nor
accurate, please send your feedback and corrections to [email protected]
https://riptutorial.com/es/home 1
Capítulo 1: Empezando con Django
Observaciones
Django se anuncia a sí mismo como "el marco web para perfeccionistas con fechas límite" y
"Django facilita la creación de mejores aplicaciones web más rápidamente y con menos código".
Puede verse como una arquitectura MVC. En su núcleo tiene:
Versiones
1.11 2017-04-04
1.10 2016-08-01
1.9 2015-12-01
1.8 2015-04-01
1.7 2014-09-02
1.6 2013-11-06
1.5 2013-02-26
1.4 2012-03-23
1.3 2011-03-23
https://riptutorial.com/es/home 2
Versión Fecha de lanzamiento
1.2 2010-05-17
1.1 2009-07-29
1.0 2008-09-03
Examples
Comenzando un proyecto
Django es un framework de desarrollo web basado en Python. Django 1.11 (la última versión
estable) requiere la instalación de Python 2.7 , 3.4 , 3.5 o 3.6 . Suponiendo que pip está
disponible, la instalación es tan simple como ejecutar el siguiente comando. Tenga en cuenta que
omitir la versión como se muestra a continuación instalará la última versión de django:
Para instalar una versión específica de django, supongamos que la versión es django 1.10.5 ,
ejecute el siguiente comando:
Las aplicaciones web creadas con Django deben residir dentro de un proyecto de Django. Puede
usar el comando django-admin para iniciar un nuevo proyecto en el directorio actual:
donde myproject es un nombre que identifica de forma única el proyecto y puede constar de
números , letras y guiones bajos .
myproject/
manage.py
myproject/
__init__.py
settings.py
urls.py
wsgi.py
$ cd myproject
$ python manage.py runserver
Ahora que el servidor está funcionando, visite http://127.0.0.1:8000/ con su navegador web.
https://riptutorial.com/es/home 3
Verás la siguiente página:
Si desea cambiar el puerto del servidor, páselo como un argumento de línea de comandos.
Tenga en cuenta que runserver es solo para compilaciones de depuración y pruebas locales. Los
programas de servidor especializados (como Apache) siempre deben usarse en producción.
Un proyecto de Django usualmente contiene múltiples apps . Esta es simplemente una forma de
estructurar su proyecto en módulos más pequeños y mantenibles. Para crear una aplicación, vaya
a su carpeta de proyecto (donde manage.py es), y ejecute el comando startapp (cambie myapp a lo
que quiera):
Esto generará la carpeta myapp y algunos archivos necesarios para usted, como models.py y
views.py .
# myproject/settings.py
# Application definition
INSTALLED_APPS = [
...
'myapp',
]
https://riptutorial.com/es/home 4
La estructura de carpetas de un proyecto de Django se puede cambiar para que se ajuste a sus
preferencias. A veces, la carpeta del proyecto cambia de nombre a /src para evitar repetir los
nombres de las carpetas. Una estructura de carpetas típica se ve así:
Conceptos Django
django-admin es una herramienta de línea de comandos que se envía con Django. Viene con
varios comandos útiles para comenzar y administrar un proyecto Django. El comando es el mismo
que ./manage.py , con la diferencia de que no es necesario que esté en el directorio del proyecto.
La variable de entorno DJANGO_SETTINGS_MODULE debe configurarse.
https://riptutorial.com/es/home 5
múltiples proyectos de Django.
El ORM de Django recopila todos los modelos de base de datos definidos en models.py y crea
tablas de base de datos basadas en esas clases de modelos. Para hacer esto, primero, configure
su base de datos modificando la configuración de DATABASES en settings.py . Luego, una vez que
haya definido sus modelos de base de datos , ejecute python manage.py makemigrations seguido de
python manage.py migrate para crear o actualizar el esquema de su base de datos según sus
modelos.
Eso creará una carpeta llamada hello que contendrá los siguientes archivos:
hello/
├── hello/
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── manage.py
Paso 3 Dentro del módulo de hello (la carpeta que contiene el __init.py__ ) cree un archivo
llamado views.py :
hello/
├── hello/
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ ├── views.py <- here
│ └── wsgi.py
└── manage.py
def hello(request):
return HttpResponse('Hello, World')
https://riptutorial.com/es/home 6
from django.conf.urls import url
from django.contrib import admin
from hello import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$', views.hello)
]
Paso 6
Hola Mundo
Ambiente virtual
Al configurar un entorno virtual diferente para cada proyecto en el que trabaja, varios proyectos de
Django pueden ejecutarse en diferentes versiones de Python y pueden mantener sus propios
conjuntos de dependencias, sin riesgo de conflicto.
Python 3.3+
Python 3.3+ ya incluye un módulo venv estándar, al que normalmente puedes llamar como pyvenv .
En entornos donde el comando pyvenv no está disponible, puede acceder a la misma
funcionalidad invocando directamente el módulo como python3 -m venv .
$ pyvenv <env-folder>
# Or, if pyvenv is not available
$ python3 -m venv <env-folder>
Python 2
Si usa Python 2, primero puede instalarlo como un módulo separado de pip:
https://riptutorial.com/es/home 7
$ pip install virtualenv
$ virtualenv <env-folder>
Linux como:
$ source <env-folder>/bin/activate
Windows como:
<env-folder>\Scripts\activate.bat
Esto cambia su indicador para indicar que el entorno virtual está activo. (<env-folder>) $
De ahora en adelante, todo lo que se instale usando pip se instalará en su carpeta de env virtual,
no en todo el sistema.
(<env-folder>) $ deactivate
# Create a virtualenv
mkvirtualenv my_virtualenv
# Activate a virtualenv
workon my_virtualenv
#!/bin/sh
# This hook is sourced after this virtualenv is activated
Cree un nuevo archivo llamado <env-folder>/.project . El contenido del archivo SOLO debe ser la
ruta del directorio del proyecto.
/path/to/project/directory
Ahora, inicie su entorno virtual (ya sea utilizando source <env-folder>/bin/activate workon
my_virtualenv o workon my_virtualenv ) y su terminal cambiará los directorios a
/path/to/project/directory .
Este ejemplo muestra una forma mínima de crear una página Hello World en Django. Esto le
ayudará a darse cuenta de que el comando de django-admin startproject example crea
https://riptutorial.com/es/home 9
básicamente un montón de carpetas y archivos y que no necesariamente necesita esa estructura
para ejecutar su proyecto.
import sys
settings.configure(
DEBUG=True,
SECRET_KEY='thisisthesecretkey',
ROOT_URLCONF=__name__,
MIDDLEWARE_CLASSES=(
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
),
)
def index(request):
return HttpResponse('Hello, World!')
urlpatterns = [
url(r'^$', index),
]
if __name__ == "__main__":
from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv)
3. Vaya a la terminal y ejecute el archivo con este comando python file.py runserver .
La plantilla de proyecto Django predeterminada está bien, pero una vez que implementas tu
código y, por ejemplo, los desarrolladores ponen sus manos en el proyecto, las cosas se
complican. Lo que puede hacer es separar su código fuente del resto que se requiere para estar
en su repositorio.
https://riptutorial.com/es/home 10
Estructura del proyecto
PROJECT_ROOT
├── devel.dockerfile
├── docker-compose.yml
├── nginx
│ └── project_name.conf
├── README.md
├── setup.py
└── src
├── manage.py
└── project_name
├── __init__.py
└── service
├── __init__.py
├── settings
│ ├── common.py
│ ├── development.py
│ ├── __init__.py
│ └── staging.py
├── urls.py
└── wsgi.py
Me gusta mantener el directorio de service denominado service para cada proyecto gracias a que
puedo usar el mismo Dockerfile en todos mis proyectos. La división de requisitos y
configuraciones ya está bien documentada aquí:
Usando múltiples archivos de requerimientos
Usando múltiples configuraciones
Dockerfile
Con el supuesto de que solo los desarrolladores hacen uso de Docker (no todos los
desarrolladores de operaciones confían en ello en estos días). Esto podría ser un entorno de
desarrollo devel.dockerfile :
FROM python:2.7
ENV PYTHONUNBUFFERED 1
WORKDIR /run/service/src
ENTRYPOINT ["python", "manage.py"]
CMD ["runserver", "0.0.0.0:8000"]
Agregar solo los requisitos aprovechará la memoria caché de Docker mientras se construye, solo
necesita reconstruir el cambio de requisitos.
https://riptutorial.com/es/home 11
Componer
Docker compose es muy útil, especialmente cuando tiene múltiples servicios para ejecutar
localmente. docker-compose.yml :
version: '2'
services:
web:
build:
context: .
dockerfile: devel.dockerfile
volumes:
- "./src/{{ project_name }}:/run/service/src/{{ project_name }}"
- "./media:/run/service/media"
ports:
- "8000:8000"
depends_on:
- db
db:
image: mysql:5.6
environment:
- MYSQL_ROOT_PASSWORD=root
- MYSQL_DATABASE={{ project_name }}
nginx:
image: nginx
ports:
- "80:80"
volumes:
- "./nginx:/etc/nginx/conf.d"
- "./media:/var/media"
depends_on:
- web
Nginx
Su entorno de desarrollo debe ser lo más cercano posible al entorno prod, por lo que me gusta
usar Nginx desde el principio. Aquí hay un ejemplo de archivo de configuración nginx:
server {
listen 80;
client_max_body_size 4G;
keepalive_timeout 5;
location /media/ {
autoindex on;
alias /var/media/;
}
location / {
proxy_pass_header Server;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
https://riptutorial.com/es/home 12
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Ssl on;
proxy_connect_timeout 600;
proxy_read_timeout 600;
proxy_pass http://web:8000/;
}
}
Uso
$ cd PROJECT_ROOT
$ docker-compose build web # build the image - first-time and after requirements change
$ docker-compose up # to run the project
$ docker-compose run --rm --service-ports --no-deps # to run the project - and be able to use
PDB
$ docker-compose run --rm --no-deps <management_command> # to use other than runserver
commands, like makemigrations
$ docker exec -ti web bash # For accessing django container shell, using it you will be
inside /run/service directory, where you can run ./manage shell, or other stuff
$ docker-compose start # Starting docker containers
$ docker-compose stop # Stopping docker containers
https://riptutorial.com/es/home 13
Capítulo 2: ¿Cómo usar Django con
Cookiecutter?
Examples
Instalando y configurando el proyecto django usando Cookiecutter
• pipa
• virtualenv
• PostgreSQL
Cambie los directorios a la carpeta donde desea que viva su proyecto. Ahora ejecuta el siguiente
comando para generar un proyecto django:
$ cookiecutter https://github.com/pydanny/cookiecutter-django.git
https://riptutorial.com/es/home 14
use_python2 [n]: n
https://riptutorial.com/es/home 15
Capítulo 3: Administración
Examples
Lista de cambios
Digamos que tienes una aplicación de myblog simple con el siguiente modelo:
class Article(models.Model):
title = models.CharField(max_length=70)
slug = models.SlugField(max_length=70, unique=True)
author = models.ForeignKey(settings.AUTH_USER_MODEL, models.PROTECT)
date_published = models.DateTimeField(default=timezone.now)
is_draft = models.BooleanField(default=True)
content = models.TextField()
La "lista de cambios" de Django Admin es la página que lista todos los objetos de un modelo
dado.
@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
pass
Por defecto, utilizará el __str__() (o __unicode__() si está en python2) de su modelo para mostrar
el "nombre" del objeto. Esto significa que si no lo ha anulado, verá una lista de artículos, todos
llamados "Objeto de artículo". Para cambiar este comportamiento, puede configurar el __str__() :
class Article(models.Model):
def __str__(self):
return self.title
Ahora, todos sus artículos deben tener un nombre diferente y más explícito que "Objeto de
artículo".
Sin embargo, es posible que desee mostrar otros datos en esta lista. Para esto, usa list_display :
@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
list_display = ['__str__', 'author', 'date_published', 'is_draft']
no está limitado a los campos y propiedades del modelo. También puede ser un
list_display
método de su ModelAdmin :
https://riptutorial.com/es/home 16
from django.forms.utils import flatatt
from django.urls import reverse
from django.utils.html import format_html
@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
list_display = ['title', 'author_link', 'date_published', 'is_draft']
class Customer(models.Model):
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
is_premium = models.BooleanField(default=False)
@admin.register(Customer)
class CustomerAdmin(admin.ModelAdmin):
list_display = ['first_name', 'last_name', 'is_premium']
search_fields = ['first_name', 'last_name']
@admin.register(Customer)
class CustomerAdmin(admin.ModelAdmin):
list_display = ['first_name', 'last_name', 'is_premium']
search_fields = ['first_name', 'last_name']
class Media:
#this path may be any you want,
#just put it in your static folder
js = ('js/admin/placeholder.js', )
https://riptutorial.com/es/home 17
Puede usar la barra de herramientas de depuración del navegador para encontrar qué ID o clase
Django estableció en esta barra de búsqueda y luego escribir su código js:
$(function () {
$('#searchbar').attr('placeholder', 'Search by name')
})
También la clase Media permite agregar archivos css con objeto de diccionario:
class Media:
css = {
'all': ('css/admin/styles.css',)
}
Por ejemplo, necesitamos mostrar cada elemento de la columna first_name en un color específico.
Por defecto, Django crea una columna en la tabla para cada elemento en list_display , todas las
etiquetas <td> tendrán una clase css como el field-'list_display_name' , en nuestro caso será
field_first_name
.field_first_name {
background-color: #e6f2ff;
}
Si desea personalizar otro comportamiento agregando JS o algunos estilos css, siempre puede
verificar los ID y las clases de elementos en la herramienta de depuración del navegador.
De forma predeterminada, Django presenta los campos de ForeignKey como una entrada de
<select> . Esto puede hacer que las páginas se carguen muy lentamente si tiene miles o
decenas de miles de entradas en la tabla a la que se hace referencia. E incluso si tiene solo
cientos de entradas, es bastante incómodo buscar una entrada en particular entre todas.
Un módulo externo muy útil para esto es django-autocomplete-light (DAL). Esto permite utilizar los
campos de autocompletar en lugar de los campos de <select> .
https://riptutorial.com/es/home 18
vistas.py
class CityAutocomp(autocomplete.Select2QuerySetView):
def get_queryset(self):
qs = City.objects.all()
if self.q:
qs = qs.filter(name__istartswith=self.q)
return qs
urls.py
urlpatterns = [
url(r'^city-autocomp/$', CityAutocomp.as_view(), name='city-autocomp'),
]
forms.py
class PlaceForm(forms.ModelForm):
city = forms.ModelChoiceField(
queryset=City.objects.all(),
widget=autocomplete.ModelSelect2(url='city-autocomp')
)
class Meta:
model = Place
https://riptutorial.com/es/home 19
fields = ['__all__']
admin.py
@admin.register(Place)
class PlaceAdmin(admin.ModelAdmin):
form = PlaceForm
https://riptutorial.com/es/home 20
Capítulo 4: Agregaciones de modelos
Introducción
Las agregaciones son métodos que permiten la ejecución de operaciones en (individuales y / o
grupos de) filas de objetos derivados de un Modelo.
Examples
Promedio, mínimo, máximo, suma de Queryset
class Product(models.Model):
name = models.CharField(max_length=20)
price = models.FloatField()
>>> Product.objects.all().aggregate(Min('price'))
# {'price__min': 9}
>>> Product.objects.all().aggregate(Max('price'))
# {'price__max':599 }
>>> Product.objects.all().aggregate(Sum('price'))
# {'price__sum':92456 }
class Category(models.Model):
name = models.CharField(max_length=20)
class Product(models.Model):
name = models.CharField(max_length=64)
category = models.ForeignKey(Category, on_delete=models.PROTECT)
https://riptutorial.com/es/home 21
>>> categories = Category.objects.annotate(Count('product'))
>>> categories.order_by('num_products')
[<Category: Footwear>, <Category: Clothing>]
>>> categories.filter(num_products__gt=20)
[<Category: Clothing>]
Podemos realizar un GROUP BY ... COUNT o un GROUP BY ... SUM consultas SQL equivalentes en
ORM de Django, con el uso de annotate() , values() , order_by() y los django.db.models 's Count y
Sum respetuosamente los métodos:
class Books(models.Model):
title = models.CharField()
author = models.CharField()
price = models.FloatField()
• Supongamos que queremos contar cuántos objetos de libros por autor distinto existen en
nuestra tabla de Books :
result = Books.objects.values('author')
.order_by('author')
.annotate(count=Count('author'))
author | count
------------|-------
OneAuthor | 5
OtherAuthor | 2
... | ...
https://riptutorial.com/es/home 22
GROUB BY ... SUM :
• Supongamos que queremos sumar el precio de todos los libros por autor distinto que existe
en nuestra tabla de Books :
result = Books.objects.values('author')
.order_by('author')
.annotate(total_price=Sum('price'))
author | total_price
------------|-------------
OneAuthor | 100.35
OtherAuthor | 50.00
... | ...
https://riptutorial.com/es/home 23
Capítulo 5: Ajustes
Examples
Configuración de la zona horaria
Puedes establecer la zona horaria que usará Django en el archivo settings.py . Ejemplos:
Cuando se ejecuta en un entorno Windows , debe configurarse de la misma manera que la zona
horaria del sistema .
USE_TZ = False
Las mejores prácticas de Django requieren el uso de UTC para almacenar información en la base
de datos:
Incluso si su sitio web está disponible en una sola zona horaria, sigue siendo una
buena práctica almacenar datos en UTC en su base de datos. La razón principal es el
horario de verano (DST). Muchos países tienen un sistema de horario de verano,
donde los relojes se mueven hacia adelante en primavera y hacia atrás en otoño. Si
está trabajando en la hora local, es probable que encuentre errores dos veces al año,
cuando ocurren las transiciones.
https://docs.djangoproject.com/en/stable/topics/i18n/timezones/
Una vez que tenga todas sus configuraciones, querrá usarlas en su código. Para hacerlo, agregue
la siguiente importación a su archivo:
Luego puede acceder a su configuración como atributos del módulo de settings , por ejemplo:
if not settings.DEBUG:
email_user(user, message)
https://riptutorial.com/es/home 24
Es una mala idea para las rutas de código duro en su aplicación. Siempre se deben usar
direcciones URL relativas para que su código pueda funcionar sin problemas en diferentes
máquinas. La mejor manera de configurar esto es definir una variable como esta
import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
Luego use esta variable BASE_DIR para definir todas sus otras configuraciones.
Y así. Esto garantiza que pueda transferir su código a diferentes máquinas sin ninguna
preocupación.
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
Una alternativa es utilizar el módulo unipath (que puede instalar con pip install unipath ).
TEMPLATE_PATH = BASE_DIR.child('templates')
STATICFILES_DIRS = [
BASE_DIR.child('static'),
]
El uso de variables de entorno es una forma muy utilizada para configurar la configuración de una
aplicación en función de su entorno, como se indica en la aplicación The Twelve-Factor .
Como es probable que las configuraciones cambien entre los entornos de implementación, esta
es una forma muy interesante de modificar la configuración sin tener que buscar en el código
fuente de la aplicación, así como guardar secretos fuera de los archivos de la aplicación y el
repositorio de código fuente.
settings.py
https://riptutorial.com/es/home 25
import os
DATABASES = {
'default': {
'ENGINE': os.environ.get('APP_DB_ENGINE', 'django.db.backends.sqlite3'),
'NAME': os.environ.get('DB_NAME', 'db.sqlite'),
'USER': os.environ.get('DB_USER', ''),
'PASSWORD': os.environ.get('DB_PASSWORD', ''),
'HOST': os.environ.get('DB_HOST', None),
'PORT': os.environ.get('DB_PORT', None),
'CONN_MAX_AGE': 600,
}
}
Con Django, puede cambiar la tecnología de su base de datos, de modo que puede usar sqlite3
en su máquina de desarrollo (y eso debería ser un buen valor predeterminado para
comprometerse con un sistema de control de origen). Aunque esto es posible no es aconsejable:
El diseño de proyecto predeterminado de Django crea un solo settings.py . Esto suele ser útil
para dividirlo así:
myprojectroot/
myproject/
__init__.py
settings/
__init__.py
base.py
dev.py
prod.py
tests.py
Esto le permite trabajar con diferentes configuraciones según esté en desarrollo, producción,
pruebas o lo que sea.
https://riptutorial.com/es/home 26
# -*- coding: utf-8 -*-
from .base import * # noqa
DEBUG = True
INSTALLED_APPS.extend([
'debug_toolbar',
])
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
INTERNAL_IPS = ['192.168.0.51', '192.168.0.69']
Alternativa # 1
Para que django-admin comandos de django-admin funcionen correctamente, tendrá que configurar
la variable de entorno DJANGO_SETTINGS_MODULE (que por defecto es myproject.settings ). En
desarrollo, lo establecerá en myproject.settings.dev . En producción, lo establecerá en
myproject.settings.prod . Si usa un virtualenv, lo mejor es establecerlo en su script postactivate :
#!/bin/sh
export PYTHONPATH="/home/me/django_projects/myproject:$VIRTUAL_ENV/lib/python3.4"
export DJANGO_SETTINGS_MODULE="myproject.settings.dev"
Si desea usar un módulo de configuración que no es señalado por DJANGO_SETTINGS_MODULE por una
vez, puede usar la opción --settings de django-admin :
Alternativa # 2
Si quieres dejar DJANGO_SETTINGS_MODULE en su configuración por defecto ( myproject.settings ),
puede simplemente decir la settings módulo de la configuración que se cargue mediante la
colocación de la importación en su __init__.py archivo.
Cada archivo de requisitos debe coincidir con el nombre de un archivo de configuración. Lea Uso
de configuraciones múltiples para más información.
Estructura
djangoproject
https://riptutorial.com/es/home 27
├── config
│ ├── __init__.py
│ ├── requirements
│ │ ├── base.txt
│ │ ├── dev.txt
│ │ ├── test.txt
│ │ └── prod.txt
│ └── settings
└── manage.py
# base.txt
Django==1.8.0
psycopg2==2.6.1
jinja2==2.8
Y en todos los demás archivos, incluya las dependencias base con -r base.txt y agregue las
dependencias específicas necesarias para el entorno actual.
# dev.txt
-r base.txt # includes all dependencies in `base.txt`
# test.txt
-r base.txt # includes all dependencies in `base.txt`
# prod.txt
-r base.txt # includes all dependencies in `base.txt`
Al usar un VCS como Git o SVN, hay algunos datos secretos que nunca deben ser versionados
(ya sea que el repositorio sea público o privado).
Una práctica común para ocultar estas configuraciones del control de versiones es crear un
archivo secrets.json en la raíz de su proyecto ( gracias a la idea ) " Two Scoops of Django " :
https://riptutorial.com/es/home 28
{
"SECRET_KEY": "N4HE:AMk:.Ader5354DR453TH8SHTQr",
"DB_PASSWORD": "v3ry53cr3t"
}
*.py[co]
*.sw[po]
*~
/secrets.json
import json
import os
from django.core.exceptions import ImproperlyConfigured
SECRET_KEY = get_secret('SECRET_KEY')
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgres',
'NAME': 'db_name',
'USER': 'username',
'PASSWORD': get_secret('DB_PASSWORD'),
},
}
Créditos: Two Scoops of Django: Best Practices for Django 1.8, de Daniel Roy Greenfeld y Audrey
RoyGreenfeld. Copyright 2015 Two Scoops Press (ISBN 978-0981467344)
En sitios de PaaS como Heroku, es habitual recibir la información de la base de datos como una
única variable de entorno de URL, en lugar de varios parámetros (host, puerto, usuario,
contraseña ...).
https://riptutorial.com/es/home 29
Uso:
import dj_database_url
if os.environ.get('DATABASE_URL'):
DATABASES['default'] =
dj_database_url.config(default=os.environ['DATABASE_URL'])
https://riptutorial.com/es/home 30
Capítulo 6: ArrayField - un campo específico
de PostgreSQL
Sintaxis
• desde django.contrib.postgres.fields importa ArrayField
• clase ArrayField (campo base, tamaño = Ninguno, ** opciones)
• FooModel.objects.filter (array_field_name__contains = [objetos, to, check])
• FooModel.objects.filter (array_field_name__contained_by = [objetos, a, verificar])
Observaciones
Tenga en cuenta que aunque el parámetro de size se pasa a PostgreSQL, PostgreSQL no lo
aplicará.
Cuando use ArrayField s, debe tener en cuenta esta palabra de advertencia de la documentación
de matrices de Postgresql .
Examples
Un ArrayField básico
Para crear un ArrayField de PostgreSQL, deberíamos darle a ArrayField el tipo de datos que
queremos que almacene como un primer campo como campo. Ya que estaremos almacenando
calificaciones de libros, usaremos FloatField .
class Book(models.Model):
ratings = ArrayField(FloatField())
class IceCream(models.Model):
scoops = ArrayField(IntegerField() # we'll use numbers to ID the scoops
https://riptutorial.com/es/home 31
, size=6) # our parlor only lets you have 6 scoops
Cuando usas el parámetro size, se pasa a postgresql, que lo acepta y luego lo ignora. Por lo
tanto, es muy posible agregar 7 enteros al campo de scoops arriba usando la consola postgresql.
Esta consulta devuelve todos los conos con una cucharada de chocolate y una cucharada de
vainilla.
También tenga en cuenta que django no creará un índice para ArrayField s. Si va a buscarlos,
necesitará un índice y tendrá que crearlo manualmente con una llamada a RunSQL en su archivo
de migraciones.
Matrices de nidificación
class SudokuBoard(models.Model):
numbers = ArrayField(
ArrayField(
models.IntegerField(),
size=9,
),
size=9,
)
Consultar a todos los modelos que contengan cualquier artículo en una lista
con contenido por
Esta consulta devuelve todos los conos con una cucharada de menta o una cucharada de vainilla.
https://riptutorial.com/es/home 32
Capítulo 7: Backends de autenticación
Examples
Backend de autenticación de correo electrónico
class EmailBackend(object):
"""
Custom Email Backend to perform authentication via email
"""
def authenticate(self, username=None, password=None):
user_model = get_user_model()
try:
user = user_model.objects.get(email=username)
if user.check_password(password): # check valid password
return user # return user to be authenticated
except user_model.DoesNotExist: # no matching user exists
return None
# settings.py
AUTHENTICATION_BACKENDS = (
'my_app.backends.EmailBackend',
...
)
https://riptutorial.com/es/home 33
Capítulo 8: Comandos de gestión
Introducción
Los comandos de administración son scripts potentes y flexibles que pueden realizar acciones en
su proyecto Django o en la base de datos subyacente. ¡Además de varios comandos
predeterminados, es posible escribir los tuyos!
En comparación con los scripts de Python normales, el uso del marco de comandos de
administración significa que un trabajo de configuración tedioso se realiza automáticamente entre
bastidores.
Observaciones
Los comandos de gestión se pueden llamar desde:
Examples
Creación y ejecución de un comando de gestión
Para realizar acciones en Django utilizando la línea de comandos u otros servicios (donde no se
usa el usuario / solicitud), puede usar los management commands .
class Command(BaseCommand):
help = 'My custom django management command'
https://riptutorial.com/es/home 34
def add_arguments(self, parser):
parser.add_argument('book_id', nargs='+', type=int)
parser.add_argument('author' , nargs='+', type=str)
# For example:
# books = Book.objects.filter(author="bob")
# for book in books:
# book.name = "Bob"
# book.save()
Aquí es obligatorio el nombre de clase Comando, que amplía BaseCommand o una de sus
subclases.
El nombre del comando de administración es el nombre del archivo que lo contiene. Para ejecutar
el comando en el ejemplo anterior, use lo siguiente en el directorio de su proyecto:
Tenga en cuenta que iniciar un comando puede demorar unos segundos (debido a la
importación de los módulos). Entonces, en algunos casos, se recomienda crear
procesos de daemon lugar de management commands de management commands .
Aquí command_name será su nombre de comando deseado, esto le mostrará el texto de ayuda
del comando.
Starts a lightweight Web server for development and also serves static files.
https://riptutorial.com/es/home 35
positional arguments:
addrport Optional port number, or ipaddr:port
optional arguments:
-h, --help show this help message and exit
--version show program's version number and exit
-v {0,1,2,3}, --verbosity {0,1,2,3}
Verbosity level; 0=minimal output, 1=normal output,
2=verbose output, 3=very verbose output
--settings SETTINGS The Python path to a settings module, e.g.
"myproject.settings.main". If this isn't provided, the
DJANGO_SETTINGS_MODULE environment variable will be
used.
--pythonpath PYTHONPATH
A directory to add to the Python path, e.g.
"/home/djangoprojects/myproject".
--traceback Raise on CommandError exceptions
--no-color Don't colorize the command output.
--ipv6, -6 Tells Django to use an IPv6 address.
--nothreading Tells Django to NOT use threading.
--noreload Tells Django to NOT use the auto-reloader.
--nostatic Tells Django to NOT automatically serve static files
at STATIC_URL.
--insecure Allows serving static files even if DEBUG is False.
Puede deshacerse de manage.py y usar el comando django-admin lugar. Para hacerlo, tendrá que
hacer manualmente lo que manage.py hace:
export PYTHONPATH="/home/me/path/to/your_project"
export DJANGO_SETTINGS_MODULE="your_project.settings"
Esto es especialmente útil en un virtualenv donde puede configurar estas variables de entorno en
el script postactivate .
django-admincomando django-admin tiene la ventaja de estar disponible donde sea que esté en su
sistema de archivos.
Django viene con una serie de comandos de administración incorporados, que utilizan python
manage.py [command] o, cuando manage.py tiene derechos + x (ejecutables) simplemente
./manage.py [command] . Los siguientes son algunos de los más utilizados:
https://riptutorial.com/es/home 36
./manage.py help
Ejecute su servidor Django en localhost: 8000; esencial para las pruebas locales
./manage.py runserver
Ejecute una consola de python (o ipython si está instalada) con la configuración de Django de su
proyecto precargada (intentar acceder a partes de su proyecto en un terminal de python sin hacer
esto fallará).
./manage.py shell
Cree un nuevo archivo de migración de base de datos en función de los cambios que haya
realizado en sus modelos. Ver migraciones
./manage.py makemigrations
./manage.py migrate
./manage.py test
./manage.py collectstatic
./manage.py createsuperuser
https://riptutorial.com/es/home 37
Capítulo 9: Cómo restablecer las migraciones
django
Introducción
A medida que desarrolla una aplicación Django, puede haber situaciones en las que puede
ahorrar mucho tiempo simplemente limpiando y reiniciando sus migraciones.
Examples
Restablecimiento de la migración de Django: eliminar la base de datos
existente y migrar como nueva
Eliminar / Eliminar su base de datos Si está utilizando SQLite para su base de datos, simplemente
elimine este archivo. Si está utilizando MySQL / Postgres o cualquier otro sistema de base de
datos, deberá abandonar la base de datos y luego volver a crear una base de datos nueva.
Ahora deberá eliminar todos los archivos de migraciones, excepto el archivo "init.py" ubicado
dentro de la carpeta de migraciones en la carpeta de su aplicación.
/your_django_project/your_app/migrations
Ahora que ha eliminado la base de datos y el archivo de migraciones, simplemente ejecute los
siguientes comandos como si fuera a migrar la primera vez que configure el proyecto django.
https://riptutorial.com/es/home 38
Capítulo 10: Configuración de la base de
datos
Examples
MySQL / MariaDB
Además de uno de los controladores MySQL de Python ( mysqlclient la opción recomendada para
Django):
La codificación de la base de datos no puede ser configurada por Django, pero debe
configurarse en el nivel de la base de datos. Busque el default-character-set en
my.cnf (o /etc/mysql/mariadb.conf/*.cnf ) y configure la codificación:
[mysql]
#default-character-set = latin1 #default on some systems.
#default-character-set = utf8mb4 #default on some systems.
default-character-set = utf8
...
[mysqld]
#character-set-server = utf8mb4
#collation-server = utf8mb4_general_ci
character-set-server = utf8
collation-server = utf8_general_ci
#myapp/settings/settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'DB_NAME',
'USER': 'DB_USER',
'PASSWORD': 'DB_PASSWORD',
'HOST': 'localhost', # Or an IP Address that your database is hosted on
https://riptutorial.com/es/home 39
'PORT': '3306',
#optional:
'OPTIONS': {
'charset' : 'utf8',
'use_unicode' : True,
'init_command': 'SET '
'storage_engine=INNODB,'
'character_set_connection=utf8,'
'collation_connection=utf8_bin'
#'sql_mode=STRICT_TRANS_TABLES,' # see note below
#'SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED',
},
'TEST_CHARSET': 'utf8',
'TEST_COLLATION': 'utf8_general_ci',
}
}
Si está utilizando el conector MySQL de Oracle, su línea ENGINE debería tener este aspecto:
'ENGINE': 'mysql.connector.django',
Cuando cree una base de datos, asegúrese de que para especificar la codificación y la
intercalación:
PostgreSQL
#myapp/settings/settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'myprojectDB',
'USER': 'myprojectuser',
'PASSWORD': 'password',
'HOST': '127.0.0.1',
'PORT': '5432',
https://riptutorial.com/es/home 40
}
}
Modelfields:
sqlite
sqlite es el predeterminado para Django. No debe utilizarse en producción ya que suele ser lento.
#myapp/settings/settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': 'db/development.sqlite3',
'USER': '',
'PASSWORD': '',
'HOST': '',
'PORT': '',
},
}
Accesorios
Los accesorios son datos iniciales para la base de datos. La forma más sencilla cuando ya tiene
algunos datos existentes es usar el comando dumpdata
Esto creará un archivo json que puede ser importado nuevamente usando
Al usar el loadddata sin especificar un archivo, Django buscará una carpeta de fixtures en su
aplicación o la lista de directorios provista en FIXTURE_DIRS en la configuración, y usará su
contenido en su lugar.
https://riptutorial.com/es/home 41
/myapp
/fixtures
myfixtures.json
morefixtures.xml
[
{
"model": "myapp.person",
"pk": 1,
"fields": {
"first_name": "John",
"last_name": "Lennon"
}
},
{
"model": "myapp.person",
"pk": 2,
"fields": {
"first_name": "Paul",
"last_name": "McCartney"
}
}
]
Ejemplo de YAML:
- model: myapp.person
pk: 1
fields:
first_name: John
last_name: Lennon
- model: myapp.person
pk: 2
fields:
first_name: Paul
last_name: McCartney
https://riptutorial.com/es/home 42
• Instala pip: $ pip install django-cassandra-engine
• Agregue Getting Started to INSTALLED_APPS en su archivo settings.py: INSTALLED_APPS =
['django_cassandra_engine']
• Configuración de BASES DE DATOS Cange Standart:
Standart
DATABASES = {
'default': {
'ENGINE': 'django_cassandra_engine',
'NAME': 'db',
'TEST_NAME': 'test_db',
'HOST': 'db1.example.com,db2.example.com',
'OPTIONS': {
'replication': {
'strategy_class': 'SimpleStrategy',
'replication_factor': 1
}
}
}
}
DATABASES = {
'default': {
'ENGINE': 'django_cassandra_engine',
'NAME': 'db',
'TEST_NAME': 'test_db',
'USER_NAME'='cassandradb',
'PASSWORD'= '123cassandra',
'HOST': 'db1.example.com,db2.example.com',
'OPTIONS': {
'replication': {
'strategy_class': 'SimpleStrategy',
'replication_factor': 1
}
}
}
https://riptutorial.com/es/home 43
Capítulo 11: CRUD en Django
Examples
** Ejemplo de CRUD más simple **
Si encuentra estos pasos desconocidos, considere comenzar aquí . Tenga en cuenta que estos
pasos provienen de la documentación de desbordamiento de pila.
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'myapp',
]
Cree un archivo llamado urls.py dentro del directorio myapp y urls.py con la siguiente vista.
urlpatterns = [
url(r'^$', views.index, name='index'),
]
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^myapp/', include('myapp.urls')),
url(r'^admin/', admin.site.urls),
]
Crea una carpeta llamada templates dentro del directorio myapp . Luego cree un archivo llamado
index.html dentro del directorio de plantillas . Rellénalo con el siguiente contenido.
https://riptutorial.com/es/home 44
<!DOCTYPE html>
<html>
<head>
<title>myapp</title>
</head>
<body>
<h2>Simplest Crud Example</h2>
<p>This shows a list of names and lets you Create, Update and Delete them.</p>
<h3>Add a Name</h3>
<button>Create</button>
</body>
</html>
También necesitamos una vista para mostrar index.html que podemos crear editando el archivo
views.py de esta manera:
Ahora tienes la base con la que vas a trabajar. El siguiente paso es crear un modelo. Este es el
ejemplo más simple posible, así que en su carpeta models.py agregue el siguiente código.
Esto crea un modelo de un objeto Nombre que agregaremos a la base de datos con los siguientes
comandos desde la línea de comandos.
Deberías ver algunas operaciones realizadas por Django. Estos configuran las tablas y crean un
superusuario que puede acceder a la base de datos de administración desde una vista de
administración potenciada por Django. Hablando de eso, permite registrar nuestro nuevo modelo
con la vista de administrador. Vaya a admin.py y agregue el siguiente código.
admin.site.register(Name)
https://riptutorial.com/es/home 45
De vuelta en la línea de comandos, ahora puede activar el servidor con el comando de python
manage.py runserver . Debería poder visitar http: // localhost: 8000 / y ver su aplicación. Luego,
vaya a http: // localhost: 8000 / admin para poder agregar un nombre a su proyecto. Inicie sesión y
agregue un Nombre debajo de la tabla MYAPP, lo mantuvimos simple para el ejemplo, así que
asegúrese de que tenga menos de 100 caracteres.
Para acceder al nombre necesitas mostrarlo en algún lugar. Edite la función de índice en
views.py para obtener todos los objetos de Nombre de la base de datos.
<!DOCTYPE html>
<html>
<head>
<title>myapp</title>
</head>
<body>
<h2>Simplest Crud Example</h2>
<p>This shows a list of names and lets you Create, Update and Delete them.</p>
{% if names_from_context %}
<ul>
{% for name in names_from_context %}
<li>{{ name.name_value }} <button>Delete</button>
<button>Update</button></li>
{% endfor %}
</ul>
{% else %}
<h3>Please go to the admin and add a Name under 'MYAPP'</h3>
{% endif %}
<h3>Add a Name</h3>
<button>Create</button>
</body>
</html>
Eso demuestra la lectura en CRUD. Dentro del directorio myapp crea un archivo forms.py.
Agregue el siguiente código:
class NameForm(forms.ModelForm):
name_value = forms.CharField(max_length=100, help_text = "Enter a name")
class Meta:
model = Name
fields = ('name_value',)
https://riptutorial.com/es/home 46
Actualice el index.html de la siguiente manera:
<!DOCTYPE html>
<html>
<head>
<title>myapp</title>
</head>
<body>
<h2>Simplest Crud Example</h2>
<p>This shows a list of names and lets you Create, Update and Delete them.</p>
{% if names_from_context %}
<ul>
{% for name in names_from_context %}
<li>{{ name.name_value }} <button>Delete</button>
<button>Update</button></li>
{% endfor %}
</ul>
{% else %}
<h3>Please go to the admin and add a Name under 'MYAPP'</h3>
{% endif %}
<h3>Add a Name</h3>
<form id="name_form" method="post" action="/">
{% csrf_token %}
{% for field in form.visible_fields %}
{{ field.errors }}
{{ field.help_text }}
{{ field }}
{% endfor %}
<input type="submit" name="submit" value="Create">
</form>
</body>
</html>
form = NameForm()
if request.method == 'POST':
form = NameForm(request.POST)
if form.is_valid():
form.save(commit=True)
return render(request, 'index.html', context_dict)
else:
print(form.errors)
Reinicie su servidor y ahora debería tener una versión de trabajo de la aplicación con la C en la
https://riptutorial.com/es/home 47
creación completada.
https://riptutorial.com/es/home 48
Capítulo 12: Depuración
Observaciones
Pdb
Pdb también puede imprimir todas las variables existentes en el ámbito global o local, escribiendo
globals() o locals() en el indicador (Pdb) respectivamente.
Examples
Usando el depurador de Python (Pdb)
La herramienta de depuración más básica de Django es pdb , una parte de la biblioteca estándar
de Python.
def index(request):
foo = 1
bar = 0
bug = foo/bar
Es obvio que Django lanzaría un ZeroDivisionError cuando intentas cargar una página de índice,
pero si pretendemos que el error está muy metido en el código, podría ser realmente
desagradable.
# Pdb import
import pdb
https://riptutorial.com/es/home 49
def index(request):
foo = 1
bar = 0
bug = foo/bar
Ahora, en la página de carga, el punto de interrupción activará (pdb) en el shell, lo que también
bloqueará su navegador en estado pendiente.
> ../views.py(12)index()
-> bug = foo/bar
# input 'foo/bar' expression to see division results:
(Pdb) foo/bar
*** ZeroDivisionError: division by zero
# input variables names to check their values:
(Pdb) foo
1
(Pdb) bar
0
# 'bar' is a source of the problem, so if we set it's value > 0...
(Pdb) bar = 1
(Pdb) foo/bar
1.0
# exception gone, ask pdb to continue execution by typing 'c':
(Pdb) c
[03/Aug/2016 10:50:45] "GET / HTTP/1.1" 200 111
En la última línea vemos que nuestra vista devolvió una respuesta OK y se ejecutó como debería.
settings.py :
A continuación, inclúyalo a las aplicaciones instaladas del proyecto, pero tenga cuidado, siempre
https://riptutorial.com/es/home 50
es una buena práctica usar un archivo settings.py diferente para aplicaciones de desarrollo y
middlewares como la barra de herramientas de depuración:
# If environment is dev...
DEBUG = True
INSTALLED_APPS += [
'debug_toolbar',
]
MIDDLEWARE += ['debug_toolbar.middleware.DebugToolbarMiddleware']
INSTALLED_APPS = [
# ...
'django.contrib.staticfiles',
# ...
]
STATIC_URL = '/static/'
# If environment is dev...
DEBUG = True
INSTALLED_APPS += [
'debug_toolbar',
]
INTERNAL_IPS = ('127.0.0.1', )
urls.py :
https://riptutorial.com/es/home 51
HTML:
En caso de que esté seguro de que ha configurado todo correctamente, pero la barra de
herramientas de depuración aún no está renderizada: use esta solución "nuclear" para
intentar averiguarlo.
hará que django genere un AssertionError con el valor proporcionado como mensaje de error
cuando se ejecute esta línea.
Si esto ocurre en una vista, o en cualquier código llamado desde una vista, y se establece
DEBUG=True , se mostrará en el navegador una pila completa y detallada con mucha información de
depuración.
En lugar de perseguir errores con un depurador, considere dedicar más tiempo a mejorar su
código al:
https://riptutorial.com/es/home 52
Capítulo 13: Despliegue
Examples
Ejecutando la aplicación Django con Gunicorn
1. Instalar gunicorn
2. Desde la carpeta del proyecto django (la misma carpeta donde reside manage.py), ejecute
el siguiente comando para ejecutar el proyecto actual de django con gunicorn
Puede usar la opción --env para configurar la ruta de acceso para cargar la configuración
3. Escribe heroku create [app_name] . Si no das un nombre de aplicación, Heroku generará una
aleatoriamente para ti. La URL de su aplicación será http://[app name].herokuapp.com
4. Haga un archivo de texto con el nombre Procfile . No pongas una extensión al final.
5. Añadir un requisito.txt.
https://riptutorial.com/es/home 53
6. ¡Es tiempo de despliegue!
Esto escala el número de web "dynos" a uno. Puedes aprender más sobre dynos
aquí.
7. Añadir complementos . Tendrá que configurar su aplicación Django para enlazar con las
bases de datos proporcionadas en Heroku como "complementos". Este ejemplo no cubre
esto, pero otro ejemplo está en la tubería de implementación de bases de datos en Heroku.
Fabric es una biblioteca de Python (2.5-2.7) y una herramienta de línea de comandos para agilizar
el uso de SSH para la implementación de aplicaciones o tareas de administración de sistemas. Te
permite ejecutar funciones de Python arbitrarias a través de la línea de comandos.
#myproject/fabfile.py
from fabric.api import *
@task
def dev():
# details of development server
env.user = # your ssh user
env.password = #your ssh password
env.hosts = # your ssh hosts (list instance, with comma-separated hosts)
env.key_filename = # pass to ssh key for github in your local keyfile
@task
def release():
# details of release server
env.user = # your ssh user
env.password = #your ssh password
env.hosts = # your ssh hosts (list instance, with comma-separated hosts)
env.key_filename = # pass to ssh key for github in your local keyfile
@task
def run():
with cd('path/to/your_project/'):
https://riptutorial.com/es/home 54
with prefix('source ../env/bin/activate'):
# activate venv, suppose it appear in one level higher
# pass commands one by one
run('git pull')
run('pip install -r requirements.txt')
run('python manage.py migrate --noinput')
run('python manage.py collectstatic --noinput')
run('touch reload.txt')
Nota: no puede configurar las claves ssh para github y simplemente escriba inicio de sesión y
contraseña manualmente, mientras se ejecuta fabfile, lo mismo que con las claves.
Si planea alojar su sitio web de Django en Heroku, puede comenzar su proyecto usando la
plantilla de inicio de Heroku Django:
Tiene una configuración lista para producción para archivos estáticos, configuraciones de base de
datos, Gunicorn, etc. y mejoras en la funcionalidad de servicio de archivos estáticos de Django a
través de WhiteNoise. Esto le ahorrará tiempo, está listo para hospedarse en Heroku,
simplemente cree su sitio web en la parte superior de esta plantilla
git init
git add -A
git commit -m "Initial commit"
heroku create
git push heroku master
¡Eso es!
1. nginx: servidor HTTP de alto rendimiento, de código abierto y gratuito, y proxy inverso, con
alto rendimiento;
2. gunicorn - 'Green Unicorn' es un servidor HTTP WSGI de Python para UNIX (necesario para
https://riptutorial.com/es/home 55
administrar su servidor);
3. supervisor: un sistema cliente / servidor que permite a sus usuarios monitorear y controlar
una serie de procesos en sistemas operativos similares a UNIX. Se utiliza cuando la
aplicación o el sistema se bloquea, reinicia la cámara de django / celery / apio, etc .;
NGINX
Vamos a empezar con nginx. Si nginx no está ya en la máquina, instálelo con sudo apt-get
install nginx . Más adelante, tendrá que crear un nuevo archivo de configuración en su directorio
nginx /etc/nginx/sites-enabled/yourapp.conf . Si hay un archivo llamado default.conf , elimínelo.
Bellow código a un archivo conf nginx, que intentará ejecutar su servicio con el uso de archivo de
socket; Más adelante habrá una configuración de gunicorn. El archivo de socket se usa aquí para
comunicarse entre nginx y gunicorn. También se puede hacer utilizando puertos.
server {
# root folder of your application
root /home/root/app/src/;
listen 80;
# server name, your main domain, all subdomains and specific subdomains
server_name yourdomain.com *.yourdomain.com somesubdomain.yourdomain.com
charset utf-8;
client_max_body_size 100m;
https://riptutorial.com/es/home 56
}
GUNICORN
Ahora nuestro script GUNICORN, que será responsable de ejecutar la aplicación django en el
servidor. Lo primero es instalar gunicorn en un entorno virtual con pip install gunicorn .
#!/bin/bash
ME="root"
DJANGODIR=/home/root/app/src # django app dir
SOCKFILE=/home/root/app/src/gunicorn.sock # your sock file - do not create it manually
USER=root
GROUP=webapps
NUM_WORKERS=3
DJANGO_SETTINGS_MODULE=yourapp.yoursettings
DJANGO_WSGI_MODULE=yourapp.wsgi
echo "Starting $NAME as `whoami`"
source /home/root/app/env/bin/activate
export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE
export PYTHONPATH=$DJANGODIR:$PYTHONPATH
para poder ejecutar el script de inicio gunicorn tiene que tener el modo de ejecución habilitado
para que
SUPERVISOR
Como se dijo al principio, queremos que nuestra aplicación se reinicie cuando un supervisor falla.
https://riptutorial.com/es/home 57
Si el supervisor aún no está en el servidor, instale con sudo apt-get install supervisor .
[program:yourappname]
command = /home/root/app/src/gunicorn_start
user = root
stdout_logfile = /home/root/app/src/logs/gunicorn_supervisor.log
redirect_stderr = true
Una vez hecho esto, tenemos que decirle a nuestro supervisor que acabamos de agregar un
nuevo archivo de configuración. Para hacerlo, hay diferentes procesos para diferentes versiones
de Ubuntu.
sudo supervisorctl reread -> vuelve a leer todos los archivos de configuración dentro del catálogo
de supervisor, esto debería imprimirse: nombre de aplicación: disponible
Para obtener una demostración en vivo de este procedimiento, navegue este video .
https://riptutorial.com/es/home 58
Esto solo está destinado a la implementación local (por ejemplo, LAN) y nunca debe usarse en
producción y solo está disponible si la aplicación staticfiles está en la configuración
INSTALLED_APPS su proyecto.
https://riptutorial.com/es/home 59
Capítulo 14: Django desde la línea de
comandos.
Observaciones
Si bien Django es principalmente para aplicaciones web, tiene un ORM potente y fácil de usar que
también se puede usar para aplicaciones de línea de comandos y scripts. Hay dos enfoques
diferentes que pueden ser utilizados. El primero es crear un comando de administración
personalizado y el segundo es inicializar el entorno Django al inicio de su script.
Examples
Django desde la línea de comandos.
# Setup environ
sys.path.append(os.getcwd())
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "main.settings")
# Setup django
import django
django.setup()
python main/cli.py
https://riptutorial.com/es/home 60
Capítulo 15: Django Rest Framework
Examples
Barebones simples API de solo lectura
Suponiendo que tenga un modelo que se parece al siguiente, iniciaremos una ejecución con una
simple API de solo lectura basada en barebones basada en Django REST Framework ("DRF").
modelos.py
class FeedItem(models.Model):
title = models.CharField(max_length=100, blank=True)
url = models.URLField(blank=True)
style = models.CharField(max_length=100, blank=True)
description = models.TextField(blank=True)
El serializador es el componente que tomará toda la información del modelo de Django (en este
caso, el artículo de FeedItem ) y lo convertirá en JSON. Es muy similar a crear clases de formulario
en Django. Si tiene alguna experiencia en eso, esto será muy cómodo para usted.
serializers.py
class FeedItemSerializer(serializers.ModelSerializer):
class Meta:
model = models.FeedItem
fields = ('title', 'url', 'description', 'style')
vistas.py
DRF ofrece muchas clases de vistas para manejar una variedad de casos de uso. En este
ejemplo, sólo vamos a tener una API de solo lectura, por lo que, en lugar de utilizar un enfoque
más integral viewset , o un montón de puntos de vista genéricos relacionados, vamos a utilizar
una sola subclase de DRF de ListAPIView .
El propósito de esta clase es vincular los datos con el serializador y envolverlos todos juntos para
un objeto de respuesta.
class FeedItemList(generics.ListAPIView):
serializer_class = serializers.FeedItemSerializer
queryset = models.FeedItem.objects.all()
urls.py
https://riptutorial.com/es/home 61
Asegúrese de apuntar su ruta a su vista DRF.
urlpatterns = [
...
url(r'path/to/api', views.FeedItemList.as_view()),
]
https://riptutorial.com/es/home 62
Capítulo 16: Django y redes sociales
Parámetros
Ajuste Hace
https://riptutorial.com/es/home 63
Ajuste Hace
Examples
Manera fácil: python-social-auth
INSTALAR
o descargue el código desde github. Ahora es un buen momento para agregar esto a su
requirements.txt archivo.
Configurando ajustes.py
En la configuración.py agregue:
INSTALLED_APPS = (
...
'social.apps.django_app.default',
...
)
CONFIGURACIÓN DE BACKENDS
https://riptutorial.com/es/home 64
AUTHENTICATION_BACKENDS = (
'social.backends.open_id.OpenIdAuth',
'social.backends.google.GoogleOpenId',
'social.backends.google.GoogleOAuth2',
'social.backends.google.GoogleOAuth',
'social.backends.twitter.TwitterOAuth',
'social.backends.yahoo.YahooOpenId',
...
'django.contrib.auth.backends.ModelBackend',
)
Si usamos por ejemplo Facebook y Linkedin Backends necesitamos agregar las claves API
SOCIAL_AUTH_FACEBOOK_KEY = 'YOURFACEBOOKKEY'
SOCIAL_AUTH_FACEBOOK_SECRET = 'YOURFACEBOOKSECRET'
SOCIAL_AUTH_LINKEDIN_KEY = 'YOURLINKEDINKEY'
SOCIAL_AUTH_LINKEDIN_SECRET = 'YOURLINKEDINSECRET'
Nota : Puede obtener las claves nedded en los desarrolladores de Facebook y en los
desarrolladores de Linkedin y aquí puede ver la lista completa y su forma respectiva de
especificar la clave de la API y el secreto de la clave.
Nota sobre las claves secretas: las claves secretas deben mantenerse secretas. Aquí hay una
explicación de desbordamiento de pila que es útil. Este tutorial es útil para aprender sobre
variables ambientales.
TEMPLATE_CONTEXT_PROCESSORS = (
...
'social.apps.django_app.context_processors.backends',
'social.apps.django_app.context_processors.login_redirect',
...
)
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, "templates")],
https://riptutorial.com/es/home 65
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'social.apps.django_app.context_processors.backends',
'social.apps.django_app.context_processors.login_redirect',
],
},
},
]
Si está utilizando un modelo de usuario personalizado y desea asociarse con él, simplemente
agregue la siguiente línea (aún en settings.py )
SOCIAL_AUTH_USER_MODEL = 'somepackage.models.CustomUser'
Configurando urls.py
# if you haven't imported inlcude make sure you do so at the top of your file
from django.conf.urls import url, include
urlpatterns = patterns('',
...
url('', include('social.apps.django_app.urls', namespace='social'))
...
)
Luego necesitamos sincronizar la base de datos para crear los modelos necesarios:
./manage.py migrate
Desconectando usuarios
Una vez que haya iniciado sesión en los usuarios, es probable que desee crear la funcionalidad
para volver a cerrarlos. En alguna plantilla, probablemente cerca de donde se mostró la plantilla
https://riptutorial.com/es/home 66
de inicio de sesión, agregue la siguiente etiqueta:
<a href="/logout">Logout</a>
def logout(request):
auth_logout(request)
return redirect('/')
Para todos mis proyectos, Django-Allauth sigue siendo uno que es fácil de configurar y viene de la
caja con muchas características que incluyen pero no se limitan a:
Si está interesado en ensuciarse las manos, Django-Allauth se sale del camino, con
configuraciones adicionales para ajustar el proceso y el uso de su sistema de autenticación.
Pasos de configuración:
https://riptutorial.com/es/home 67
# Already defined Django-related contexts here
AUTHENTICATION_BACKENDS = (
# Needed to login by username in Django admin, regardless of `allauth`
'django.contrib.auth.backends.ModelBackend',
INSTALLED_APPS = (
# Up here is all your default installed apps from Django
'allauth',
'allauth.account',
'allauth.socialaccount',
Hecho con los cambios en el archivo settings.py arriba, muévase al archivo urls.py Puede ser su
yourapp/urls.py o su ProjectName/urls.py Normalmente, prefiero el ProjectName/urls.py
urlpatterns = [
# other urls here
url(r'^accounts/', include('allauth.urls')),
# other urls here
]
https://riptutorial.com/es/home 68
^accounts/ ^ ^password/reset/done/$ [name='account_reset_password_done']
^accounts/ ^ ^password/reset/key/(?P<uidb36>[0-9A-Za-z]+)-(?P<key>.+)/$
[name='account_reset_password_from_key']
^accounts/ ^ ^password/reset/key/done/$ [name='account_reset_password_from_key_done']
^accounts/ ^social/
^accounts/ ^google/
^accounts/ ^twitter/
^accounts/ ^facebook/
^accounts/ ^facebook/login/token/$ [name='facebook_login_by_token']
Finalmente, python ./manage.py migrate para cometer las migraciones de Django-allauth a la base
de datos.
Como de costumbre, para poder iniciar sesión en su aplicación utilizando cualquier red social que
haya agregado, deberá agregar los detalles de la cuenta social de la red.
Es posible que necesite cuentas en cada proveedor de autenticación para obtener detalles para
completar en las secciones de Aplicaciones sociales.
https://riptutorial.com/es/home 69
Capítulo 17: Ejecución de apio con
supervisor
Examples
Configuración de apio
APIO
1. Instalación - pip install django-celery
2. Añadir
- src/
- bin/celery_worker_start # will be explained later on
- logs/celery_worker.log
- stack/__init __.py
- stack/celery.py
- stack/settings.py
- stack/urls.py
- manage.py
@shared_task()
def add(x, y):
print("x*y={}".format(x*y))
https://riptutorial.com/es/home 70
celery -A stack worker -l info si también desea agregar
Supervisor de carrera
1. Crear una secuencia de comandos para iniciar el trabajador de apio. Inserte su script dentro
de su aplicación. Por ejemplo: stack/bin/celery_worker_start
#!/bin/bash
PROJECT_DIR=/home/stackoverflow/apps/proj/proj/
ENV_DIR=/home/stackoverflow/apps/proj/env/
if [ -d "${ENV_DIR}" ]
then
. "${ENV_DIR}bin/activate"
fi
[program:stack-celery-worker]
command = /home/stackoverflow/apps/stack/src/bin/celery_worker_start
user = polsha
stdout_logfile = /home/stackoverflow/apps/stack/src/logs/celery_worker.log
redirect_stderr = true
environment = LANG = en_US.UTF-8,LC_ALL = en_US.UTF-8
numprocs = 1
autostart = true
autorestart = true
startsecs = 10
stopwaitsecs = 600
priority = 998
https://riptutorial.com/es/home 71
stack-celery-worker: added process group
6. Comandos básicos
El apio requiere un corredor para manejar el paso de mensajes. Utilizamos RabbitMQ porque es
fácil de configurar y está bien soportado.
Una vez que se complete la instalación, cree un usuario, agregue un host virtual y configure los
permisos.
sudo rabbitmq-server
BROKER_URL = 'amqp://myuser:mypassword@localhost:5672/myvhost'
Este comando inicia a un trabajador de apio para ejecutar cualquier tarea definida en su
aplicación django.
https://riptutorial.com/es/home 72
Supervisor es un programa de Python que le permite controlar y seguir ejecutando cualquier
proceso de Unix. También puede reiniciar procesos estrellados. Lo usamos para asegurarnos de
que los trabajadores de Apio siempre estén corriendo.
[program:your_proj_celery]
command=/home/your_user/your_proj/.venv/bin/celery --app=your_proj.celery:app worker -l info
directory=/home/your_user/your_proj
numprocs=1
stdout_logfile=/home/your_user/your_proj/logs/celery-worker.log
stderr_logfile=/home/your_user/your_proj/logs/low-worker.log
autostart=true
autorestart=true
startsecs=10
Una vez creado y guardado nuestro archivo de configuración, podemos informar al Supervisor de
nuestro nuevo programa a través del comando supervisorctl. Primero le pedimos a Supervisor
que busque cualquier configuración de programa nueva o modificada en el directorio
/etc/supervisor/conf.d con:
Una vez que nuestros programas se estén ejecutando, indudablemente habrá un momento en el
que deseamos detenernos, reiniciar o ver su estado.
https://riptutorial.com/es/home 73
Capítulo 18: Enrutadores de base de datos
Examples
Agregar un archivo de enrutamiento de base de datos
Para usar múltiples bases de datos en Django, solo especifique cada una en settings.py :
DATABASES = {
'default': {
'NAME': 'app_data',
'ENGINE': 'django.db.backends.postgresql',
'USER': 'django_db_user',
'PASSWORD': os.environ['LOCAL_DB_PASSWORD']
},
'users': {
'NAME': 'remote_data',
'ENGINE': 'django.db.backends.mysql',
'HOST': 'remote.host.db',
'USER': 'remote_user',
'PASSWORD': os.environ['REMOTE_DB_PASSWORD']
}
}
Utilice un archivo dbrouters.py para especificar qué modelos deben operar en qué bases de datos
para cada clase de operación de base de datos, por ejemplo, para datos remotos almacenados
en remote_data , es posible que desee lo siguiente:
class DbRouter(object):
"""
A router to control all database operations on models in the
auth application.
"""
def db_for_read(self, model, **hints):
"""
Attempts to read remote models go to remote database.
"""
if model._meta.app_label == 'remote':
return 'remote_data'
return 'app_data'
https://riptutorial.com/es/home 74
obj2._meta.app_label == 'remote':
return False
return None
DATABASE_ROUTERS = ['path.to.DbRouter', ]
obj.save(using='other_db')
obj.delete(using='other_db')
MyModel.objects.using('other_db').all()
https://riptutorial.com/es/home 75
Capítulo 19: Enrutamiento de URL
Examples
Cómo Django maneja una solicitud
Django maneja una solicitud enrutando la ruta URL entrante a una función de vista. La función de
visualización es responsable de devolver una respuesta al cliente que realiza la solicitud. Las
diferentes URL son manejadas generalmente por diferentes funciones de vista. Para dirigir la
solicitud a una función de vista específica, Django analiza la configuración de su URL (o URLconf
para abreviar). La plantilla de proyecto predeterminada define el URLconf en <myproject>/urls.py .
Su URLconf debe ser un módulo de Python que define un atributo denominado urlpatterns , que
es una lista de django.conf.urls.url() de django.conf.urls.url() . Cada instancia de url() debe,
como mínimo, definir una expresión regular (una expresión regular) para que coincida con la URL
y un objetivo, que es una función de vista o un URLconf diferente. Si un patrón de URL apunta a
una función de vista, es una buena idea darle un nombre para hacer referencia fácilmente al
patrón más adelante.
# In <myproject>/urls.py
urlpatterns = [
url(r'^$', home, name='home'),
url(r'^about/$', about, name='about'),
url(r'^blog/(?P<id>\d+)/$', blog_detail, name='blog-detail'),
]
Este URLconf define tres patrones de URL, todos dirigidos a una vista: home , about y blog-detail .
La expresión regular contiene un anclaje de inicio '^', seguido inmediatamente por un anclaje de
extremo '$'. Este patrón coincidirá con las solicitudes en las que la ruta de la URL sea una cadena
vacía y las myapp.views a la vista de home definida en myapp.views .
Esta expresión regular contiene un anclaje de inicio, seguido por la cadena literal about/ , y el
anclaje final. Esto coincidirá con la URL /about/ y lo dirigirá a la vista about . Dado que cada URL
no vacía comienza con un / , Django corta convenientemente la primera barra para usted.
https://riptutorial.com/es/home 76
Este regex es un poco más complejo. Define el ancla de inicio y la cadena literal blog/ , como el
patrón anterior. La siguiente parte, (?P<id>\d+) , se llama un grupo de captura. Un grupo de
captura, como sugiere su nombre, captura una parte de la cadena, y Django pasa la cadena
capturada como un argumento a la función de vista.
La sintaxis de un grupo de captura es (?P<name>pattern) . name define el nombre del grupo, que
también es el nombre que Django usa para pasar el argumento a la vista. El patrón define qué
caracteres coinciden con el grupo.
En este caso, el nombre es id , por lo que la función blog_detail debe aceptar un parámetro
llamado id . El patrón es \d+ . \d significa que el patrón solo coincide con caracteres numéricos. +
significa que el patrón debe coincidir con uno o más caracteres.
[0-
9]{4} año (largo) Cuatro números, de cero a nueve.
año (corto)
[0-
9]{2} mes Dos números, de cero a nueve.
dia del mes
segmento de
[^/]+ Cualquier cosa excepto una barra
trayectoria
El grupo de captura en el patrón de blog-detail está seguido por un literal / y el ancla final.
Django procesa cada patrón de URL en el mismo orden en que se definen en urlpatterns . Esto
es importante si varios patrones pueden coincidir con la misma URL. Por ejemplo:
urlpatterns = [
url(r'blog/(?P<slug>[\w-]+)/$', blog_detail, name='blog-detail'),
url(r'blog/overview/$', blog_overview, name='blog-overview'),
https://riptutorial.com/es/home 77
]
urlpatterns = [
url(r'blog/overview/$', blog_overview, name='blog-overview'),
url(r'blog/(?P<slug>[\w-]+)/$', blog_detail, name='blog-detail'),
]
# In <myapp>/urls.py
from django.conf.urls import url
app_name = 'myapp'
urlpatterns = [
url(r'^$', overview, name='overview'),
]
# In <myproject>/urls.py
from django.conf.urls import include, url
urlpatterns = [
url(r'^myapp/', include('myapp.urls')),
]
Su aplicación reutilizable ahora puede revertir las URL usando el espacio de nombres de la
aplicación:
El URLconf raíz todavía puede establecer un espacio de nombres de instancia con el parámetro
de namespace :
https://riptutorial.com/es/home 78
# In <myproject>/urls.py
urlpatterns = [
url(r'^myapp/', include('myapp.urls', namespace='mynamespace')),
]
https://riptutorial.com/es/home 79
Capítulo 20: Estructura del proyecto
Examples
Repositorio> Proyecto> Sitio / Conf.
Para un proyecto Django con requirements y deployment tools bajo control de código fuente. Este
ejemplo se basa en los conceptos de las Dos cucharadas de Django . Han publicado una plantilla
:
repository/
docs/
.gitignore
project/
apps/
blog/
migrations/
static/ #( optional )
blog/
some.css
templates/ #( optional )
blog/
some.html
models.py
tests.py
admin.py
apps.py #( django 1.9 and later )
views.py
accounts/
#... ( same as blog )
search/
#... ( same as blog )
conf/
settings/
local.py
development.py
production.py
wsgi
urls.py
static/
templates/
deploy/
fabfile.py
requirements/
base.txt
local.txt
README
AUTHORS
LICENSE
Aquí, las apps y las carpetas conf contienen user created applications y core configuration folder
para el proyecto respectivamente.
static carpetas static y de templates en el directorio del project contienen archivos estáticos y
https://riptutorial.com/es/home 80
archivos de html markup , respectivamente, que se usan globalmente a lo largo del proyecto.
Y todas las carpetas de aplicaciones de blog , accounts y search también pueden (en su mayoría)
contener carpetas static y de templates .
static carpeta static y de templates en las aplicaciones también debe contener una carpeta con el
nombre de la aplicación ex. blog es una convención que se utiliza para evitar la contaminación del
espacio de nombres, por lo que hacemos referencia a los archivos como /blog/base.html lugar de
/base.html que proporciona más claridad sobre el archivo al que hacemos referencia y conserva el
espacio de nombres.
Ejemplo: templates carpeta de templates dentro del blog y las aplicaciones de search contiene un
archivo con el nombre base.html , y al hacer referencia al archivo en views su aplicación se
confunde en qué archivo se procesa.
(Project Structure)
.../project/
apps/
blog/
templates/
base.html
search/
templates/
base.html
(blog/views.py)
def some_func(request):
return render(request, "/base.html")
(search/views.py)
def some_func(request):
return render(request, "/base.html")
(Project Structure)
.../project/
apps/
blog/
templates/
blog/
base.html
search/
templates/
search/
base.html
(blog/views.py)
def some_func(request):
return render(request, "/blog/base.html")
(search/views.py)
def some_func(request):
return render(request, "/search/base.html")
https://riptutorial.com/es/home 81
Lea Estructura del proyecto en línea: https://riptutorial.com/es/django/topic/4299/estructura-del-
proyecto
https://riptutorial.com/es/home 82
Capítulo 21: Etiquetas de plantillas y filtros
Examples
Filtros personalizados
Filtros le permite aplicar una función a una variable. Esta función puede tomar 0 o 1 argumento.
Aquí está la sintaxis:
{{ variable|filter_name }}
{{ variable|filter_name:argument }}
{{ variable|filter_name:argument|another_filter }}
print(another_filter(filter_name(variable, argument)))
@register.filter
def verbose_name(model, plural=False):
"""Return the verbose name of a model.
`model` can be either:
- a Model class
- a Model instance
- a QuerySet
- any object refering to a model through a `model` attribute.
Usage:
- Get the verbose name of an object
{{ object|verbose_name }}
- Get the plural verbose name of an object from a QuerySet
{{ objects_list|verbose_name:True }}
"""
if not hasattr(model, '_meta'):
# handle the case of a QuerySet (among others)
model = model.model
opts = model._meta
if plural:
return opts.verbose_name_plural
else:
return opts.verbose_name
Etiquetas simples
https://riptutorial.com/es/home 83
La forma más sencilla de definir una etiqueta de plantilla personalizada es usar un simple_tag .
Estos son muy fáciles de configurar. El nombre de la función será el nombre de la etiqueta
(aunque puede anularlo), y los argumentos serán tokens ("palabras" separadas por espacios,
excepto los espacios entre comillas). Incluso soporta argumentos de palabras clave.
Digamos que queremos que esta etiqueta muy inútil se muestre así:
HELLO;hello world;bar:World;foo:True<br/>
HELLO;hello world;bar:World;foo:True<br/>
HELLO;hello world;bar:World;foo:True<br/>
@register.simple_tag
def useless(repeat, *args, **kwargs):
output = ';'.join(args + ['{}:{}'.format(*item) for item in kwargs.items()])
outputs = [output] * repeat
return format_html_join('\n', '{}<br/>', ((e,) for e in outputs))
format_html_join permite marcar <br/> como HTML seguro, pero no el contenido de los outputs .
A veces, lo que quieres hacer es demasiado complejo para un filter o un simple_tag . De este
modo, deberá crear una función de compilación y un renderizador.
En este ejemplo, crearemos una etiqueta de plantilla verbose_name con la siguiente sintaxis:
Ejemplo Descripción
https://riptutorial.com/es/home 84
Ejemplo Descripción
La razón por la que no podemos hacer esto con una etiqueta simple es que plural y capfirst no
son variables ni cadenas, son "palabras clave". Obviamente, podríamos decidir pasarlos como
cadenas 'plural' y 'capfirst' , pero puede entrar en conflicto con los campos con estos nombres.
¿ {% verbose_name obj 'plural' %} significaría "nombre detallado plural de obj " o "nombre
detallado de obj.plural "?
@register.tag(name='verbose_name')
def do_verbose_name(parser, token):
"""
- parser: the Parser object. We will use it to parse tokens into
nodes such as variables, strings, ...
- token: the Token object. We will use it to iterate each token
of the template tag.
"""
# Split tokens within spaces (except spaces inside quotes)
tokens = token.split_contents()
tag_name = tokens[0]
try:
# each token is a string so we need to parse it to get the actual
# variable instead of the variable name as a string.
model = parser.compile_filter(tokens[1])
except IndexError:
raise TemplateSyntaxError(
"'{}' tag requires at least 1 argument.".format(tag_name))
field_name = None
flags = {
'plural': False,
'capfirst': False,
}
bits = tokens[2:]
for bit in bits:
if bit in flags.keys():
# here we don't need `parser.compile_filter` because we expect
# 'plural' and 'capfirst' flags to be actual strings.
if flags[bit]:
raise TemplateSyntaxError(
"'{}' tag only accept one occurrence of '{}' flag".format(
tag_name, bit)
)
flags[bit] = True
continue
if field_name:
raise TemplateSyntaxError((
"'{}' tag only accept one field name at most. {} is the second "
"field name encountered."
https://riptutorial.com/es/home 85
).format(tag_name, bit)
field_name = parser.compile_filter(bit)
Y ahora el renderizador:
class VerboseNameNode(Node):
def get_field_verbose_name(self):
if self.plural:
raise ValueError("Plural is not supported for fields verbose name.")
return self.model._meta.get_field(self.field_name).verbose_name
def get_model_verbose_name(self):
if self.plural:
return self.model._meta.verbose_name_plural
else:
return self.model._meta.verbose_name
https://riptutorial.com/es/home 86
Capítulo 22: Examen de la unidad
Examples
Pruebas - un ejemplo completo
Esto supone que ha leído la documentación sobre cómo iniciar un nuevo proyecto de Django.
Supongamos que la aplicación principal de su proyecto se llama td (abreviatura de prueba). Para
crear su primera prueba, cree un archivo llamado test_view.py y copie y pegue el siguiente
contenido en él.
class ViewTest(TestCase):
def test_hello(self):
c = Client()
resp = c.get('/hello/')
self.assertEqual(resp.status_code, 200)
./manage.py test
¿Por qué sucede eso? ¡Porque no hemos definido una vista para eso! Hagamoslo. Cree un
archivo llamado views.py y coloque en él el siguiente código
urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'^hello/', views.hello),
....
]
Ahora ejecuta la prueba otra vez ./manage.py test otra vez y viola !!
https://riptutorial.com/es/home 87
Creating test database for alias 'default'...
.
----------------------------------------------------------------------
Ran 1 test in 0.004s
OK
class Author(models.Model):
name = models.CharField(max_length=50)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('view_author', args=[str(self.id)])
class Book(models.Model):
author = models.ForeignKey(Manufacturer, on_delete=models.CASCADE)
private = models.BooleanField(default=false)
publish_date = models.DateField()
def get_absolute_url(self):
return reverse('view_book', args=[str(self.id)])
def __str__(self):
return self.name
Ejemplos de prueba
class BaseModelTestCase(TestCase):
@classmethod
def setUpClass(cls):
super(BaseModelTestCase, cls).setUpClass()
cls.author = Author(name='hawking')
cls.author.save()
cls.first_book = Book(author=cls.author, name="short_history_of_time")
cls.first_book.save()
cls.second_book = Book(author=cls.author, name="long_history_of_time")
cls.second_book.save()
class AuthorModelTestCase(BaseModelTestCase):
def test_created_properly(self):
self.assertEqual(self.author.name, 'hawking')
self.assertEqual(True, self.first_book in self.author.book_set.all())
def test_absolute_url(self):
https://riptutorial.com/es/home 88
self.assertEqual(self.author.get_absolute_url(), reverse('view_author',
args=[str(self.author.id)]))
class BookModelTestCase(BaseModelTestCase):
def test_created_properly(self:
...
self.assertEqual(1, len(Book.objects.filter(name__startswith='long'))
def test_absolute_url(self):
...
Algunos puntos
Finalmente, ante la duda, escribe una prueba. Los cambios de comportamiento triviales se captan
prestando atención a los detalles y los fragmentos de código olvidados no terminan causando
problemas innecesarios.
tl; dr : crea una clase base que define dos objetos de usuario (por ejemplo, user y another_user ).
Crea tus otros modelos y define tres instancias de Client .
Ahora acceda a todas sus direcciones URL públicas y privadas desde estos tres objetos de
cliente y dicte la respuesta que espera. A continuación, muestro la estrategia para un objeto Book
que puede ser private (propiedad de unos pocos usuarios privilegiados) o public (visible para
todos).
class BaseViewTestCase(TestCase):
@classmethod
def setUpClass(cls):
super(BaseViewTestCase, cls).setUpClass()
cls.client = Client()
cls.another_client = Client()
https://riptutorial.com/es/home 89
cls.unlogged_client = Client()
cls.user = User.objects.create_user(
'dummy',password='dummy'
)
cls.user.save()
cls.another_user = User.objects.create_user(
'dummy2', password='dummy2'
)
cls.another_user.save()
cls.first_book = Book.objects.create(
name='first',
private = true
)
cls.first_book.readers.add(cls.user)
cls.first_book.save()
cls.public_book = Template.objects.create(
name='public',
private=False
)
cls.public_book.save()
def setUp(self):
self.client.login(username=self.user.username, password=self.user.username)
self.another_client.login(username=self.another_user.username,
password=self.another_user.username)
"""
Only cls.user owns the first_book and thus only he should be able to see it.
Others get 403(Forbidden) error
"""
class PrivateBookAccessTestCase(BaseViewTestCase):
def setUp(self):
super(PrivateBookAccessTestCase, self).setUp()
self.url = reverse('view_book',kwargs={'book_id':str(self.first_book.id)})
def test_user_sees_own_book(self):
response = self.client.get(self.url)
self.assertEqual(200, response.status_code)
self.assertEqual(self.first_book.name,response.context['book'].name)
self.assertTemplateUsed('myapp/book/view_template.html')
def test_user_cant_see_others_books(self):
response = self.another_client.get(self.url)
self.assertEqual(403, response.status_code)
def test_unlogged_user_cant_see_private_books(self):
response = self.unlogged_client.get(self.url)
self.assertEqual(403, response.status_code)
"""
Since book is public all three clients should be able to see the book
"""
class PublicBookAccessTestCase(BaseViewTestCase):
def setUp(self):
super(PublicBookAccessTestCase, self).setUp()
self.url = reverse('view_book',kwargs={'book_id':str(self.public_book.id)})
https://riptutorial.com/es/home 90
def test_user_sees_book(self):
response = self.client.get(self.url)
self.assertEqual(200, response.status_code)
self.assertEqual(self.public_book.name,response.context['book'].name)
self.assertTemplateUsed('myapp/book/view_template.html')
def test_another_user_sees_public_books(self):
response = self.another_client.get(self.url)
self.assertEqual(200, response.status_code)
def test_unlogged_user_sees_public_books(self):
response = self.unlogged_client.get(self.url)
self.assertEqual(200, response.status_code)
Django usa una configuración especial de la base de datos cuando realiza pruebas, de modo que
las pruebas pueden usar la base de datos normalmente, pero se ejecutan por defecto en una
base de datos vacía. Los cambios en la base de datos en una prueba no serán vistos por otra.
Por ejemplo, ambas de las siguientes pruebas pasarán:
class MyTest(TestCase):
def test_1(self):
self.assertEqual(Thing.objects.count(), 0)
Thing.objects.create()
self.assertEqual(Thing.objects.count(), 1)
def test_2(self):
self.assertEqual(Thing.objects.count(), 0)
Thing.objects.create(attr1="value")
self.assertEqual(Thing.objects.count(), 1)
Accesorios
Si desea que los objetos de la base de datos utilicen varias pruebas, puede crearlos en el método
de setUp del caso de prueba. Además, si ha definido los accesorios en su proyecto de django, se
pueden incluir así:
class MyTest(TestCase):
fixtures = ["fixture1.json", "fixture2.json"]
Por defecto, django está buscando accesorios en el directorio de fixtures en cada aplicación. Se
pueden configurar otros directorios utilizando la configuración FIXTURE_DIRS :
# myapp/settings.py
FIXTURE_DIRS = [
os.path.join(BASE_DIR, 'path', 'to', 'directory'),
]
https://riptutorial.com/es/home 91
Supongamos que ha creado un modelo de la siguiente manera:
# models.py
from django.db import models
class Person(models.Model):
"""A person defined by his/her first- and lastname."""
firstname = models.CharField(max_length=255)
lastname = models.CharField(max_length=255)
# fixture1.json
[
{ "model": "myapp.person",
"pk": 1,
"fields": {
"firstname": "Peter",
"lastname": "Griffin"
}
},
{ "model": "myapp.person",
"pk": 2,
"fields": {
"firstname": "Louis",
"lastname": "Griffin"
}
},
]
Para acelerar las pruebas de ejecución, puede indicar al comando de administración que reutilice
la base de datos de prueba (y que evite que se cree antes y se elimine después de cada
ejecución de prueba). Esto se puede hacer usando la marca keepdb (o taquigrafía -k ) de esta
manera:
Es posible limitar las pruebas ejecutadas por manage.py test especificando qué módulos debe
descubrir el corredor de prueba:
# If you split the tests file into a module with several tests files for an app
$ python manage.py test app1.tests.test_models
https://riptutorial.com/es/home 92
Si desea ejecutar un montón de pruebas, puede pasar un patrón de nombres de archivos. Por
ejemplo, es posible que desee ejecutar solo pruebas que involucren a sus modelos:
OK
FAILED (failures=1)
FAILED (failures=1)
https://riptutorial.com/es/home 93
Capítulo 23: Explotación florestal
Examples
Iniciar sesión en el servicio Syslog
Es posible configurar Django para generar un registro de salida a un servicio de syslog local o
remoto. Esta configuración utiliza el SysLogHandler incorporado en python .
https://riptutorial.com/es/home 94
Configuración básica de registro de Django.
Internamente, Django usa el sistema de registro Python. Hay muchas formas de configurar el
registro de un proyecto. Aquí hay una base:
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'default': {
'format': "[%(asctime)s] %(levelname)s [%(name)s:%(lineno)s] %(message)s",
'datefmt': "%Y-%m-%d %H:%M:%S"
},
},
'handlers': {
'console': {
'level': 'INFO',
'class': 'logging.StreamHandler',
'formatter': 'default'
},
},
'loggers': {
'django': {
'handlers': ['console'],
'propagate': True,
'level': 'INFO',
},
}
}
Formateadores
Se puede usar para configurar la aparición de los registros cuando se imprimen en la salida.
Puede definir muchos formateadores configurando una cadena de clave para cada formateador
diferente. Luego se usa un formateador cuando se declara un controlador.
Manipuladores
Se puede utilizar para configurar dónde se imprimirán los registros. En el ejemplo anterior, se
envían a stdout y stderr. Hay varias clases de manejador:
'rotated_logs': {
'class': 'logging.handlers.RotatingFileHandler',
'filename': '/var/log/my_project.log',
'maxBytes': 1024 * 1024 * 5, # 5 MB
'backupCount': 5,
'formatter': 'default'
'level': 'DEBUG',
},
Esto producirá registros en el archivo seleccionado por filename de filename . En este ejemplo, se
creará un nuevo archivo de registro cuando el actual alcance el tamaño de 5 MB (el anterior se
renombrará a my_project.log.1) y los últimos 5 archivos se guardarán para archivar.
https://riptutorial.com/es/home 95
'mail_admins': {
'level': 'ERROR',
'class': 'django.utils.log.AdminEmailHandler'
},
Esto enviará cada registro por eamil a los usuarios especificados en la variable de configuración
ADMINS . El nivel se establece en ERROR , por lo que solo los registros con nivel ERROR se enviarán por
correo electrónico. Esto es extremadamente útil para mantenerse informado sobre posibles
errores 50x en un servidor de producción.
Otros manejadores pueden usarse con Django. Para una lista completa, por favor lea la
documentación correspondiente. Al igual que los formateadores, puede definir muchos
manejadores en un mismo proyecto, estableciendo para cada cadena de clave diferente. Cada
controlador se puede utilizar en un registrador específico.
Madereros
En LOGGING , la última parte configura para cada módulo el nivel de registro mínimo, los
controladores a usar, etc.
https://riptutorial.com/es/home 96
Capítulo 24: Extendiendo o Sustituyendo
Modelo de Usuario
Examples
Modelo de usuario personalizado con correo electrónico como campo de
inicio de sesión principal.
modelos.py:
class UserManager(BaseUserManager):
def _create_user(self, email,password, is_staff, is_superuser, **extra_fields):
now = timezone.now()
if not email:
raise ValueError('users must have an email address')
email = self.normalize_email(email)
user = self.model(email = email,
is_staff = is_staff,
is_superuser = is_superuser,
last_login = now,
date_joined = now,
**extra_fields)
user.set_password(password)
user.save(using = self._db)
return user
class User(AbstractBaseUser,PermissionsMixin):
"""My own custom user class"""
objects = UserManager()
USERNAME_FIELD = 'email'
https://riptutorial.com/es/home 97
REQUIRED_FIELDS = []
class Meta:
verbose_name = _('user')
verbose_name_plural = _('users')
def get_full_name(self):
"""Return the email."""
return self.email
def get_short_name(self):
"""Return the email."""
return self.email
forms.py:
class RegistrationForm(UserCreationForm):
email = forms.EmailField(widget=forms.TextInput(
attrs={'class': 'form-control','type':'text','name': 'email'}),
label="Email")
password1 = forms.CharField(widget=forms.PasswordInput(
attrs={'class':'form-control','type':'password', 'name':'password1'}),
label="Password")
password2 = forms.CharField(widget=forms.PasswordInput(
attrs={'class':'form-control','type':'password', 'name': 'password2'}),
label="Password (again)")
def clean(self):
"""
Verifies that the values entered into the password fields match
NOTE : errors here will appear in 'non_field_errors()'
"""
cleaned_data = super(RegistrationForm, self).clean()
if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data:
if self.cleaned_data['password1'] != self.cleaned_data['password2']:
raise forms.ValidationError("Passwords don't match. Please try again!")
return self.cleaned_data
#The save(commit=False) tells Django to save the new record, but dont commit it to the
database yet
https://riptutorial.com/es/home 98
email = forms.EmailField(widget=forms.TextInput(
attrs={'class': 'form-control','type':'text','name': 'email','placeholder':'Email'}),
label='Email')
password = forms.CharField(widget=forms.PasswordInput(
attrs={'class':'form-control','type':'password', 'name':
'password','placeholder':'Password'}),
label='Password')
class Meta:
fields = ['email', 'password']
views.py:
def login(request):
if request.method == 'POST':
form = AuthenticationForm(data = request.POST)
if form.is_valid():
email = request.POST['email']
password = request.POST['password']
user = django_authenticate(email=email, password=password)
if user is not None:
if user.is_active:
django_login(request,user)
return redirect('/dashboard') #user is redirected to dashboard
else:
form = AuthenticationForm()
return render(request,'login.html',{'form':form,})
def register(request):
if request.method == 'POST':
form = RegistrationForm(data = request.POST)
if form.is_valid():
user = form.save()
u = django_authenticate(user.email = user, user.password = password)
django_login(request,u)
return redirect('/dashboard')
else:
form = RegistrationForm()
return render(request,'register.html',{'form':form,})
def logout(request):
django_logout(request)
return redirect('/')
@login_required(login_url ="/")
def dashboard(request):
return render(request, 'dashboard.html',{})
https://riptutorial.com/es/home 99
settings.py:
AUTH_USER_MODEL = 'myapp.User'
admin.py
class UserAdmin(BaseUserAdmin):
list_display = ('email','is_staff')
list_filter = ('is_staff',)
fieldsets = ((None,
{'fields':('email','password')}), ('Permissions',{'fields':('is_staff',)}),)
add_fieldsets = ((None, {'classes': ('wide',), 'fields': ('email', 'password1',
'password2')}),)
search_fields =('email',)
ordering = ('email',)
filter_horizontal = ()
admin.site.register(User, UserAdmin)
admin.site.unregister(Group)
Si desea deshacerse del campo de username de username y utilizar el email como identificador único
de usuario, tendrá que crear un modelo de User personalizado que extienda AbstractBaseUser lugar
de AbstractUser . De hecho, el username y el email se definen en AbstractUser y no puede anularlos.
Esto significa que también tendrá que redefinir todos los campos que desee que estén definidos
en AbstractUser .
class UserManager(BaseUserManager):
use_in_migrations = True
https://riptutorial.com/es/home 100
extra_fields.setdefault('is_superuser', False)
return self._create_user(email, password, **extra_fields)
class Meta:
verbose_name = _("user")
verbose_name_plural = _("users")
db_table = 'auth_user'
# `db_table` is only needed if you move from the existing default
# User model to a custom one. This enables to keep the existing data.
USERNAME_FIELD = 'email'
"""Use the email as unique username."""
GENDER_MALE = 'M'
GENDER_FEMALE = 'F'
GENDER_CHOICES = [
(GENDER_MALE, _("Male")),
(GENDER_FEMALE, _("Female")),
]
email = models.EmailField(
verbose_name=_("email address"), unique=True,
error_messages={
'unique': _(
"A user is already registered with this email address"),
},
)
gender = models.CharField(
max_length=1, blank=True, choices=GENDER_CHOICES,
verbose_name=_("gender"),
)
first_name = models.CharField(
max_length=30, verbose_name=_("first name"),
)
last_name = models.CharField(
max_length=30, verbose_name=_("last name"),
)
is_staff = models.BooleanField(
https://riptutorial.com/es/home 101
verbose_name=_("staff status"),
default=False,
help_text=_(
"Designates whether the user can log into this admin site."
),
)
is_active = models.BooleanField(
verbose_name=_("active"),
default=True,
help_text=_(
"Designates whether this user should be treated as active. "
"Unselect this instead of deleting accounts."
),
)
date_joined = models.DateTimeField(
verbose_name=_("date joined"), default=timezone.now,
)
objects = UserManager()
Cree una clase de modelo UserProfile con la relación de OneToOne con el modelo de User
predeterminado:
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='user')
photo = FileField(verbose_name=_("Profile Picture"),
upload_to=upload_to("main.UserProfile.photo", "profiles"),
format="Image", max_length=255, null=True, blank=True)
website = models.URLField(default='', blank=True)
bio = models.TextField(default='', blank=True)
phone = models.CharField(max_length=20, blank=True, default='')
city = models.CharField(max_length=100, default='', blank=True)
country = models.CharField(max_length=100, default='', blank=True)
organization = models.CharField(max_length=100, default='', blank=True)
Usando Django Signals, cree un nuevo UserProfile User inmediatamente después de crear un
objeto de User . Esta función se puede colocar debajo de la clase de modelo UserProfile en el
mismo archivo, o colocarla donde desee. No me importa, siempre y cuando lo refiera
correctamente.
https://riptutorial.com/es/home 102
inlineformset_factory al rescate
if user_form.is_valid():
created_user = user_form.save(commit=False)
formset = ProfileInlineFormset(request.POST, request.FILES,
instance=created_user)
if formset.is_valid():
created_user.save()
formset.save()
return HttpResponseRedirect('/accounts/profile/')
Nuestra plantilla
{% load material_form %}
<!-- Material form is just a materialize thing for django forms -->
<div class="col s12 m8 offset-m2">
<div class="card">
<div class="card-content">
<h2 class="flow-text">Update your information</h2>
<form action="." method="POST" class="padding">
https://riptutorial.com/es/home 103
{% csrf_token %} {{ noodle_form.as_p }}
<div class="divider"></div>
{{ formset.management_form }}
{{ formset.as_p }}
<button type="submit" class="btn-floating btn-large waves-light waves-effect"><i
class="large material-icons">done</i></button>
<a href="#" onclick="window.history.back(); return false;" title="Cancel"
class="btn-floating waves-effect waves-light red"><i class="material-icons">history</i></a>
</form>
</div>
</div>
</div>
Sobre el fragmento de código tomado de la extensión del perfil de usuario de Django como un
profesional
AUTH_USER_MODEL = 'myapp.MyUser'
Tenga en cuenta que es altamente AUTH_USER_MODEL crear AUTH_USER_MODEL antes de crear cualquier
migración o ejecutar manage.py migrate por primera vez. Debido a las limitaciones de la
característica de dependencia synamic de Django.
Por ejemplo, en su blog, es posible que desee que otros autores puedan iniciar sesión con una
dirección de correo electrónico en lugar del nombre de usuario habitual, por lo que creamos un
modelo de User personalizado con una dirección de correo electrónico como USERNAME_FIELD :
class CustomUser(AbstractBaseUser):
email = models.EmailField(unique=True)
USERNAME_FIELD = 'email'
Para que el comando Django manage.py createsuperuser sepa qué otros campos son necesarios,
podemos especificar un REQUIRED_FIELDS . Este valor no tiene efecto en otras partes de Django!
class CustomUser(AbstractBaseUser):
...
first_name = models.CharField(max_length=254)
https://riptutorial.com/es/home 104
last_name = models.CharField(max_length=254)
...
REQUIRED_FIELDS = ['first_name', 'last_name']
Para cumplir con otra parte de Django, todavía tenemos que especificar el valor is_active , las
funciones get_full_name() y get_short_name() :
class CustomUser(AbstractBaseUser):
...
is_active = models.BooleanField(default=False)
...
def get_full_name(self):
full_name = "{0} {1}".format(self.first_name, self.last_name)
return full_name.strip()
def get_short_name(self):
return self.first_name
También debe crear un UserManager personalizado para su modelo de User , que le permita a
Django usar las create_user() y create_superuser() :
class CustomUserManager(BaseUserManager):
def create_user(self, email, first_name, last_name, password=None):
if not email:
raise ValueError('Users must have an email address')
user = self.model(
email=self.normalize_email(email),
)
user.set_password(password)
user.first_name = first_name
user.last_name = last_name
user.save(using=self._db)
return user
user.is_admin = True
user.is_active = True
user.save(using=self.db)
return user
Su código no funcionará en proyectos en los que haga referencia al modelo de User ( y donde se
haya cambiado la configuración de AUTH_USER_MODEL ) directamente.
https://riptutorial.com/es/home 105
Por ejemplo: si desea crear Post modelo de Post para un blog con un modelo de User
personalizado, debe especificar el modelo de User personalizado de esta manera:
class Post(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
https://riptutorial.com/es/home 106
Capítulo 25: F () expresiones
Introducción
Una expresión F () es una forma en que Django puede usar un objeto de Python para referirse al
valor del campo del modelo o la columna anotada en la base de datos sin tener que extraer el
valor en la memoria de Python. Esto permite a los desarrolladores evitar ciertas condiciones de
carrera y también filtrar los resultados según los valores de campo del modelo.
Sintaxis
• desde django.db.models import F
Examples
Evitando las condiciones de carrera.
Vea esta pregunta de preguntas y respuestas si no sabe cuáles son las condiciones de la raza.
article = Article.objects.get(pk=69)
article.views_count += 1
article.save()
Si dos clientes acceden a este artículo al mismo tiempo, lo que puede suceder es que la segunda
solicitud HTTP ejecute Article.objects.get(pk=69) antes de que el primero ejecute article.save() .
Por lo tanto, ambas solicitudes tendrán views_count = 1337 , lo incrementarán y guardarán
views_count = 1338 en la base de datos, mientras que en realidad debería ser 1339 .
article = Article.objects.get(pk=69)
article.views_count = F('views_count') + 1
article.save()
https://riptutorial.com/es/home 107
Supongamos que queremos eliminar 2 upvotes de todos los artículos del autor con id 51 .
Hacer esto solo con Python ejecutaría N consultas (siendo N la cantidad de artículos en el conjunto
de consultas):
¿Qué pasaría si en lugar de juntar todos los artículos en Python, hacer un bucle sobre ellos,
disminuir los votos positivos y guardar cada uno actualizado en la base de datos, hubiera otra
manera?
Usando una expresión F() , puede hacerlo en una consulta:
Article.objects.filter(author_id=51).update(upvotes=F('upvotes') - 2)
• En lugar de Python haciendo el trabajo, pasamos la carga a la base de datos que se ajusta
para realizar dichas consultas.
• Reduce efectivamente el número de consultas de base de datos necesarias para lograr el
resultado deseado.
F()expresiones F() se pueden usar para ejecutar operaciones aritméticas ( + , - , * etc.) entre los
campos del modelo, para definir una búsqueda / conexión algebraica entre ellos.
class MyModel(models.Model):
int_1 = models.IntegerField()
int_2 = models.IntegerField()
• Ahora supongamos que queremos recuperar todos los objetos de la tabla MyModel int_2
campos int_1 e int_2 satisfacen esta ecuación: int_1 + int_2 >= 5 . Utilizando annotate() y
filter() obtenemos:
result = MyModel.objects.annotate(
diff=F(int_1) + F(int_2)
).filter(diff__gte=5)
https://riptutorial.com/es/home 108
Aunque el ejemplo utiliza campos Integer , este método funcionará en todos los campos en los
que se pueda aplicar una operación aritmética.
https://riptutorial.com/es/home 109
Capítulo 26: filtro django
Examples
Utilice django-filter con CBV
django-filter es un sistema genérico para filtrar Django QuerySets según las selecciones de los
usuarios. La documentación lo utiliza en una vista basada en funciones como modelo de
producto:
class Product(models.Model):
name = models.CharField(max_length=255)
price = models.DecimalField()
description = models.TextField()
release_date = models.DateField()
manufacturer = models.ForeignKey(Manufacturer)
import django_filters
class ProductFilter(django_filters.FilterSet):
name = django_filters.CharFilter(lookup_expr='iexact')
class Meta:
model = Product
fields = ['price', 'release_date']
Para usar esto en un CBV, anule get_queryset() de ListView, luego devuelva el conjunto de
querset filtrado:
class ArticleListView(ListView):
model = Product
def get_queryset(self):
qs = self.model.objects.all()
product_filtered_list = ProductFilter(self.request.GET, queryset=qs)
return product_filtered_list.qs
Es posible acceder a los objetos filtrados en sus vistas, como con la paginación, en f.qs Esto
paginará la lista de objetos filtrados.
https://riptutorial.com/es/home 110
Capítulo 27: Form Widgets
Examples
Widget de entrada de texto simple
El ejemplo más simple de widget es el ingreso de texto personalizado. Por ejemplo, para crear un
<input type="tel"> , debe subclase TextInput y establecer input_type en 'tel' .
class PhoneInput(TextInput):
input_type = 'tel'
Widget compuesto
class SelectMonthDateWidget(MultiWidget):
"""This widget allows the user to fill in a month and a year.
This represents the first day of this month or, if `last_day=True`, the
last day of this month.
"""
default_nb_years = 10
if not years:
this_year = date.today().year
years = range(this_year, this_year + self.default_nb_years)
if not months:
months = MONTHS
# Here we will use two `Select` widgets, one for months and one for years
widgets = (Select(attrs=attrs, choices=months.items()),
Select(attrs=attrs, choices=((y, y) for y in years)))
super().__init__(widgets, attrs)
https://riptutorial.com/es/home 111
def decompress(self, value):
"""Split the widget value into subwidgets values.
We expect value to be a valid date formated as `%Y-%m-%d`.
We extract month and year parts from this string.
"""
if value:
value = date(*map(int, value.split('-')))
return [value.month, value.year]
return [None, None]
https://riptutorial.com/es/home 112
Capítulo 28: Formas
Examples
Ejemplo de ModelForm
class OrderForm(forms.ModelForm):
class Meta:
model = Order
fields = ['item', 'order_date', 'customer', 'status']
class ContactForm(forms.Form):
contact_name = forms.CharField(
label="Your name", required=True,
widget=forms.TextInput(attrs={'class': 'form-control'}))
contact_email = forms.EmailField(
label="Your Email Address", required=True,
widget=forms.TextInput(attrs={'class': 'form-control'}))
content = forms.CharField(
label="Your Message", required=True,
widget=forms.Textarea(attrs={'class': 'form-control'}))
attrsatributos son atributos que se copiarán tal como están en el HTML procesado para el
formulario.
https://riptutorial.com/es/home 113
Si tenemos un modelo como el siguiente,
class UserModuleProfile(models.Model):
user = models.OneToOneField(User)
expired = models.DateTimeField()
admin = models.BooleanField(default=False)
employee_id = models.CharField(max_length=50)
organisation_name = models.ForeignKey('Organizations', on_delete=models.PROTECT)
country = models.CharField(max_length=100)
position = models.CharField(max_length=100)
def __str__(self):
return self.user
class UserProfileForm(forms.ModelForm):
admin = forms.BooleanField(label="Make this User
Admin",widget=forms.CheckboxInput(),required=False)
employee_id = forms.CharField(label="Employee Id ")
organisation_name = forms.ModelChoiceField(label='Organisation
Name',required=True,queryset=Organizations.objects.all(),empty_label="Select an Organization")
country = forms.CharField(label="Country")
position = forms.CharField(label="Position")
class Meta:
model = UserModuleProfile
fields = ('admin','employee_id','organisation_name','country','position',)
Tenga en cuenta que debajo de la clase Meta en el formulario agregué una función de inicio que
podemos usar mientras inicializamos el formulario desde views.py para eliminar un campo de
formulario (o algunas otras acciones). Te lo explicaré más tarde.
Por lo tanto, este formulario se puede utilizar para fines de registro de usuario y queremos que
todos los campos estén definidos en la clase Meta del formulario. Pero, ¿qué pasa si queremos
usar el mismo formulario cuando editamos al usuario pero cuando lo hacemos no queremos
mostrar el campo de administración del formulario?
def edit_profile(request,user_id):
context = RequestContext(request)
https://riptutorial.com/es/home 114
user = get_object_or_404(User, id=user_id)
profile = get_object_or_404(UserModuleProfile, user_id=user_id)
admin_check = False
if request.user.is_superuser:
admin_check = True
# If it's a HTTP POST, we're interested in processing form data.
if request.method == 'POST':
# Attempt to grab information from the raw form information.
profile_form =
UserProfileForm(data=request.POST,instance=profile,admin_check=admin_check)
# If the form is valid...
if profile_form.is_valid():
form_bool = request.POST.get("admin", "xxx")
if form_bool == "xxx":
form_bool_value = False
else:
form_bool_value = True
profile = profile_form.save(commit=False)
profile.user = user
profile.admin = form_bool_value
profile.save()
edited = True
else:
print profile_form.errors
return render_to_response(
'usermodule/edit_user.html',
{'id':user_id, 'profile_form': profile_form, 'edited': edited, 'user':user},
context)
Como puede ver, he mostrado aquí un ejemplo de edición simple utilizando el formulario que
creamos anteriormente. Observe que cuando inicialicé el formulario pasé una variable admin_check
adicional que contiene True o False .
Ahora, si observa el formulario que escribimos anteriormente, puede ver que en el inicio
intentamos capturar el admin_check que pasamos desde aquí. Si el valor es Falso, simplemente
eliminamos el Campo de admin del formulario y lo usamos. Y dado que este es un modelo, el
campo de administrador no puede ser nulo en el modelo, simplemente verificamos si la
publicación de formulario tenía un campo de administrador en la publicación de formulario, si no lo
configuramos como False en el código de vista en el siguiente código de vista.
https://riptutorial.com/es/home 115
En primer lugar, debemos agregar MEDIA_ROOT y MEDIA_URL a nuestro archivo settings.py
También aquí trabajará con ImageField , así que recuerde que en tales casos instale la biblioteca
Pillow ( pip install pillow ). De lo contrario, tendrá tal error:
Django viene con dos campos de formulario para cargar archivos al servidor, FileField e
ImageField , el siguiente es un ejemplo del uso de estos dos campos en nuestro formulario
forms.py:
class UploadDocumentForm(forms.Form):
file = forms.FileField()
image = forms.ImageField()
views.py:
def upload_doc(request):
form = UploadDocumentForm()
if request.method == 'POST':
form = UploadDocumentForm(request.POST, request.FILES) # Do not forget to add:
request.FILES
if form.is_valid():
# Do something with our files or simply save them
# if saved, our files would be located in media/ folder under the project's base
folder
form.save()
return render(request, 'upload_doc.html', locals())
upload_doc.html:
<html>
<head>File Uploads</head>
<body>
<form enctype="multipart/form-data" action="" method="post"> <!-- Do not forget to
add: enctype="multipart/form-data" -->
{% csrf_token %}
{{ form }}
<input type="submit" value="Save">
</form>
https://riptutorial.com/es/home 116
</body>
</html>
Ya hay formularios implementados dentro de Django para cambiar la contraseña del usuario, un
ejemplo es SetPasswordForm .
Sin embargo, no hay formularios para modificar el correo electrónico del usuario y creo que el
siguiente ejemplo es importante para entender cómo usar un formulario correctamente.
class EmailChangeForm(forms.Form):
"""
A form that lets a user change set their email while checking for a change in the
e-mail.
"""
error_messages = {
'email_mismatch': _("The two email addresses fields didn't match."),
'not_changed': _("The email address is the same as the one already defined."),
}
new_email1 = forms.EmailField(
label=_("New email address"),
widget=forms.EmailInput,
)
new_email2 = forms.EmailField(
label=_("New email address confirmation"),
widget=forms.EmailInput,
)
def clean_new_email1(self):
old_email = self.user.email
new_email1 = self.cleaned_data.get('new_email1')
if new_email1 and old_email:
if new_email1 == old_email:
raise forms.ValidationError(
self.error_messages['not_changed'],
code='not_changed',
https://riptutorial.com/es/home 117
)
return new_email1
def clean_new_email2(self):
new_email1 = self.cleaned_data.get('new_email1')
new_email2 = self.cleaned_data.get('new_email2')
if new_email1 and new_email2:
if new_email1 != new_email2:
raise forms.ValidationError(
self.error_messages['email_mismatch'],
code='email_mismatch',
)
return new_email2
def email_change(request):
form = EmailChangeForm()
if request.method=='POST':
form = Email_Change_Form(user,request.POST)
if form.is_valid():
if request.user.is_authenticated:
if form.cleaned_data['email1'] == form.cleaned_data['email2']:
user = request.user
u = User.objects.get(username=user)
# get the proper user
u.email = form.cleaned_data['email1']
u.save()
return HttpResponseRedirect("/accounts/profile/")
else:
return render_to_response("email_change.html", {'form':form},
context_instance=RequestContext(request))
https://riptutorial.com/es/home 118
Capítulo 29: Formsets
Sintaxis
• NewFormSet = formset_factory (SomeForm, extra = 2)
• formset = NewFormSet (initial = [{'some_field': 'Field Value', 'other_field': 'Other Field
Value',}])
Examples
Formsets con datos inicializados y unificados.
Formset es una forma de representar múltiples formularios en una página, como una cuadrícula de
datos. Ej .: Este ChoiceForm podría estar asociado con alguna pregunta de ordenación. Como, los
niños son los más inteligentes entre qué edad ?.
appname/forms.py
En sus vistas, puede usar el constructor formset_factory que toma Form como parámetro su
ChoiceForm en este caso y extra que describe cuántas formas adicionales distintas de las formas
inicializadas deben procesarse, y puede recorrer el objeto formset como cualquier otro. otro
iterable.
appname/views.py
import datetime
from django.forms import formset_factory
from appname.forms import ChoiceForm
ChoiceFormSet = formset_factory(ChoiceForm, extra=2)
formset = ChoiceFormSet(initial=[
{'choice': 'Between 5-15 ?',
'pub_date': datetime.date.today(),}
])
si hace un bucle sobre el formset object como este para form in formset: print (form.as_table ())
<tr>
<th><label for="id_form-0-choice">Choice:</label></th>
https://riptutorial.com/es/home 119
<td><input type="text" name="form-0-choice" value="Between 5-15 ?" id="id_form-0-choice"
/></td>
</tr>
<tr>
<th><label for="id_form-0-pub_date">Pub date:</label></th>
<td><input type="text" name="form-0-pub_date" value="2008-05-12" id="id_form-0-pub_date"
/></td>
</tr>
<tr>
<th><label for="id_form-1-choice">Choice:</label></th>
<td><input type="text" name="form-1-choice" id="id_form-1-choice" /></td>
</tr>
<tr>
<th><label for="id_form-1-pub_date">Pub date:</label></th>
<td><input type="text" name="form-1-pub_date" id="id_form-1-pub_date" /></td
</tr>
<tr>
<th><label for="id_form-2-choice">Choice:</label></th>
<td><input type="text" name="form-2-choice" id="id_form-2-choice" /></td>
</tr>
<tr>
<th><label for="id_form-2-pub_date">Pub date:</label></th>
<td><input type="text" name="form-2-pub_date" id="id_form-2-pub_date" /></td>
</tr>
https://riptutorial.com/es/home 120
Capítulo 30: Gestores personalizados y
Querysets
Examples
Definiendo un administrador básico usando Querysets y el método
`as_manager`
Django manger es una interfaz a través de la cual el modelo de django consulta la base de datos.
El campo de objects utilizado en la mayoría de las consultas de django es en realidad el
administrador predeterminado creado por nosotros por django (esto solo se crea si no definimos
administradores personalizados).
Para evitar escribir consultas comunes en todo el código base y, en su lugar, recomendarlas
utilizando una abstracción más fácil de recordar. Ejemplo: Decida usted mismo qué versión es
más legible:
Otro beneficio es que si mañana decidimos que todos los psychologists también son
dermatologists , podemos modificar fácilmente la consulta en nuestro Gerente y terminar con ella.
class ProfileQuerySet(QuerySet):
def doctors(self):
return self.filter(user_type="Doctor", user__is_active=True)
def users(self):
return self.filter(user_type="Customer", user__is_active=True)
ProfileManager = ProfileQuerySet.as_manager
class Profile(models.Model):
https://riptutorial.com/es/home 121
...
manager = ProfileManager()
NOTA : Una vez que hayamos definido un manager en nuestro modelo, los objects ya no se
definirán para el modelo.
class Book(models.Model):
name= models.CharField(max_length=50)
author = models.ForeignKey(Author)
class Author(models.Model):
name = models.CharField(max_length=50)
En vista
books = Book.objects.select_related('author').all()
Gestor personalizado
class BookManager(models.Manager):
def get_queryset(self):
qs = super().get_queryset()
return qs.select_related('author')
class Book(models.Model):
...
objects = BookManager()
books = Book.objects.all()
https://riptutorial.com/es/home 122
Definir gestores personalizados.
Muy a menudo sucede que se trata de modelos que tienen algo así como un campo published .
Este tipo de campos se utilizan casi siempre al recuperar objetos, por lo que se encontrará a sí
mismo escribiendo algo como:
my_news = News.objects.filter(published=True)
demasiadas veces. Puedes usar administradores personalizados para lidiar con estas
situaciones, de modo que luego puedas escribir algo como:
my_news = News.objects.published()
que es más agradable y más fácil de leer por otros desarrolladores también.
class NewsManager(models.Manager):
class News(models.Model):
""" News model
"""
insertion_date = models.DateTimeField('insertion date', auto_now_add=True)
title = models.CharField('title', max_length=255)
# some other fields here
published = models.BooleanField('published')
my_news = News.objects.published()
https://riptutorial.com/es/home 123
my_news = News.objects.published(title__icontains='meow')
https://riptutorial.com/es/home 124
Capítulo 31: Integración continua con
Jenkins
Examples
Jenkins 2.0+ Pipeline Script
Las versiones modernas de Jenkins (versión 2.x) vienen con un "Build Pipeline Plugin" que se
puede usar para organizar tareas de CI complejas sin crear una multitud de trabajos
interconectados, y le permite controlar fácilmente la configuración de compilación / compilación.
Aquí hay una configuración simple para los sitios de Django que requieren que solo se instalen
los módulos de python especificados del sitio.
#!/usr/bin/groovy
node {
// If you are having issues with your project not getting updated,
// try uncommenting the following lines.
//stage 'Checkout'
//checkout scm
//sh 'git submodule update --init --recursive'
stage 'Test'
// Invoke Django's tests
sh 'source env/bin/activate && python ./manage.py runtests'
}
Aquí hay un ejemplo de un script de canalización que construye un contenedor Docker y luego
ejecuta las pruebas dentro de él. El punto de entrada se supone que es ya sea manage.py o invoke
/ fabric con una runtests de comandos disponibles.
#!/usr/bin/groovy
node {
stage 'Checkout'
checkout scm
sh 'git submodule update --init --recursive'
https://riptutorial.com/es/home 125
imageName = 'mycontainer:build'
remotes = [
'dockerhub-account',
]
stage 'Build'
def djangoImage = docker.build imageName
stage 'Push'
for (int i = 0; i < remotes.size(); i++) {
sh "docker tag ${imageName} ${remotes[i]}/${imageName}"
sh "docker push ${remotes[i]}/${imageName}"
}
}
https://riptutorial.com/es/home 126
Capítulo 32: Internacionalización
Sintaxis
• gettext (mensaje)
• ngettext (singular, plural, número)
• ugettext (mensaje)
• ungettext (singular, plural, número)
• pgettext (contexto, mensaje)
• npgettext (contexto, singular, plural, número)
• gettext_lazy (mensaje)
• ngettext_lazy (singular, plural, número = ninguno)
• ugettext_lazy (mensaje)
• ungettext_lazy (singular, plural, número = ninguno)
• pgettext_lazy (contexto, mensaje)
• npgettext_lazy (contexto, singular, plural, número = ninguno)
• gettext_noop (mensaje)
• ugettext_noop (mensaje)
Examples
Introducción a la internacionalización
Configurando
settings.py
https://riptutorial.com/es/home 127
Marcando cuerdas como traducibles
El primer paso en la traducción es marcar cadenas como traducibles . Esto es pasarlos a través
de una de las funciones gettext (vea la sección de Sintaxis ). Por ejemplo, aquí hay un ejemplo de
definición de modelo:
class Child(models.Model):
class Meta:
verbose_name = _("child")
verbose_name_plural = _("children")
Todas las cadenas encapsuladas en _() ahora están marcadas como traducibles. Cuando se
imprimen, siempre se mostrarán como la cadena encapsulada, independientemente del idioma
elegido (ya que todavía no hay traducción disponible).
Traduciendo cuerdas
Este ejemplo es suficiente para comenzar con la traducción. La mayoría de las veces, solo querrá
marcar las cadenas como traducibles para anticipar la posible internacionalización de su
proyecto. Por lo tanto, esto se cubre en otro ejemplo .
https://riptutorial.com/es/home 128
>>> month = _("June")
>>> month
<django.utils.functional.lazy.<locals>.__proxy__ object at 0x7f61cb805780>
>>> str(month)
'June'
>>> activate('fr')
>>> month
<django.utils.functional.lazy.<locals>.__proxy__ object at 0x7f61cb805780>
>>> "month: {}".format(month)
'month: juin'
>>> "month: %s" % month
'month: Juni'
Traducción en plantillas
{% load i18n %}
https://riptutorial.com/es/home 129
Si first_name y last_name ya están en su contexto, incluso puede omitir la cláusula with :
Sin embargo, solo se pueden usar variables de contexto de "nivel superior". Esto no funcionará:
{% blocktrans %}
My name is {{ user.first_name }} {{ user.last_name }}
{% endblocktrans %}
Esto se debe principalmente a que el nombre de la variable se utiliza como marcador de posición
en los archivos de traducción.
{{ site_name|default:_("It works!") }}
{% firstof var1 var2 _("translatable fallback") %}
Este es un sistema de plantillas django incorporado mágico para imitar una sintaxis de llamada de
función, pero no es una llamada de función. _("It works!") Pasado a la etiqueta de plantilla
default como una cadena '_("It works!")' Que luego se analiza como una cadena traducible, tal
como el name se analiza como una variable y el "name" es analizado como una cadena.
Traduciendo cuerdas
Para traducir cadenas, deberás crear archivos de traducción. Para hacerlo, django se envía con
los comandos de gestión makemessages .
$ django-admin makemessages -l fr
processing locale fr
El comando anterior descubrirá todas las cadenas marcadas como traducibles dentro de las
aplicaciones instaladas y creará un archivo de idioma para cada aplicación para la traducción al
francés. Por ejemplo, si solo tiene una aplicación myapp contiene cadenas traducibles, esto creará
un archivo myapp/locale/fr/LC_MESSAGES/django.po . Este archivo puede parecerse a lo siguiente:
https://riptutorial.com/es/home 130
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-07-24 14:01+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <[email protected]>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: myapp/models.py:22
msgid "user"
msgstr ""
#: myapp/models.py:39
msgid "A user already exists with this email address."
msgstr ""
#: myapp/templates/myapp/register.html:155
#, python-format
msgid ""
"By signing up, you accept our <a href=\"%(terms_url)s\" "
"target=_blank>Terms of services</a>."
msgstr ""
Primero tendrá que rellenar los marcadores de posición (resaltados con mayúsculas). Luego
traduce las cuerdas. msgid es la cadena marcada como traducible en su código. msgstr es donde
tienes que escribir la traducción de la cadena de arriba.
Cuando una cadena contiene marcadores de posición, también deberá incluirlos en su traducción.
Por ejemplo, traducirás el último mensaje de la siguiente manera:
#: myapp/templates/myapp/register.html:155
#, python-format
msgid ""
"By signing up, you accept our <a href=\"%(terms_url)s\" "
"target=_blank>Terms of services</a>."
msgstr ""
"En vous inscrivant, vous acceptez nos <a href=\"%(terms_url)s\" "
"target=_blank>Conditions d'utilisation</a>"
Una vez que se termina su archivo de traducción, tendrá que compilar los .po archivos en .mo
archivos. Esto se hace llamando al compilemessages gestión de compilemessages :
$ django-admin compilemessages
Para actualizar sus archivos de traducción cuando realice cambios en su código, puede volver a
ejecutar django-admin makemessages -l fr . Esto actualizará los archivos .po , manteniendo sus
https://riptutorial.com/es/home 131
traducciones existentes y agregando las nuevas. Las cadenas eliminadas todavía estarán
disponibles en los comentarios. Para actualizar archivos .po para todos los idiomas, ejecute
django-admin makemessages -a . Una vez que se .po archivos .po , no olvide ejecutar nuevamente
los django-admin compilemessages para generar archivos .mo .
(u)gettext_noop permite marcar una cadena como traducible sin traducirla realmente.
Un caso de uso típico es cuando desea registrar un mensaje para desarrolladores (en inglés) pero
también desea mostrarlo al cliente (en el idioma solicitado). Puede pasar una variable a gettext ,
pero su contenido no se descubrirá como una cadena traducible porque es, por definición,
variable. .
logger = logging.getLogger(__name__)
El mensaje de error no aparecerá en el archivo .po y deberá recordar que existe para agregarlo
manualmente. Para solucionar esto, puede utilizar gettext_noop .
Ahora la cadena "Oops, something went wrong!" se descubrirá y estará disponible en el archivo .po
cuando se genere. Y el error todavía se registrará en inglés para los desarrolladores.
Errores comunes
traducciones difusas
A veces, los makemessages pueden pensar que la cadena que encontró para la traducción es algo
similar a la traducción ya existente. Lo hará cuando lo marque en el archivo .po con un
comentario fuzzy especial como este:
#: templates/randa/map.html:91
#, fuzzy
msgid "Country"
msgstr "Länderinfo"
https://riptutorial.com/es/home 132
Cuerdas multilínea
makemessagesanaliza los archivos en varios formatos, desde texto plano a código Python y no está
diseñado para seguir todas las reglas posibles para tener cadenas de varias líneas en esos
formatos. La mayoría de las veces funcionará bien con cadenas de una sola línea, pero si tiene
una construcción como esta:
translation = _("firstline"
"secondline"
"thirdline")
Solo recogerá firstline para la traducción. La solución para esto es evitar el uso de cadenas
multilínea cuando sea posible.
https://riptutorial.com/es/home 133
Capítulo 33: JSONField - un campo
específico de PostgreSQL
Sintaxis
• JSONField (** opciones)
Observaciones
• El JSONField de Django realmente almacena los datos en una columna JSONB Postgres, que
solo está disponible en Postgres 9.4 y posteriores.
• JSONField es genial cuando quieres un esquema más flexible. Por ejemplo, si desea cambiar
las claves sin tener que realizar ninguna migración de datos, o si no todos sus objetos
tienen la misma estructura.
• Si está almacenando datos con claves estáticas, considere usar varios campos normales en
lugar de JSONField s, ya que la consulta a JSONField puede ser bastante tediosa a veces.
Encadenar consultas
Puedes encadenar consultas juntas. Por ejemplo, si un diccionario existe dentro de una lista,
agregue dos guiones bajos y su consulta de diccionario.
Examples
Creando un campo JSON
class IceCream(models.Model):
metadata = JSONField()
https://riptutorial.com/es/home 134
Creando un objeto con datos en un campo JSON
Pase datos en forma nativa de Python, por ejemplo, list , dict , str , None , bool , etc.
IceCream.objects.create(metadata={
'date': '1/1/2016',
'ordered by': 'Jon Skeet',
'buyer': {
'favorite flavor': 'vanilla',
'known for': ['his rep on SO', 'writing a book']
},
'special requests': ['hot sauce'],
})
Obtenga todos los conos de helado que fueron ordenados por personas que les gusta el
chocolate:
IceCream.objects.filter(metadata__buyer__favorite_flavor='chocolate')
data = JSONField()
https://riptutorial.com/es/home 135
Lea JSONField - un campo específico de PostgreSQL en línea:
https://riptutorial.com/es/django/topic/1759/jsonfield---un-campo-especifico-de-postgresql
https://riptutorial.com/es/home 136
Capítulo 34: Mapeo de cadenas a cadenas
con HStoreField - un campo específico de
PostgreSQL
Sintaxis
• FooModel.objects.filter (field_name__key_name = 'valor a consultar')
Examples
Configurando HStoreField
Primero, tendremos que hacer alguna configuración para que HStoreField funcione.
class FooMigration(migrations.Migration):
# put your other migration stuff here
operations = [
HStoreExtension(),
...
]
-> Nota: asegúrese de configurar HStoreField primero antes de continuar con este
ejemplo. (encima)
class Catalog(models.model):
name = models.CharField(max_length=200)
titles_to_authors = HStoreField()
https://riptutorial.com/es/home 137
Catalog.objects.create(name='Library of Congress', titles_to_authors={
'Using HStoreField with Django': 'CrazyPython and la communidad',
'Flabbergeists and thingamajigs': 'La Artista Fooista',
'Pro Git': 'Scott Chacon and Ben Straub',
})
Usando contiene
Catalog.objects.filter(titles__contains={
'Pro Git': 'Scott Chacon and Ben Straub'})
https://riptutorial.com/es/home 138
Capítulo 35: Meta: Pautas de documentación.
Observaciones
Esta es una extensión de "Meta: Pautas de documentación" de Python para Django.
Estas son solo propuestas, no recomendaciones. Siéntase libre de editar cualquier cosa aquí si
no está de acuerdo o si tiene algo más que mencionar.
Examples
Las versiones no compatibles no necesitan una mención especial
Es poco probable que alguien use una versión no compatible de Django, y bajo su propio riesgo.
Si alguna vez alguien lo hace, debe preocuparle saber si existe una característica en la versión
dada.
1.6
Este tipo de bloque es inútil porque ninguna persona sana usa Django <1.6.
1.8
Este tipo de bloque es inútil porque ninguna persona sana usa Django <1.8.
Esto también se aplica a los temas. En el momento de escribir este ejemplo, las vistas de clase
basadas en estados admitidos son versiones 1.3-1.9 . Podemos asumir con seguridad que esto
es en realidad equivalente a All versions . Esto también evita actualizar todos los temas de las
versiones compatibles cada vez que se lanza una nueva versión.
https://riptutorial.com/es/home 139
Capítulo 36: Middleware
Introducción
Middleware en Django es un marco que permite que el código se enganche en el procesamiento
de respuesta / solicitud y altere la entrada o salida de Django.
Observaciones
Es necesario agregar middleware a su configuración.py MIDDLEWARE_CLASSES lista antes de que se
incluya en la ejecución. La lista predeterminada que proporciona Django al crear un nuevo
proyecto es la siguiente:
MIDDLEWARE_CLASSES = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
Estas son todas las funciones que se ejecutarán en orden en cada solicitud (una vez antes de
que alcance su código de vista en views.py y una vez en orden inverso para devolución de
llamada process_response , antes de la versión 1.10). Hacen una variedad de cosas, como inyectar
el token de falsificación de solicitudes en sitios cruzados (csrf) .
El orden importa porque si algún middleware realiza una redirección, el middleware subsiguiente
nunca se ejecutará. O si un middleware espera que el token csrf esté allí, tiene que ejecutarse
después del CsrfViewMiddleware .
Examples
Añadir datos a las solicitudes
Django hace que sea realmente fácil agregar datos adicionales a las solicitudes de uso dentro de
la vista. Por ejemplo, podemos analizar el subdominio en el META de la solicitud y adjuntarlo
como una propiedad separada en la solicitud mediante el uso de middleware.
class SubdomainMiddleware:
def process_request(self, request):
"""
Parse out the subdomain from the request
"""
host = request.META.get('HTTP_HOST', '')
host_s = host.replace('www.', '').split('.')
https://riptutorial.com/es/home 140
request.subdomain = None
if len(host_s) > 2:
request.subdomain = host_s[0]
Si agrega datos con middleware a su solicitud, puede acceder a los datos recién agregados más
adelante en la línea. Aquí usaremos el subdominio analizado para determinar algo como qué
organización está accediendo a su aplicación. Este enfoque es útil para las aplicaciones que se
implementan con una configuración de DNS con subdominios comodín que apuntan a una sola
instancia y la persona que accede a la aplicación desea una versión con apariencia que dependa
del punto de acceso.
class OrganizationMiddleware:
def process_request(self, request):
"""
Determine the organization based on the subdomain
"""
try:
request.org = Organization.objects.get(domain=request.subdomain)
except Organization.DoesNotExist:
request.org = None
Recuerde que el orden es importante cuando el middleware depende del otro. Para las
solicitudes, deseará que el middleware dependiente se coloque después de la dependencia.
MIDDLEWARE_CLASSES = [
...
'myapp.middleware.SubdomainMiddleware',
'myapp.middleware.OrganizationMiddleware',
...
]
yourproject/yourapp/middleware
La carpeta de middleware se debe colocar en la misma carpeta que settings.py, urls, templates ...
Importante: no olvide crear el archivo init .py vacío dentro de la carpeta de middleware para
que su aplicación reconozca esta carpeta
En lugar de tener una carpeta separada que contenga sus clases de middleware, también es
posible poner sus funciones en un solo archivo, yourproject/yourapp/middleware.py .
https://riptutorial.com/es/home 141
Ahora debemos crear un archivo para nuestro middleware personalizado. En este ejemplo,
supongamos que queremos un middleware que filtre a los usuarios según su dirección IP,
creamos un archivo llamado filter_ip_middleware.py :
#yourproject/yourapp/middleware/filter_ip_middleware.py
from django.core.exceptions import PermissionDenied
class FilterIPMiddleware(object):
# Check if client IP address is allowed
def process_request(self, request):
allowed_ips = ['192.168.1.1', '123.123.123.123', etc...] # Authorized ip's
ip = request.META.get('REMOTE_ADDR') # Get client IP address
if ip not in allowed_ips:
raise PermissionDenied # If user is not allowed raise Error
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
# Above are Django standard middlewares
¡Hecho! Ahora, cada solicitud de cada cliente llamará a su middleware personalizado y procesará
su código personalizado.
Supongamos que ha implementado alguna lógica para detectar intentos de modificar un objeto en
la base de datos, mientras que el cliente que envió los cambios no tuvo las últimas
modificaciones. Si tal caso ocurre, ConfictError(detailed_message) una excepción personalizada
ConfictError(detailed_message) .
Ahora desea devolver un código de estado HTTP 409 (Conficto) cuando se produce este error.
Por lo general, puede usarlo como middleware para esto en lugar de manejarlo en cada vista que
pueda generar esta excepción.
class ConfictErrorHandlingMiddleware:
def process_exception(self, request, exception):
if not isinstance(exception, ConflictError):
return # Propagate other exceptions, we only handle ConflictError
https://riptutorial.com/es/home 142
context = dict(confict_details=str(exception))
return TemplateResponse(request, '409.html', context, status=409)
En este nuevo estilo, un middleware es un invocable que devuelve otro invocable . Bueno, en
realidad la primera es una fábrica de middleware y la última es el middleware real .
El mejor ejemplo para ilustrar cómo funciona el middleware de nuevo estilo es probablemente
mostrar cómo hacer un middleware compatible con versiones anteriores:
class MyMiddleware:
https://riptutorial.com/es/home 143
Capítulo 37: Migraciones
Parámetros
makemigrations --name <migration_name> Genera una migración para my_app con el nombre
<my_app> migration_name
Examples
Trabajando con migraciones
Django usa migraciones para propagar los cambios que realiza a sus modelos en su base de
datos. La mayoría de las veces, django puede generarlos por ti.
https://riptutorial.com/es/home 144
Esto creará un archivo de migración en el submódulo de migration de app_name . La primera
migración se llamará 0001_initial.py , la otra comenzará con 0002_ , luego 0003 , ...
También puede llamar a revertir migraciones, esto se puede hacer pasando el nombre de la
migrate command . Dada la lista anterior de migraciones (mostrada por django-admin showmigrations
):
Migraciones manuales
A veces, las migraciones generadas por Django no son suficientes. Esto es especialmente cierto
cuando desea realizar migraciones de datos .
class Article(models.Model):
title = models.CharField(max_length=70)
class Article(models.Model):
title = models.CharField(max_length=70)
slug = models.SlugField(max_length=70)
Usted creó las migraciones para agregar el campo, pero ahora le gustaría establecer la babosa
https://riptutorial.com/es/home 145
para todos los artículos existentes, de acuerdo con su title .
$ django-admin shell
>>> from my_app.models import Article
>>> from django.utils.text import slugify
>>> for article in Article.objects.all():
... article.slug = slugify(article.title)
... article.save()
...
>>>
Pero tendrá que hacer esto en todos sus entornos (es decir, en el escritorio de su oficina, en su
computadora portátil, ...), todos sus compañeros de trabajo también deberán hacerlo, y tendrán
que pensar en ello durante la puesta en escena y al momento de presionar. vivir.
Para hacerlo de una vez por todas, lo haremos en una migración. Primero crea una migración
vacía:
Esto creará un archivo de migración vacío. Ábrelo, contiene un esqueleto base. Digamos que su
migración anterior se llamó 0023_article_slug y esta se llama 0024_auto_20160719_1734 . Esto es lo
que escribiremos en nuestro archivo de migración:
class Migration(migrations.Migration):
dependencies = [
('hosting', '0023_article_slug'),
]
operations = [
migrations.RunPython(gen_slug, reverse_code=migrations.RunPython.noop),
# We set `reverse_code` to `noop` because we cannot revert the migration
# to get it back in the previous state.
# If `reverse_code` is not given, the migration will not be reversible,
# which is not the behaviour we expect here.
]
https://riptutorial.com/es/home 146
Migraciones falsas
Cuando se ejecuta una migración, Django almacena el nombre de la migración en una tabla
django_migrations.
Si su aplicación ya tiene modelos y tablas de base de datos, y no tiene migraciones. Primero crea
migraciones iniciales para tu aplicación.
Use la makemigrations --name <your_migration_name> para permitir nombrar las migraciones en lugar
de usar un nombre generado.
Introducción
A veces, las migraciones entran en conflicto, lo que hace que la migración no tenga éxito. Esto
puede suceder en muchos escenarios, sin embargo, puede ocurrir de manera regular al
desarrollar una aplicación con un equipo.
Los conflictos de migración comunes ocurren mientras se usa el control de origen, especialmente
cuando se usa el método de característica por rama. Para este escenario, usaremos un modelo
llamado Reporter con el name y la address los atributos.
https://riptutorial.com/es/home 147
Dos desarrolladores en este punto van a desarrollar una característica, por lo que ambos obtienen
esta copia inicial del modelo Reporter . El desarrollador A agrega una age que da como resultado
el archivo 0002_reporter_age.py . El desarrollador B agrega un campo bank_account que da como
resultado 0002_reporter_bank_account . Una vez que estos desarrolladores fusionan su código e
intentan migrar las migraciones, se produjo un conflicto de migración.
Este conflicto se produce porque estas migraciones alteran el mismo modelo, Reporter . Además
de eso, los nuevos archivos comienzan con 0002.
Fusionando migraciones
Hay varias maneras de hacerlo. Lo siguiente está en el orden recomendado:
1. La solución más simple para esto es ejecutar el comando makemigrations con una marca --
merge.
En primer lugar, supongamos que este es su modelo inicial, dentro de una aplicación llamada
discography :
class Album(models.Model):
name = models.CharField(max_length=255)
artist = models.CharField(max_length=255)
Ahora, te das cuenta de que quieres usar una ForeignKey para el artista. Este es un proceso algo
complejo, que se debe realizar en varios pasos.
Paso 1, agregue un nuevo campo para ForeignKey, asegurándose de marcarlo como nulo (tenga
en cuenta que el modelo al que estamos vinculando también se incluye ahora):
class Album(models.Model):
name = models.CharField(max_length=255)
artist = models.CharField(max_length=255)
artist_link = models.ForeignKey('Artist', null=True)
https://riptutorial.com/es/home 148
class Artist(models.Model):
name = models.CharField(max_length=255)
Paso 2, rellena tu nuevo campo. Para hacer esto, tienes que crear una migración vacía.
Una vez que tenga esta migración vacía, desea agregar una sola operación RunPython para
vincular sus registros. En este caso, podría verse algo como esto:
Ahora que sus datos se transfirieron al nuevo campo, podría terminar y dejar todo como está,
usando el nuevo campo artist_link para todo. O, si desea hacer un poco de limpieza, desea
crear dos migraciones más.
Para su primera migración, querrá eliminar su campo original, artist . Para su segunda
migración, cambie el nombre del nuevo campo artist_link a artist .
Esto se realiza en varios pasos para garantizar que Django reconozca las operaciones
correctamente.
https://riptutorial.com/es/home 149
Capítulo 38: Modelo de referencia de campo
Parámetros
Parámetro Detalles
Texto que se mostrará con el campo, para ayudar a los usuarios. HTML
texto de ayuda
está permitido.
https://riptutorial.com/es/home 150
Parámetro Detalles
Observaciones
• Puede escribir sus propios campos si lo considera necesario.
• Puede anular las funciones de la clase del modelo base, más comúnmente la función save()
Examples
Campos de números
AutoField
https://riptutorial.com/es/home 151
from django.db import models
class MyModel(models.Model):
pk = models.AutoField()
BigIntegerField
class MyModel(models.Model):
number_of_seconds = models.BigIntegerField()
Campo integral
IntegerField se utiliza para almacenar valores enteros desde -2147483648 hasta 2147483647 ( 4
Bytes ).
class Food(models.Model):
name = models.CharField(max_length=255)
calorie = models.IntegerField(default=0)
PositiveIntegerField
Como un campo Integer, pero debe ser positivo o cero (0). El PositiveIntegerField se utiliza para
almacenar valores enteros de 0 a 2147483647 ( 4 Bytes ). Esto puede ser útil en un campo que
debería ser semánticamente positivo. Por ejemplo, si está registrando alimentos con sus calorías,
no debería ser negativo. Este campo evitará valores negativos a través de sus validaciones.
class Food(models.Model):
name = models.CharField(max_length=255)
calorie = models.PositiveIntegerField(default=0)
https://riptutorial.com/es/home 152
SmallIntegerField
SmallIntegerField se utiliza para almacenar valores enteros de -32768 a 32767 ( 2 Bytes ). Este
campo es útil para que los valores no sean extremos.
class Place(models.Model):
name = models.CharField(max_length=255)
temperature = models.SmallIntegerField(null=True)
PositiveSmallIntegerField
SmallIntegerField se utiliza para almacenar valores enteros de 0 a 32767 ( 2 Bytes ). Al igual que
SmallIntegerField, este campo es útil para valores que no son tan altos y debería ser
semánticamente positivo. Por ejemplo, puede almacenar la edad que no puede ser negativa.
class Staff(models.Model):
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
age = models.PositiveSmallIntegerField(null=True)
APPLICATION_NEW = 1
APPLICATION_RECEIVED = 2
APPLICATION_APPROVED = 3
APPLICATION_REJECTED = 4
APLICATION_CHOICES = (
(APPLICATION_NEW, _('New')),
(APPLICATION_RECEIVED, _('Received')),
(APPLICATION_APPROVED, _('Approved')),
(APPLICATION_REJECTED, _('Rejected')),
)
class JobApplication(models.Model):
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
status = models.PositiveSmallIntegerField(
choices=APLICATION_CHOICES,
default=APPLICATION_NEW
)
...
https://riptutorial.com/es/home 153
Campo decimal
Un número decimal de precisión fija, representado en Python por una instancia decimal. A
diferencia de IntegerField y sus derivados, este campo tiene 2 argumentos requeridos:
Si desea almacenar números de hasta 99 con 3 lugares decimales necesita usar max_digits=5 y
decimal_places=3 :
class Place(models.Model):
name = models.CharField(max_length=255)
atmospheric_pressure = models.DecimalField(max_digits=5, decimal_places=3)
Campo binario
Este es un campo especializado, utilizado para almacenar datos binarios. Solo acepta bytes . Los
datos son base64 serializados en el almacenamiento.
Como esto es almacenar datos binarios, este campo no se puede usar en un filtro.
class MyModel(models.Model):
my_binary_data = models.BinaryField()
Campo de golf
class MyModel(models.Model):
name = models.CharField(max_length=128, blank=True)
DateTimeField
class MyModel(models.Model):
start_time = models.DateFimeField(null=True, blank=True)
created_on = models.DateTimeField(auto_now_add=True)
updated_on = models.DateTimeField(auto_now=True)
https://riptutorial.com/es/home 154
Un DateTimeField tiene dos parámetros opcionales:
• auto_now_add establece el valor del campo en la fecha y hora actual cuando se crea el objeto.
• auto_now establece el valor del campo en la fecha y hora actual cada vez que se guarda el
campo.
Clave externa
El campo ForeignKey se utiliza para crear una relación de many-to-one entre los modelos. No
como la mayoría de los otros campos requiere argumentos posicionales. El siguiente ejemplo
demuestra la relación de automóvil y propietario:
class Person(models.Model):
GENDER_FEMALE = 'F'
GENDER_MALE = 'M'
GENDER_CHOICES = (
(GENDER_FEMALE, 'Female'),
(GENDER_MALE, 'Male'),
)
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
gender = models.CharField(max_length=1, choices=GENDER_CHOICES)
age = models.SmallIntegerField()
class Car(model.Model)
owner = models.ForeignKey('Person')
plate = models.CharField(max_length=15)
brand = models.CharField(max_length=50)
model = models.CharField(max_length=50)
color = models.CharField(max_length=50)
El primer argumento del campo es la clase con la que se relaciona el modelo. El segundo
argumento posicional es el argumento on_delete . En las versiones actuales, este argumento no
es necesario, pero será necesario en Django 2.0. La funcionalidad predeterminada del argumento
se muestra a continuación:
class Car(model.Model)
owner = models.ForeignKey('Person', on_delete=models.CASCADE)
...
Esto provocará que los objetos de automóvil se eliminen del modelo cuando su
propietario se elimine del modelo de persona. Esta es la funcionalidad por defecto.
class Car(model.Model)
owner = models.ForeignKey('Person', on_delete=models.PROTECT)
https://riptutorial.com/es/home 155
...
Esto evitará que los objetos Person se eliminen si están relacionados con al menos un
objeto Car. Todos los objetos de Car que hacen referencia a un objeto de Persona
deben eliminarse primero. Y luego el objeto de persona puede ser eliminado.
https://riptutorial.com/es/home 156
Capítulo 39: Modelos
Introducción
En el caso básico, un modelo es una clase de Python que se asigna a una única tabla de base de
datos. Los atributos de la clase se asignan a las columnas de la tabla y una instancia de la clase
representa una fila en la tabla de la base de datos. Los modelos heredan de
django.db.models.Model que proporciona una API enriquecida para agregar y filtrar resultados de la
base de datos.
Examples
Creando tu primer modelo
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.ForeignKey('Author', on_delete=models.CASCADE,
related_name='authored_books')
publish_date = models.DateField(null=True, blank=True)
Junto con los atributos, definimos un método __str__ devuelve el título del libro que se usará
como su representación de string cuando sea necesario, en lugar del valor predeterminado.
https://riptutorial.com/es/home 157
Aplicando los cambios a la base de datos (Migraciones).
Después de crear un nuevo modelo o modificar modelos existentes, deberá generar migraciones
para sus cambios y luego aplicar las migraciones a la base de datos especificada. Esto se puede
hacer usando el sistema de migraciones incorporado de Django. Usando la utilidad manage.py
cuando manage.py en el directorio raíz del proyecto:
El comando anterior creará los scripts de migración que son necesarios en el subdirectorio de
migrations de su aplicación. Si omite el parámetro <appname> , se procesarán todas las aplicaciones
definidas en el argumento INSTALLED_APPS de settings.py . Si lo considera necesario, puede editar
las migraciones.
Puede verificar qué migraciones son necesarias sin crear realmente la migración, use la opción --
dry-run, por ejemplo:
El comando anterior ejecutará los scripts de migración generados en el primer paso y actualizará
físicamente la base de datos.
class YourModel(models.Model):
parms = models.CharField()
class Meta:
db_table = "custom_table_name"
Si desea ver qué código SQL ejecutará una determinada migración, simplemente ejecute este
comando:
Django> 1.10
https://riptutorial.com/es/home 158
La nueva opción makemigrations --check hace que el comando salga con un estado distinto de
cero cuando se detectan cambios en el modelo sin migraciones.
class Author(models.Model):
name = models.CharField(max_length=50)
La opción más genérica. Se puede utilizar en cualquier lugar que desee representar una relación
class Topping(models.Model):
name = models.CharField(max_length=50)
# One pizza can have many toppings and same topping can be on many pizzas
class Pizza(models.Model):
name = models.CharField(max_length=50)
toppings = models.ManyToManyField(Topping)
class Service(models.Model):
name = models.CharField(max_length=35)
class Client(models.Model):
name = models.CharField(max_length=35)
age = models.IntegerField()
services = models.ManyToManyField(Service, through='Subscription')
class Subscription(models.Model):
client = models.ForeignKey(Client)
service = models.ForeignKey(Service)
subscription_type = models.CharField(max_length=1, choices=SUBSCRIPTION_TYPES)
created_at = models.DateTimeField(default=timezone.now)
De esta manera, podemos mantener más metadatos sobre una relación entre dos entidades.
Como puede verse, un cliente puede suscribirse a varios servicios a través de varios tipos de
suscripción. La única diferencia en este caso es que para agregar nuevas instancias a la relación
https://riptutorial.com/es/home 159
M2M, no se puede usar el método abreviado pizza.toppings.add(topping) , sino que se debe crear
un nuevo objeto de la clase through , Subscription.objects.create(client=client, service=service,
subscription_type='p')
class Employee(models.Model):
name = models.CharField(max_length=50)
age = models.IntegerField()
spouse = models.OneToOneField(Spouse)
class Spouse(models.Model):
name = models.CharField(max_length=50)
Utilice estos campos cuando solo tendrá una relación de composición entre los dos modelos.
Django ORM es una poderosa abstracción que le permite almacenar y recuperar datos de la base
de datos sin tener que escribir consultas SQL por su cuenta.
class Author(models.Model):
name = models.CharField(max_length=50)
class Book(models.Model):
name = models.CharField(max_length=50)
author = models.ForeignKey(Author)
Suponiendo que haya agregado el código anterior a una aplicación de django y ejecute el
comando migrate (para que se cree su base de datos). Inicia el shell Django
Esto inicia el shell estándar de Python, pero con las bibliotecas de Django relevantes importadas,
para que pueda centrarse directamente en las partes importantes.
Comience importando los modelos que acabamos de definir (supongo que esto se hace en un
archivo models.py )
>>> Author.objects.all()
[]
>>> Book.objects.all()
https://riptutorial.com/es/home 160
[]
o use la función crear para crear objetos modelo y guardar en un código de línea
>>> Book.objects.all()
[<Book: Book object>]
>>> book = Book.objects.first() #getting the first book object
>>> book.name
u'history of time'
>>> Book.objects.filter(name='nothing')
[]
>>> Author.objects.filter(name__startswith='Ste')
[<Author: Author object>]
Para obtener todos los libros publicados por Stephen Hawking (libro de búsqueda por su autor)
>>> hawking.book_set.all()
[<Book: Book object>]
_setes la notación que se usa para "búsquedas inversas", es decir, mientras el campo de
búsqueda está en el modelo de Libro, podemos usar book_set en un objeto de autor para obtener
todos sus libros.
En algún momento del uso de Django, es posible que desee interactuar con tablas que ya se han
creado o con vistas de base de datos. En estos casos, no querrá que Django administre las tablas
a través de sus migraciones. Para configurar esto, necesita agregar solo una variable a la clase
Meta su modelo: managed = False .
https://riptutorial.com/es/home 161
Este es un ejemplo de cómo puede crear un modelo no administrado para interactuar con una
vista de base de datos:
class Dummy(models.Model):
something = models.IntegerField()
class Meta:
managed = False
Una vez que haya creado este modelo, puede usarlo como lo haría con cualquier otro modelo:
>>> Dummy.objects.all()
[<Dummy: Dummy object>, <Dummy: Dummy object>, <Dummy: Dummy object>]
>>> Dummy.objects.filter(something=42)
[<Dummy: Dummy object>]
Modelos avanzados
Un modelo puede proporcionar mucha más información que solo los datos sobre un objeto.
Veamos un ejemplo y dividámoslo en lo que es útil para:
@python_2_unicode_compatible
class Book(models.Model):
slug = models.SlugField()
title = models.CharField(max_length=128)
publish_date = models.DateField()
def get_absolute_url(self):
return reverse('library:book', kwargs={'pk':self.pk})
def __str__(self):
return self.title
class Meta:
ordering = ['publish_date', 'title']
https://riptutorial.com/es/home 162
Url absoluta
La primera función que se define es get_absolute_url . De esta manera, si tiene un libro, puede
obtener un enlace a él sin tener que manipular la etiqueta url, la resolución, el atributo y similares.
Simplemente llame a book.get_absolute_url y obtendrá el enlace correcto. Como beneficio
adicional, su objeto en el administrador de django obtendrá un botón "ver en el sitio".
Representación de cuerdas
Tenga un método __str__ que le permita usar el objeto cuando necesite mostrarlo. Por ejemplo,
con el método anterior, agregar un enlace al libro en una plantilla es tan simple como <a href="{{
book.get_absolute_url }}">{{ book }}</a> . Directo al grano. Este método también controla lo que
se muestra en el menú desplegable de administración, por ejemplo, para clave externa.
El decorador de clase te permite definir el método una vez para __str__ y __unicode__ en python 2
sin causar problemas en python 3. Si esperas que tu aplicación se ejecute en ambas versiones,
esa es la manera de hacerlo.
Campo de babosa
El campo slug es similar a un campo char pero acepta menos símbolos. Por defecto, solo letras,
números, guiones bajos o guiones. Es útil si desea identificar un objeto con una buena
representación, por ejemplo, en url.
La clase meta
La clase Meta nos permite definir mucha más información sobre toda la colección de artículos.
Aquí, solo se establece el orden predeterminado. Es útil con el objeto ListView, por ejemplo. Se
necesita una lista corta ideal de campos para usar en la clasificación. Aquí, el libro se ordenará
primero por fecha de publicación y luego por título si la fecha es la misma.
Valores calculados
Una vez que se ha recuperado un objeto modelo, se convierte en una instancia completamente
realizada de la clase. Como tal, se puede acceder a cualquier método adicional en formularios y
serializadores (como Django Rest Framework).
El uso de propiedades de python es una forma elegante de representar valores adicionales que
no se almacenan en la base de datos debido a diversas circunstancias.
https://riptutorial.com/es/home 163
def expire():
return timezone.now() + timezone.timedelta(days=7)
class Coupon(models.Model):
expiration_date = models.DateField(default=expire)
@property
def is_expired(self):
return timezone.now() > self.expiration_date
Si bien la mayoría de los casos puede complementar los datos con anotaciones en sus consultas,
los valores computados como propiedades de modelo son ideales para cálculos que no pueden
evaluarse simplemente dentro del alcance de una consulta.
Además, las propiedades, ya que están declaradas en la clase python y no como parte del
esquema, no están disponibles para realizar consultas.
Para crear una presentación legible por humanos de un objeto modelo, necesita implementar el
método Model.__str__() (o Model.__unicode__() en python2). Se llamará a este método siempre
que llame a str() en una instancia de su modelo (incluido, por ejemplo, cuando el modelo se
utiliza en una plantilla). Aquí hay un ejemplo:
# your_app/models.py
class Book(models.Model):
name = models.CharField(max_length=50)
author = models.CharField(max_length=50)
>>> print(himu_book)
<Book: Book object>
<Libro: Objeto de libro> , el resultado predeterminado, no nos ayuda. Para solucionar esto,
vamos a agregar un método __str__ .
@python_2_unicode_compatible
class Book(models.Model):
name = models.CharField(max_length=50)
https://riptutorial.com/es/home 164
author = models.CharField(max_length=50)
def __str__(self):
return '{} by {}'.format(self.name, self.author)
>>> print(himu_book)
Himu Mama by Humayun Ahmed
¡Mucho mejor!
La representación de la cadena también se usa cuando el modelo se usa en los ModelForm para
ForeignKeyField y ManyToManyField .
Modelo mixins
En los mismos casos, diferentes modelos podrían tener los mismos campos y procedimientos en
el ciclo de vida del producto. Para manejar estas similitudes sin tener herencia de repetición de
código se podría utilizar. En lugar de heredar una clase completa, el patrón de diseño mixin nos
ofrece heredar ( o algunos dicen que incluyen ) algunos métodos y atributos. Veamos un ejemplo:
class PostableMixin(models.Model):
class Meta:
abstract=True
sender_name = models.CharField(max_length=128)
sender_address = models.CharField(max_length=255)
receiver_name = models.CharField(max_length=128)
receiver_address = models.CharField(max_length=255)
post_datetime = models.DateTimeField(auto_now_add=True)
delivery_datetime = models.DateTimeField(null=True)
notes = models.TextField(max_length=500)
class Envelope(PostableMixin):
ENVELOPE_COMMERCIAL = 1
ENVELOPE_BOOKLET = 2
ENVELOPE_CATALOG = 3
ENVELOPE_TYPES = (
(ENVELOPE_COMMERCIAL, 'Commercial'),
(ENVELOPE_BOOKLET, 'Booklet'),
(ENVELOPE_CATALOG, 'Catalog'),
)
envelope_type = models.PositiveSmallIntegerField(choices=ENVELOPE_TYPES)
class Package(PostableMixin):
weight = models.DecimalField(max_digits=6, decimal_places=2)
width = models.DecimalField(max_digits=5, decimal_places=2)
height = models.DecimalField(max_digits=5, decimal_places=2)
https://riptutorial.com/es/home 165
depth = models.DecimalField(max_digits=5, decimal_places=2)
Para convertir un modelo en una clase abstracta, deberá mencionar abstract=True en su clase
Meta interna. Django no crea ninguna tabla para modelos abstractos en la base de datos. Sin
embargo, para los modelos Envelope y Package , las tablas correspondientes se crearían en la base
de datos.
Además, los campos de algunos métodos de modelo serán necesarios en más de un modelo. Por
lo tanto, estos métodos podrían agregarse a mixins para evitar la repetición del código. Por
ejemplo, si creamos un método para establecer la fecha de entrega en PostableMixin , será
accesible desde sus dos hijos:
class PostableMixin(models.Model):
class Meta:
abstract=True
...
...
self.delivery_datetime = dt
self.save()
Un modelo por defecto utilizará una clave primaria de incremento automático (entero). Esto le
dará una secuencia de teclas 1, 2, 3.
import uuid
from django.db import models
class ModelUsingUUID(models.Model):
https://riptutorial.com/es/home 166
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
Herencia
La herencia de tablas múltiples creará una tabla para los campos comunes y una por ejemplo de
modelo secundario:
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
class Restaurant(Place):
serves_hot_dogs = models.BooleanField(default=False)
serves_pizza = models.BooleanField(default=False)
creará 2 tablas, una para Place y otra para Restaurant con un campo OneToOne oculto a Place para
los campos comunes.
tenga en cuenta que esto requerirá una consulta adicional a las tablas de lugares cada vez que
obtenga un objeto de restaurante.
https://riptutorial.com/es/home 167
Capítulo 40: Plantilla
Examples
Variables
En tus views.py :
class UserView(TemplateView):
""" Supply the request user object to the template """
template_name = "user.html"
En user.html :
Las variables de la plantilla no pueden acceder a los métodos que toman argumentos.
{% if user.is_authenticated %}
{% for item in menu %}
<li><a href="{{ item.url }}">{{ item.name }}</a></li>
{% endfor %}
{% else %}
<li><a href="{% url 'login' %}">Login</a>
{% endif %}
Se accede a las URL utilizando el formato {% url 'name' %} , donde los nombres corresponden a
los nombres en urls.py
https://riptutorial.com/es/home 168
{% url next %} - Las URL pueden ser variables
En tus views.py :
class ItemView(TemplateView):
template_name = "item.html"
def items(self):
""" Get all Items """
return Item.objects.all()
def certain_items(self):
""" Get certain Items """
return Item.objects.filter(model_field="certain")
def categories(self):
""" Get categories related to this Item """
return Item.objects.get(slug=self.kwargs['slug']).categories.all()
Puede utilizar una plantilla en una vista basada en funciones de la siguiente manera:
def view(request):
return render(request, "template.html")
https://riptutorial.com/es/home 169
Si desea utilizar variables de plantilla, puede hacerlo de la siguiente manera:
def view(request):
context = {"var1": True, "var2": "foo"}
return render(request, "template.html", context=context)
<html>
{% if var1 %}
<h1>{{ var2 }}</h1>
{% endif %}
</html>
Filtros de plantillas
El sistema de plantillas de Django tiene etiquetas y filtros incorporados, que son funciones dentro
de la plantilla para representar contenido de una manera específica. Se pueden especificar varios
filtros con canalizaciones y los filtros pueden tener argumentos, al igual que en la sintaxis
variable.
Para agregar sus propios filtros de plantilla, cree una carpeta llamada templatetags dentro de la
carpeta de su aplicación. Luego agregue un __init__.py , y el archivo de su archivo que contendrá
los filtros:
#/myapp/templatetags/filters.py
from django import template
register = template.Library()
@register.filter(name='tostring')
def to_string(value):
return str(value)
#templates/mytemplate.html
{% load filters %}
{% if customer_id|tostring = customer %} Welcome back {% endif%}
https://riptutorial.com/es/home 170
Trucos
A pesar de que los filtros parecen simples al principio, permite hacer algunas cosas ingeniosas:
Cuando un objeto se expone al contexto de la plantilla, sus métodos sin argumentos están
disponibles. Esto es útil cuando estas funciones son "captadores". Pero puede ser peligroso si
estos métodos alteran algunos datos o tienen algunos efectos secundarios. Aunque es probable
que confíe en el autor de la plantilla, es posible que no esté al tanto de los efectos secundarios de
una función o que piense que debe llamar al atributo incorrecto por error.
class Foobar(models.Model):
points_credit = models.IntegerField()
Esto incrementará el número de puntos cada vez que se llame a la plantilla. Y puede que ni
siquiera lo note.
Para evitar esto, debe establecer el atributo alters_data en True a los métodos que tienen efectos
secundarios. Esto hará que sea imposible llamarlos desde una plantilla.
resumen
https://riptutorial.com/es/home 171
• {% extiende%} : esto declara que la plantilla dada como argumento es la principal de la
plantilla actual. Uso: {% extends 'parent_template.html' %} .
• {% block%} {% endblock%} : esto se usa para definir secciones en sus plantillas, de modo
que si otra plantilla extiende esta, podrá reemplazar cualquier código html que se haya
escrito dentro de ella. Los bloques se identifican por su nombre. Uso: {% block content %}
<html_code> {% endblock %} .
• {% include%} : esto insertará una plantilla dentro de la actual. Tenga en cuenta que la
plantilla incluida recibirá el contexto de la solicitud y que también puede asignarle variables
personalizadas. Uso básico: {% include 'template_name.html' %} , uso con variables: {%
include 'template_name.html' with variable='value' variable2=8 %}
Guía
Supongamos que está creando su código del lado frontal con diseños comunes para todos los
códigos y no desea repetir el código para cada plantilla. Django te da en las etiquetas construidas
para hacerlo.
Supongamos que tenemos un sitio web de blog con 3 plantillas que comparten el mismo diseño:
project_directory
..
templates
front-page.html
blogs.html
blog-detail.html
<html>
<head>
</head>
<body>
{% block content %}
{% endblock %}
</body>
</html>
{% extends 'base.html' %}
{% block content %}
# write your blog related code here
{% endblock %}
Aquí blog.html el diseño base para que su diseño HTML ahora esté disponible en el blog.html
blog.html. El concepto de { % block %} es la herencia de la plantilla que le permite crear una
https://riptutorial.com/es/home 172
plantilla básica "esqueleto" que contiene todos los elementos comunes de su sitio y define los
bloques que las plantillas secundarias pueden anular.
3) Ahora suponga que todas sus 3 plantillas también tienen la misma división de HTML que define
algunas publicaciones populares. En lugar de escribirse 3 veces, cree una nueva plantilla
posts.html .
blog.html
{% extends 'base.html' %}
{% block content %}
# write your blog related code here
{% include 'posts.html' %} # includes posts.html in blog.html file without passing any
data
<!-- or -->
{% include 'posts.html' with posts=postdata %} # includes posts.html in blog.html file
with passing posts data which is context of view function returns.
{% endblock %}
https://riptutorial.com/es/home 173
Capítulo 41: Procesadores de contexto
Observaciones
Use procesadores de contexto para agregar variables que sean accesibles en cualquier parte de
sus plantillas.
Especifique una función, o funciones que devuelvan dict de las variables que desea, luego
agregue esas funciones a TEMPLATE_CONTEXT_PROCESSORS .
Examples
Utilice un procesador de contexto para acceder a settings.DEBUG en
plantillas
en myapp/context_processors.py :
def debug(request):
return {'DEBUG': settings.DEBUG}
en settings.py :
TEMPLATES = [
{
...
'OPTIONS': {
'context_processors': [
...
'myapp.context_processors.debug',
],
},
},
]
TEMPLATE_CONTEXT_PROCESSORS = (
...
'myapp.context_processors.debug',
)
https://riptutorial.com/es/home 174
Uso de un procesador de contexto para acceder a las entradas de blog más
recientes en todas las plantillas
Suponiendo que tiene un modelo llamado Post definida en su archivo models.py que contiene
publicaciones de blog y tiene un campo de fecha de date_published .
def recent_blog_posts(request):
return {'recent_posts':Post.objects.order_by('-date_published')[0:3],} # Can change
numbers for more/fewer posts
TEMPLATES = [
{
...
'OPTIONS': {
'context_processors': [
...
'myapp.context_processors.recent_blog_posts',
],
},
},
]
(En las versiones de Django anteriores a 1.9, esto se configuró directamente en settings.py
utilizando una variable TEMPLATE_CONTEXT_PROCESSORS ).
¡Ya no es necesario pasar entradas de blog recientes a través de vistas individuales! Solo usa
recent_blog_posts en cualquier plantilla.
Por ejemplo, en home.html puede crear una barra lateral con enlaces a publicaciones recientes:
<div class="blog_post_sidebar">
{% for post in recent_blog_posts %}
<div class="post">
<a href="{{post.get_absolute_url}}">{{post.title}}</a>
</div>
{% endfor %}
</div>
https://riptutorial.com/es/home 175
O en blog.html puede crear una visualización más detallada de cada publicación:
<div class="content">
{% for post in recent_blog_posts %}
<div class="post_detail">
<h2>{{post.title}}</h2>
<p>Published on {{post.date_published}}</p>
<p class="author">Written by: {{post.author}}</p>
<p><a href="{{post.get_absolute_url}}">Permalink</a></p>
<p class="post_body">{{post.body}}</p>
</div>
{% endfor %}
</div>
myapp / context_processors.py
def template_selection(request):
site_template = 'template_public.html'
if request.user.is_authenticated():
if request.user.groups.filter(name="some_group_name").exists():
site_template = 'template_new.html'
return {
'site_template': site_template,
}
{% extends site_template %}
https://riptutorial.com/es/home 176
Capítulo 42: Puntos de vista
Introducción
Una función de vista, o vista para abreviar, es simplemente una función de Python que toma una
solicitud web y devuelve una respuesta web. -Django Documentación-
Examples
[Introducción] Vista simple (Hello World Equivalent)
Vamos a crear una vista muy simple para responder a una plantilla "Hello World" en formato html.
def hello_world(request):
html = "<html><title>Hello World!</title><body>Hello World!</body></html>"
return HttpResponse(html)
urlpatterns = [
url(r'^hello_world/$', views.hello_world, name='hello_world'),
]
https://riptutorial.com/es/home 177
Capítulo 43: Querysets
Introducción
Un Queryset es fundamentalmente una lista de objetos derivados de un Model , por una
compilación de consultas de base de datos.
Examples
Consultas simples en un modelo independiente.
Aquí hay un modelo simple que usaremos para ejecutar algunas consultas de prueba:
class MyModel(models.Model):
name = models.CharField(max_length=10)
model_num = models.IntegerField()
flag = models.NullBooleanField(default=False)
MyModel.objects.get(pk=4)
MyModel.objects.all()
MyModel.objects.filter(flag=True)
MyModel.objects.filter(model_num__gt=25)
Modelos de name búsqueda simple para una cadena específica (distingue entre mayúsculas y
minúsculas)
MyModel.objects.filter(name__contains="ch")
Modelos de búsqueda simple de name para una cadena específica (no distingue mayúsculas y
https://riptutorial.com/es/home 178
minúsculas):
MyModel.objects.filter(name__icontains="ch")
Dado el modelo:
class MyModel(models.Model):
name = models.CharField(max_length=10)
model_num = models.IntegerField()
flag = models.NullBooleanField(default=False)
Podemos usar objetos Q para crear condiciones AND , OR en su consulta de búsqueda. Por ejemplo,
supongamos que queremos que todos los objetos que tienen el flag=True O model_num>15 .
Lo anterior se traduce a WHERE flag=True OR model_num > 15 manera similar para un AND que haría.
Qobjetos Q también nos permiten hacer consultas NO con el uso de ~ . Digamos que queríamos
obtener todos los objetos que tienen flag=False AND model_num!=15 , haríamos:
Nota: los objetos Q se pueden usar con cualquier función de búsqueda que tome argumentos de
palabras clave como filter , exclude , get . Asegúrese de que cuando use con get solo devolverá
un objeto o se generará la excepción MultipleObjectsReturned .
Problema
# models.py:
class Library(models.Model):
name = models.CharField(max_length=100)
books = models.ManyToManyField(Book)
https://riptutorial.com/es/home 179
class Book(models.Model):
title = models.CharField(max_length=100)
# views.py
def myview(request):
# Query the database.
libraries = Library.objects.all()
Solución
Use prefetch_related en ManyToManyField si sabe que necesitará acceder más tarde a un campo
que es un campo ManyToManyField .
# views.py
def myview(request):
# Query the database.
libraries = Library.objects.prefetch_related('books').all()
# models.py:
class User(models.Model):
name = models.CharField(max_length=100)
class Library(models.Model):
name = models.CharField(max_length=100)
books = models.ManyToManyField(Book)
class Book(models.Model):
title = models.CharField(max_length=100)
readers = models.ManyToManyField(User)
# views.py
def myview(request):
# Query the database.
libraries = Library.objects.prefetch_related('books', 'books__readers').all()
https://riptutorial.com/es/home 180
# Does not query the database again, since `books` and `readers` is pre-populated
for library in libraries:
for book in library.books.all():
for user in book.readers.all():
user.name
# ...
Sin embargo, una vez que se ha ejecutado el queryset, los datos obtenidos no pueden alterarse
sin volver a golpear la base de datos. Lo siguiente ejecutaría consultas extra por ejemplo:
# views.py
def myview(request):
# Query the database.
libraries = Library.objects.prefetch_related('books').all()
for library in libraries:
for book in library.books.filter(title__contains="Django"):
print(book.name)
Problema
Los querysets de Django se evalúan de manera perezosa. Por ejemplo:
# models.py:
class Author(models.Model):
name = models.CharField(max_length=100)
class Book(models.Model):
author = models.ForeignKey(Author, related_name='books')
title = models.CharField(max_length=100)
# views.py
def myview(request):
# Query the database
books = Book.objects.all()
https://riptutorial.com/es/home 181
for book in books:
# Query the database on each iteration to get author (len(books) times)
# if there is 100 books, there will have 100 queries plus the initial query
book.author
# ...
El código anterior hace que django consulte la base de datos del autor de cada libro. Esto es
ineficiente, y es mejor tener solo una consulta.
Solución
Utilice select_related en ForeignKey si sabe que necesitará acceder más tarde a un campo
ForeignKey .
# views.py
def myview(request):
# Query the database.
books = Books.objects.select_related('author').all()
# total : 1 query
# models.py:
class AuthorProfile(models.Model):
city = models.CharField(max_length=100)
class Author(models.Model):
name = models.CharField(max_length=100)
profile = models.OneToOneField(AuthorProfile)
class Book(models.Model):
author = models.ForeignKey(Author, related_name='books')
title = models.CharField(max_length=100)
# views.py
def myview(request):
books = Book.objects.select_related('author')\
.select_related('author__profile').all()
https://riptutorial.com/es/home 182
# total : 1 query
El atributo de query en queryset le proporciona una sintaxis equivalente a SQL para su consulta.
Advertencia:
Esta salida solo se debe utilizar para fines de depuración. La consulta generada no es
específica del backend. Como tales, los parámetros no se citan correctamente, lo que
lo hace vulnerable a la inyección de SQL, y es posible que la consulta ni siquiera sea
ejecutable en su base de datos.
MyModel.objects.first()
MyModel.objects.last()
MyModel.objects.filter(name='simple').first()
MyModel.objects.filter(name='simple').last()
Es apropiado usar objetos F() siempre que necesite hacer referencia al valor de otro campo en su
consulta. Por sí mismos, los objetos F() no significan nada, y no pueden y no deben llamarse
fuera de un queryset. Se utilizan para hacer referencia al valor de un campo en el mismo
queryset.
https://riptutorial.com/es/home 183
Por ejemplo, dado un modelo ...
SomeModel(models.Model):
...
some_field = models.IntegerField()
... un usuario puede consultar objetos donde el valor de some_field es el doble de su id haciendo
referencia al valor del campo de id mientras filtra usando F() esta manera:
SomeModel.objects.filter(some_field=F('id') * 2)
F('id') simplemente hace referencia al valor de id para esa misma instancia. Django lo usa para
crear la declaración SQL correspondiente. En este caso algo muy parecido a esto:
Sin las expresiones F() , esto se lograría con SQL sin procesar o filtrado en Python (lo que reduce
el rendimiento, especialmente cuando hay muchos objetos).
Referencias:
Nota: este ejemplo publicado provino de la respuesta que aparece arriba con el consentimiento de
TinyInstance.
https://riptutorial.com/es/home 184
Capítulo 44: RangeFields - un grupo de
campos específicos de PostgreSQL
Sintaxis
• desde django.contrib.postgres.fields import * RangeField
• IntegerRangeField (** opciones)
• BigIntegerRangeField (** opciones)
• FloatRangeField (** opciones)
• DateTimeRangeField (** opciones)
• DateRangeField (** opciones)
Examples
Incluyendo campos de rango numérico en su modelo
class Book(models.Model):
name = CharField(max_length=200)
ratings_range = IntegerRange()
Es más simple y más fácil ingresar valores como una tupla de Python en lugar de un NumericRange
.
Usando contiene
Esta consulta selecciona todos los libros con cualquier calificación inferior a tres.
https://riptutorial.com/es/home 185
bad_books = Books.objects.filter(ratings_range__contains=(1, 3))
Usando contenido_por
Esta consulta obtiene todos los libros con calificaciones mayores o iguales a cero y menores a
seis.
Usando superposición
Appointment.objects.filter(time_span__overlap=(6, 10))
Esta consulta selecciona todos los libros con una calificación mayor o igual a cuatro.
Rangos de operaciones
# Events which, at least partially, take place during the selected period.
Event.objects.filter(timeslot__overlap=period)
https://riptutorial.com/es/home 186
Capítulo 45: Relaciones de muchos a muchos
Examples
Con un modelo pasante.
class Skill(models.Model):
name = models.CharField(max_length=50)
description = models.TextField()
class Developer(models.Model):
name = models.CharField(max_length=50)
skills = models.ManyToManyField(Skill, through='DeveloperSkill')
class DeveloperSkill(models.Model):
"""Developer skills with respective ability and experience."""
class Meta:
order_with_respect_to = 'developer'
"""Sort skills per developer so that he can choose which
skills to display on top for instance.
"""
unique_together = [
('developer', 'skill'),
]
"""It's recommended that a together unique index be created on
`(developer,skill)`. This is especially useful if your database is
being access/modified from outside django. You will find that such an
index is created by django when an explicit through model is not
being used.
"""
ABILITY_CHOICES = [
(1, "Beginner"),
(2, "Accustomed"),
(3, "Intermediate"),
(4, "Strong knowledge"),
(5, "Expert"),
]
ability = models.PositiveSmallIntegerField(choices=ABILITY_CHOICES)
experience = models.PositiveSmallIntegerField(help_text="Years of experience.")
https://riptutorial.com/es/home 187
Simple muchos a muchos relación.
class Person(models.Model):
name = models.CharField(max_length=50)
description = models.TextField()
class Club(models.Model):
name = models.CharField(max_length=50)
members = models.ManyToManyField(Person)
Aquí definimos una relación donde un club tiene muchas Person y miembros y una Persona puede
ser miembro de varios Club diferentes.
Aunque solo definimos dos modelos, django crea tres tablas en la base de datos para nosotros.
Estas son myapp_person , myapp_club y myapp_club_members. Django crea automáticamente un
índice único en las myapp_club_members(club_id,person_id) .
class Person(models.Model):
name = models.CharField(max_length=50)
description = models.TextField()
class Club(models.Model):
name = models.CharField(max_length=50)
members = models.ManyToManyField(Person)
Te regalaré
Tom
Bill
https://riptutorial.com/es/home 188
Capítulo 46: Seguridad
Examples
Protección de Cross Site Scripting (XSS)
Los ataques XSS consisten en inyectar código HTML (o JS) en una página. Consulte Qué es el
script de sitios cruzados para obtener más información.
Para evitar este ataque, de forma predeterminada, Django escapa las cadenas que pasan a
través de una variable de plantilla.
context = {
'class_name': 'large" style="font-size:4000px',
'paragraph': (
"<script type=\"text/javascript\">alert('hello world!');</script>"),
}
Si tiene variables que contienen HTML en las que confía y que realmente desea representar,
debe decir explícitamente que es seguro:
Si tiene un bloque que contiene varias variables que son seguras, puede deshabilitar el escape
automático localmente:
{% autoescape off %}
<p class="{{ class_name }}">{{ paragraph }}</p>
{% endautoescape %}
<!-- Will be rendered as: -->
<p class="large" style="font-size: 4000px"><script>alert('hello world!');</script></p>
context = {
'class_name': 'large" style="font-size:4000px',
'paragraph': mark_safe(
"<script type=\"text/javascript\">alert('hello world!');</script>"),
https://riptutorial.com/es/home 189
}
Algunas utilidades de Django como format_html ya devuelven cadenas marcadas como seguras:
context = {
'var': format_html('<b>{}</b> {}', 'hello', '<i>world!</i>'),
}
Protección de clickjacking
# settings.py
MIDDLEWARE_CLASSES = [
...
'django.middleware.clickjacking.XFrameOptionsMiddleware',
...
]
X_FRAME_OPTIONS = 'DENY'
https://riptutorial.com/es/home 190
@xframe_options_sameorigin
def my_view(request, *args, **kwargs):
"""Forces 'X-Frame-Options: SAMEORIGIN'."""
return HttpResponse(...)
@method_decorator(xframe_options_deny, name='dispatch')
class MyView(View):
"""Forces 'X-Frame-Options: DENY'."""
@xframe_options_exempt_m
class MyView(View):
"""Does not set 'X-Frame-Options' header when passing through the
XFrameOptionsMiddleware.
"""
La falsificación de solicitudes entre sitios, también conocida como ataque con un solo
clic o sesión montada y abreviada como CSRF o XSRF, es un tipo de vulnerabilidad
malintencionada de un sitio web donde se transmiten comandos no autorizados de un
usuario en el que el sitio confía. Aprende más
Para habilitar la protección CSRF, agregue CsrfViewMiddleware a sus clases de middleware. Este
middleware está habilitado por defecto.
# settings.py
MIDDLEWARE_CLASSES = [
...
'django.middleware.csrf.CsrfViewMiddleware',
...
]
Este middleware establecerá un token en una cookie en la respuesta saliente. Cuando una
solicitud entrante utiliza un método inseguro (cualquier método excepto GET , HEAD , OPTIONS y TRACE
), la cookie debe coincidir con un token que se envía como datos de formulario
csrfmiddlewaretoken o como encabezado X-CsrfToken . Esto garantiza que el cliente que inicia la
solicitud también es el propietario de la cookie y, por extensión, la sesión (autenticada).
Los formularios que utilizan el método POST deben incluir el token CSRF en la plantilla. La etiqueta
de plantilla {% csrf_token %} generará un campo oculto y garantizará que la cookie esté
configurada en la respuesta:
<form method='POST'>
{% csrf_token %}
...
</form>
Las vistas individuales que no son vulnerables a los ataques CSRF pueden quedar exentas
https://riptutorial.com/es/home 191
utilizando el decorador @csrf_exempt :
@csrf_exempt
def my_view(request, *args, **kwargs):
"""Allows unsafe methods without CSRF protection"""
return HttpResponse(...)
@csrf_protect
def my_view(request, *args, **kwargs):
"""This view is protected against CSRF attacks if the middleware is disabled"""
return HttpResponse(...)
https://riptutorial.com/es/home 192
Capítulo 47: Señales
Parámetros
Observaciones
Ahora, los detalles.
Las señales de Django son una forma de informar a su aplicación de ciertas tareas (como un
modelo antes o después de guardar o eliminar) cuando se lleva a cabo.
Por ejemplo, cada vez que se crea un nuevo Usuario de Django, el Modelo de Usuario emite una
señal, con parámetros asociados como sender=User que le permite dirigir específicamente su
escucha de señales a una actividad específica que ocurre, en este caso, una nueva creación de
usuario .
La documentación de Django proporciona una amplia documentación sobre todas las posibles
señales disponibles .
Sin embargo, el ejemplo anterior es explicar en términos prácticos un caso de uso típico cuando
se usan señales puede ser una adición útil.
"Con un gran poder viene una gran responsabilidad". Puede ser tentador tener señales dispersas
en toda su aplicación o proyecto solo porque son increíbles. Bueno no lo hagas Porque son
geniales, no los convierte en la solución de referencia para cada situación simple que se le
ocurra.
Las señales son geniales para, como siempre, no todo. Login / Logouts, las señales son geniales.
Modelos clave que liberan signos, como el Modelo de Usuario, si está bien.
https://riptutorial.com/es/home 193
La creación de señales para todos y cada uno de los modelos en su aplicación puede ser
abrumadora en algún momento, y anular la idea general del uso de spjan de Django Signals.
• La señal se relaciona con un modelo en particular y se puede mover a uno de los métodos
de ese modelo, posiblemente llamado por save() .
• La señal se puede reemplazar con un método de administrador de modelos personalizado.
• La señal se relaciona con una vista particular y se puede mover a esa vista
Examples
Ejemplo de extensión de perfil de usuario
Este ejemplo es un fragmento de código extraído del perfil de usuario de Django como un
profesional.
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='user')
website = models.URLField(default='', blank=True)
bio = models.TextField(default='', blank=True)
https://riptutorial.com/es/home 194
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='user')
website = models.URLField(default='', blank=True)
bio = models.TextField(default='', blank=True)
@receiver(post_save, sender=UserProfile)
def post_save_user(sender, **kwargs):
user = kwargs.get('instance')
if kwargs.get('created'):
...
Al utilizar pre_save , podemos determinar si una acción de save en nuestra base de datos fue sobre
la actualización de un objeto existente o la creación de uno nuevo.
@receiver(pre_save, sender=User)
def pre_save_user(sender, instance, **kwargs):
if not instance._state.adding:
print ('this is an update')
else:
print ('this is an insert')
Ahora, cada vez que se realiza una acción de save , la señal de pre_save se ejecutará e imprimirá:
Tenga en cuenta que este método no requiere ninguna consulta de base de datos adicional.
Las señales de Django están restringidas a firmas de clase precisas al registrarse, y por lo tanto,
los modelos subclasificados no se registran inmediatamente en la misma señal.
class Event(models.Model):
user = models.ForeignKey(User)
class StatusChange(Event):
...
class Comment(Event):
...
https://riptutorial.com/es/home 195
"""
Fire a notification upon saving an event
"""
if not raw:
msg_factory = MessageFactory(instance.id)
msg_factory.on_activity(str(instance))
post_save.connect(send_activity_notification, Event)
Con los modelos extendidos, debe adjuntar manualmente la señal en cada subclase, de lo
contrario no se verán afectados.
post_save.connect(send_activity_notification, StatusChange)
post_save.connect(send_activity_notification, Comment)
Con Python 3.6, puede aprovechar algunos métodos de clase adicionales construidos en clases
para automatizar este enlace.
class Event(models.Model):
@classmethod
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
post_save.connect(send_activity_notification, cls)
https://riptutorial.com/es/home 196
Capítulo 48: Tareas asíncronas (Apio)
Observaciones
El apio es una cola de tareas que puede ejecutar trabajos en segundo plano o programados y se
integra bastante bien con Django. El apio requiere algo conocido como intermediario de
mensajes para pasar mensajes de invocación a los trabajadores. Este intermediario de mensajes
puede ser redis, rabbitmq o incluso Django ORM / db, aunque no es un enfoque recomendado.
Antes de comenzar con el ejemplo, deberá configurar el apio. Para configurar el apio, cree un
archivo celery_config.py en la aplicación principal, paralelo al archivo settings.py .
# broker url
BROKER_URL = 'redis://localhost:6379/0'
app = Celery('config')
app.config_from_object('django.conf:settings')
# if you do not need to keep track of results, this can be turned off
app.conf.update(
CELERY_RESULT_BACKEND=BROKER_URL,
)
# This line will tell Celery to autodiscover all your tasks.py that are in your app folders
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)
Para ejecutar el trabajo de apio, use este comando en el nivel donde se encuentra manage.py.
Examples
Ejemplo simple para sumar 2 números.
https://riptutorial.com/es/home 197
Para empezar:
@task
def add_number(x, y):
return x + y
Para verificar si la función asíncrona ha finalizado la operación, puede usar la función .ready() en
el objeto asíncrono devuelto por el método de delay .
Para obtener el resultado del cálculo, puede usar el atributo .result en el objeto asíncrono.
Ejemplo
https://riptutorial.com/es/home 198
Capítulo 49: Transacciones de base de datos
Examples
Transacciones atómicas
Problema
Por defecto, Django confirma inmediatamente los cambios en la base de datos. Cuando se
producen excepciones durante una serie de confirmaciones, esto puede dejar su base de datos
en un estado no deseado:
En el siguiente escenario:
Solución
El módulo django.db.transaction permite combinar múltiples cambios de base de datos en una
transacción atómica :
[una] serie de operaciones de base de datos de manera que ocurran todas o no ocurra
nada.
@transaction.atomic
https://riptutorial.com/es/home 199
def create_category(name, products):
category = Category.objects.create(name=name)
product_api.add_products_to_category(category, products)
activate_category(category)
https://riptutorial.com/es/home 200
Capítulo 50: Usando Redis con Django -
Caching Backend
Observaciones
El uso de django-redis-cache o django-redis son soluciones efectivas para almacenar todos los
elementos almacenados en caché. Si bien es posible que Redis se configure directamente como
SESSION_ENGINE , una estrategia efectiva es configurar el almacenamiento en caché (como se indica
arriba) y declarar su caché predeterminado como SESSION_ENGINE . Si bien este es realmente el
tema de otro artículo de documentación, su relevancia lleva a la inclusión.
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
Examples
Usando django-redis-cache
Una implementación potencial de Redis como una utilidad de almacenamiento en caché de fondo
es el paquete django-redis-cache .
Edite su settings.py para incluir un objeto CACHES (consulte la documentación de Django sobre
almacenamiento en caché ).
CACHES = {
'default': {
'BACKEND': 'redis_cache.RedisCache',
'LOCATION': 'localhost:6379',
'OPTIONS': {
'DB': 0,
}
}
}
Utilizando django-redis
Una implementación potencial de Redis como una utilidad de almacenamiento en caché de fondo
es el paquete django-redis .
https://riptutorial.com/es/home 201
$ pip install django-redis
Edite su settings.py para incluir un objeto CACHES (consulte la documentación de Django sobre
almacenamiento en caché ).
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379/1',
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
}
}
}
https://riptutorial.com/es/home 202
Capítulo 51: Vistas basadas en clase
Observaciones
Cuando usamos CBV, a menudo necesitamos saber exactamente qué métodos podemos
sobrescribir para cada clase genérica. Esta página de la documentación de django enumera todas
las clases genéricas con todos sus métodos simplificados y los atributos de clase que podemos
usar.
Además, el sitio web Classy Class Based View proporciona la misma información con una interfaz
interactiva agradable.
Examples
Vistas basadas en clase
Las vistas basadas en clase le permiten concentrarse en lo que hace que sus vistas sean
especiales.
Una página estática sobre la página puede no tener nada especial, excepto la plantilla utilizada.
Utilice un TemplateView ! Todo lo que tienes que hacer es establecer un nombre de plantilla.
Trabajo hecho. Siguiente.
vistas.py
from django.views.generic import TemplateView
class AboutView(TemplateView):
template_name = "about.html"
urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url('^about/', views.AboutView.as_view(), name='about'),
]
Observe cómo no utilizamos directamente AboutView en la url. Esto se debe a que se espera una
llamada y eso es exactamente lo que as_view() devuelve.
Datos de contexto
https://riptutorial.com/es/home 203
A veces, su plantilla necesita un poco más de información. Por ejemplo, nos gustaría tener al
usuario en el encabezado de la página, con un enlace a su perfil junto al enlace de cierre de
sesión. En estos casos, utilice el método get_context_data .
vistas.py
class BookView(DetailView):
template_name = "book.html"
libro.html
<h3>Active publishers</h3>
<ul>
{% for publisher in publishers %}
<li>{{ publisher.name }}</li>
{% endfor %}
</ul>
Las vistas de plantilla están bien para la página estática y podría usarlas para todo con
get_context_data pero sería apenas mejor que usar la función como vistas.
app / models.py
from django.db import models
class Pokemon(models.Model):
name = models.CharField(max_length=24)
species = models.CharField(max_length=48)
slug = models.CharField(max_length=48)
https://riptutorial.com/es/home 204
app / views.py
from django.views.generic import ListView, DetailView
from .models import Pokemon
class PokedexView(ListView):
""" Provide a list of Pokemon objects """
model = Pokemon
paginate_by = 25
class PokemonView(DetailView):
model = Pokemon
Eso es todo lo que necesita para generar una vista que enumere todos sus objetos de modelos y
vistas de un elemento singular. La lista está incluso paginada. Puede proporcionar template_name
si desea algo específico. Por defecto, se genera a partir del nombre del modelo.
El contexto se rellena con la lista de objetos bajo dos nombres, object_list y una segunda
compilación a partir del nombre del modelo, aquí pokemon_list . Si ha paginado la lista, también
debe cuidar el enlace anterior y el siguiente. El objeto Paginator puede ayudar con eso, también
está disponible en los datos de contexto.
Como antes, el contexto se completa con su objeto modelo bajo el nombre de object y pokemon , el
segundo se deriva del nombre del modelo.
app / urls.py
from django.conf.urls import url
https://riptutorial.com/es/home 205
from . import views
app_name = 'app'
urlpatterns = [
url(r'^pokemon/$', views.PokedexView.as_view(), name='pokedex'),
url(r'^pokemon/(?P<pk>\d+)/$', views.PokemonView.as_view(), name='pokemon'),
]
En este fragmento, la url para la vista de detalle se crea utilizando la clave principal. También es
posible usar una bala como argumento. Esto da una url más bonita que es más fácil de recordar.
Sin embargo, requiere la presencia de un campo llamado slug en su modelo.
Si un campo llamado slug no está presente, se puede utilizar el slug_field puesta en DetailView
para que apunte a un campo diferente.
Para la paginación, use una página obtener parámetros o poner una página directamente en la
url.
Escribir una vista para crear un objeto puede ser bastante aburrido. Debe mostrar un formulario,
debe validarlo, debe guardar el elemento o devolver el formulario con un error. A menos que uses
una de las vistas de edición genéricas .
app / views.py
from django.core.urlresolvers import reverse_lazy
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from .models import Pokemon
class PokemonCreate(CreateView):
model = Pokemon
fields = ['name', 'species']
class PokemonUpdate(UpdateView):
model = Pokemon
fields = ['name', 'species']
class PokemonDelete(DeleteView):
model = Pokemon
success_url = reverse_lazy('pokedex')
CreateViewy UpdateView tienen dos atributos, model y fields requeridos. De forma predeterminada,
ambos usan un nombre de plantilla basado en el nombre del modelo con el sufijo '_form'. Solo
puede cambiar el sufijo con el atributo template_name_suffix. El DeleteView muestra un mensaje
de confirmación antes de eliminar el objeto.
https://riptutorial.com/es/home 206
Tanto UpdateView como DeleteView deben DeleteView en el objeto. Utilizan el mismo método que
DetailView , extraen la variable de la URL y hacen coincidir los campos del objeto.
formcontiene el formulario con todos los campos necesarios. Aquí, se mostrará con un párrafo
para cada campo debido a as_p .
Dos problemas permanecen con el modelo, si se usa lo mismo que con la lista y el ejemplo de
detalle. En primer lugar, crear y actualizar se quejará de una URL de redireccionamiento que falta.
Eso se puede resolver agregando un get_absolute_url al modelo pokemon. El segundo problema
es que la confirmación de eliminación no muestra información significativa. Para resolver esto, la
solución más sencilla es agregar una representación de cadena.
app / models.py
from django.db import models
from django.urls import reverse
from django.utils.encoding import python_2_unicode_compatible
@python_2_unicode_compatible
class Pokemon(models.Model):
name = models.CharField(max_length=24)
https://riptutorial.com/es/home 207
species = models.CharField(max_length=48)
def get_absolute_url(self):
return reverse('app:pokemon', kwargs={'pk':self.pk})
def __str__(self):
return self.name
El decorador de la clase se asegurará de que todo funcione sin problemas bajo python 2.
Ejemplo minimo
views.py :
class MyView(View):
def get(self, request):
# <view logic>
return HttpResponse('result')
urls.py :
urlpatterns = [
url(r'^about/$', MyView.as_view()),
]
Con las vistas genéricas basadas en clase, es muy simple y fácil crear las vistas CRUD desde
nuestros modelos. A menudo, el administrador integrado de Django no es suficiente o no es el
preferido y necesitamos rodar nuestras propias vistas de CRUD. Los CBV pueden ser muy útiles
en tales casos.
La clase CreateView necesita 3 cosas: un modelo, los campos para usar y la url de éxito.
Ejemplo:
class CampaignCreateView(CreateView):
model = Campaign
fields = ('title', 'description')
success_url = "/campaigns/list"
https://riptutorial.com/es/home 208
Una vez que la creación es exitosa, el usuario es redirigido a success_url . También podemos
definir un método get_success_url en get_success_url lugar y usar reverse o reverse_lazy para
obtener la url de éxito.
Ahora, necesitamos crear una plantilla para esta vista. La plantilla debe tener un nombre en el
formato <app name>/<model name>_form.html . El nombre del modelo debe estar en mayúsculas
inferiores. Por ejemplo, si el nombre de mi aplicación es dashboard , entonces para la vista de
creación anterior, debo crear una plantilla llamada dashboard/campaign_form.html .
En la plantilla, una variable de form contendría el formulario. Aquí hay un código de ejemplo para
la plantilla:
Si visitamos la URL, deberíamos ver un formulario con los campos que elegimos. Cuando lo
enviemos, intentará crear una nueva instancia del modelo con los datos y guardarlo. En caso de
éxito, el usuario será redirigido a la URL de éxito. En caso de errores, el formulario se mostrará de
nuevo con los mensajes de error.
Este es un ejemplo rápido del uso de múltiples formularios en una vista de Django.
class AddCommentView(TemplateView):
post_form_class = AddPostForm
comment_form_class = AddCommentForm
template_name = 'blog/post.html'
context = self.get_context_data(post_form=post_form,
comment_form=comment_form)
if post_form.is_valid():
self.form_save(post_form)
https://riptutorial.com/es/home 209
if comment_form.is_valid():
self.form_save(comment_form)
return self.render_to_response(context)
https://riptutorial.com/es/home 210
Capítulo 52: Vistas genéricas
Introducción
Las vistas genéricas son vistas que realizan una determinada acción predefinida, como crear,
editar o eliminar objetos, o simplemente mostrar una plantilla.
Las vistas genéricas deben distinguirse de las vistas funcionales, que siempre se escriben a
mano para realizar las tareas requeridas. En pocas palabras, se puede decir que las vistas
genéricas deben configurarse, mientras que las vistas funcionales deben programarse.
Las vistas genéricas pueden ahorrar mucho tiempo, especialmente cuando tiene que realizar
muchas tareas estandarizadas.
Observaciones
Estos ejemplos muestran que las vistas genéricas generalmente hacen que las tareas
estandarizadas sean mucho más simples. En lugar de programar todo desde cero, configura lo
que otras personas ya han programado para usted. Esto tiene sentido en muchas situaciones, ya
que le permite concentrarse más en el diseño de sus proyectos que en los procesos en segundo
plano.
Entonces, ¿ siempre deberías usarlos? No. Solo tienen sentido siempre que sus tareas sean
bastante estandarizadas (cargar, editar, eliminar objetos) y cuanto más repetitivas sean sus
tareas. Usar una vista genérica específica solo una vez y luego anular todos sus métodos para
realizar tareas muy específicas puede que no tenga sentido. Puede que estés mejor con una vista
funcional aquí.
Sin embargo, si tiene muchas vistas que requieren esta funcionalidad o si sus tareas coinciden
exactamente con las tareas definidas de una vista genérica específica, entonces las vistas
genéricas son exactamente lo que necesita para simplificar su vida.
Examples
Ejemplo Mínimo: Funcional vs. Vistas Genéricas
Ejemplo para una vista funcional para crear un objeto. Excluyendo comentarios y líneas en
blanco, necesitamos 15 líneas de código:
# imports
from django.shortcuts import render_to_response
from django.http import HttpResponseRedirect
https://riptutorial.com/es/home 211
# view functioon
def create_object(request):
Ejemplo para una 'Vista genérica basada en clase' para realizar la misma tarea. Solo necesitamos
7 líneas de código para lograr la misma tarea:
class CreateObject(CreateView):
model = SampleObject
form_class = SampleObjectForm
success_url = 'url_to_redirect_to'
El ejemplo anterior solo funciona si sus tareas son tareas completamente estándar. No agrega
contexto adicional aquí, por ejemplo.
Hagamos un ejemplo más realista. Supongamos que queremos agregar un título de página a la
plantilla. En la vista funcional, esto funcionaría así: con solo una línea adicional:
def create_object(request):
page_title = 'My Page Title'
# ...
Esto es más difícil (o contra-intuitivo) de lograr con vistas genéricas. Como están basados en la
clase, debe anular uno o varios de los métodos de la clase para lograr el resultado deseado. En
nuestro ejemplo, necesitamos anular el método get_context_data de la clase de la siguiente
manera:
https://riptutorial.com/es/home 212
class CreateObject(CreateView):
model = SampleObject
form_class = SampleObjectForm
success_url = 'url_to_redirect_to'
Aquí, necesitamos cuatro líneas adicionales para codificar en lugar de solo una, al menos para la
primera variable de contexto adicional que deseamos agregar.
El verdadero poder de las vistas genéricas se despliega cuando las combinas con Mixins. Un
mixin es simplemente otra clase definida por usted cuyos métodos pueden ser heredados por su
clase de vista.
Supongamos que desea que cada vista muestre la variable adicional 'page_title' en la plantilla. En
lugar de anular el método get_context_data cada vez que defina la vista, cree un mixin con este
método y deje que sus vistas se hereden de este mixin. Suena más complicado de lo que
realmente es:
# Your Mixin
class CustomMixin(object):
https://riptutorial.com/es/home 213
Lea Vistas genéricas en línea: https://riptutorial.com/es/django/topic/9452/vistas-genericas
https://riptutorial.com/es/home 214
Capítulo 53: Zonas horarias
Introducción
Las zonas horarias son a menudo una molestia para los desarrolladores. Django ofrece algunas
excelentes utilidades a su disposición para facilitar el trabajo con las zonas horarias.
Incluso si su proyecto está operando en una sola zona horaria, sigue siendo una buena práctica
almacenar datos como UTC en su base de datos para manejar los casos de ahorro de luz diurna.
Si está operando en múltiples zonas horarias, almacenar datos de tiempo como UTC es una
necesidad.
Examples
Habilitar soporte de zona horaria
Si USE_TZ es Falso, TIME_ZONE será la zona horaria que Django usará para almacenar todas las
fechas de los datos. Cuando USE_TZ está habilitado, TIME_ZONE es la zona horaria predeterminada
que Django usará para mostrar los tiempos de las fechas en las plantillas e interpretar los tiempos
de los datos ingresados en los formularios.
Con el soporte de zona horaria habilitado, django almacenará los datos de datetime y datetime en
la base de datos como la zona horaria UTC
Los objetos datetime.datetime de Python tienen un atributo tzinfo que se utiliza para almacenar
información de zona horaria. Cuando se establece el atributo, el objeto se considera consciente,
cuando el atributo no se establece, se considera un ingenuo.
Para asegurarse de que una zona horaria sea ingenua o consciente, puede usar .is_naive() y
.is_aware()
Si tiene USE_TZ habilitado en su archivo settings.py , una datetime y datetime tendrá información de
zona horaria adjunta siempre que su TIME_ZONE predeterminado esté configurado en settings.py
Si bien esta zona horaria predeterminada puede ser buena en algunos casos, es probable que no
sea suficiente, especialmente si está manejando usuarios en múltiples zonas horarias. Para lograr
esto, se debe utilizar middleware.
import pytz
https://riptutorial.com/es/home 215
from django.utils import timezone
response = self.get_response(request)
return response
Hay algunas cosas nuevas que están sucediendo. Para obtener más información sobre el
middleware y lo que hace, consulte esa parte de la documentación . En __call__ estamos
manejando la configuración de los datos de la zona horaria. Al principio, nos aseguramos de que
el usuario esté autenticado, para asegurarnos de que tenemos datos de la zona horaria para este
usuario. Una vez que sabemos que lo hacemos, activamos la zona horaria para la sesión de los
usuarios utilizando timezone.activate() . Para convertir la cadena de zona horaria que tenemos a
algo utilizable por datetime, usamos pytz.timezone(str) .
{{ my_datetime_value }}
Si desea un control detallado sobre si se usa la zona horaria del usuario, mire lo siguiente:
{% load tz %}
{% localtime on %}
{# this time will be respect the users time zone #}
{{ your_date_time }}
{% endlocaltime %}
{% localtime off %}
{# this will not respect the users time zone #}
{{ your_date_time }}
{% endlocaltime %}
Tenga en cuenta que este método descrito solo funciona en Django 1.10 y en. Para admitir
https://riptutorial.com/es/home 216
django desde antes de 1.10, busque en MiddlewareMixin
https://riptutorial.com/es/home 217
Creditos
S.
Capítulos Contributors
No
Agregaciones de
4 Ian Clark, John Moutafis, ravigadila
modelos
ArrayField - un
6 campo específico de Antoine Pinsard, e4c5, noɥʇʎԀʎzɐɹƆ
PostgreSQL
Backends de
7 knbk, Rahul Gupta
autenticación
Configuración de la Ahmad Anwar, Antoine Pinsard, Evans Murithi, Kid Binary, knbk
10
base de datos , lxer, Majid, Peter Mortensen
https://riptutorial.com/es/home 218
11 CRUD en Django aisflat439, George H.
12 Depuración Antoine Pinsard, Ashutosh, e4c5, Kid Binary, knbk, Sayse, Udi
Django desde la
14 e4c5, OliPro007
línea de comandos.
Django Rest
15 The Brewmaster
Framework
Ejecución de apio
17 RéÑjïth, sebb
con supervisor
Enrutadores de base
18 fredley, knbk
de datos
Enrutamiento de
19 knbk
URL
Estructura del
20 Antoine Pinsard, naveen.panwar, nicorellius
proyecto
https://riptutorial.com/es/home 219
George H., knbk, NBajanca, nicorellius, RamenChef,
rumman0786, sudshekhar, trpt4him
29 Formsets naveen.panwar
Gestores
30 personalizados y abidibo, knbk, sudshekhar, Trivial
Querysets
Integración continua
31 pnovotnak
con Jenkins
JSONField - un
Antoine Pinsard, Daniil Ryzhkov, Matthew Schinckel, noɥʇʎԀ
33 campo específico de
ʎzɐɹƆ, Omar Shehata, techydesigner
PostgreSQL
Mapeo de cadenas a
cadenas con
34 HStoreField - un noɥʇʎԀʎzɐɹƆ
campo específico de
PostgreSQL
Meta: Pautas de
35 Antoine Pinsard
documentación.
Modelo de referencia Burhan Khalid, Husain Basrawala, knbk, Matt Seymour, Rod
38
de campo Xavier, scriptmonster, techydesigner, The_Cthulhu_Kid
https://riptutorial.com/es/home 220
Procesadores de Antoine Pinsard, Brian Artschwager, Dan Russell, Daniil
41
contexto Ryzhkov, fredley
RangeFields - un
grupo de campos
44 Antoine Pinsard, noɥʇʎԀʎzɐɹƆ
específicos de
PostgreSQL
Relaciones de
45 Antoine Pinsard, e4c5, knbk, Kostronor
muchos a muchos
Tareas asíncronas
48 iankit, Mevin Babu
(Apio)
Transacciones de
49 Ian Clark
base de datos
https://riptutorial.com/es/home 221