Apprendimento Django-It
Apprendimento Django-It
#django
Sommario
Di 1
Osservazioni 2
Versioni 2
Examples 3
Avvio di un progetto 3
Concetti di Django 5
Ambiente virtuale 7
Python 3.3+ 7
Python 2 7
Dockerfile 11
Comporre 11
nginx 12
uso 12
introduzione 14
Examples 14
Capitolo 3: Amministrazione 17
Examples 17
Cambia lista 17
views.py 20
urls.py 20
forms.py 20
admin.py 21
Sintassi 22
Osservazioni 22
Examples 22
Un ArrayField di base 22
Nesting ArrayFields 23
Interrogazione per tutti i modelli che contengono elementi in un elenco con contained_by 23
Capitolo 5: Associazione di stringhe alle stringhe con HStoreField: un campo specifico Pos 24
Sintassi 24
Examples 24
Impostazione di HStoreField 24
L'utilizzo contiene 25
Osservazioni 26
Examples 26
Examples 28
introduzione 29
Osservazioni 29
Examples 29
introduzione 33
Examples 33
Examples 34
Examples 36
MySQL / MariaDB 36
PostgreSQL 37
sqlite 38
infissi 38
Examples 41
Osservazioni 46
Examples 46
Considera di scrivere più documenti, test, log e asserzioni invece di usare un debugger 49
Capitolo 14: Distribuzione 50
Examples 50
Nginx 53
GUNICORN 54
SUPERVISORE 54
Osservazioni 57
Examples 57
Parametri 58
Examples 59
Examples 65
Examples 67
Examples 68
SEDANO 68
Supervisore in esecuzione 69
Examples 72
introduzione 82
Sintassi 82
Examples 82
Sintassi 85
Examples 85
introduzione 87
Examples 87
Examples 89
Examples 92
settings.py 93
# 1 alternativo 95
N. 2 alternativo 95
Struttura 95
Examples 99
Sintassi 101
Examples 101
Impostare 101
settings.py 101
Sintassi 108
Osservazioni 108
Examples 108
Examples 111
Convalida dei campi e impegno per modellare (Modifica e-mail utente) 115
Osservazioni 117
Examples 117
introduzione 118
Osservazioni 118
Examples 118
Parametri 122
Examples 122
Lavorare con le migrazioni 122
introduzione 125
introduzione 128
Examples 128
Eredità 138
Osservazioni 139
Examples 139
Utilizzare un processore di contesto per accedere alle impostazioni.DEBUG nei modelli 139
Utilizzo di un processore di contesto per accedere alle voci del blog più recenti in tutti 139
Estendere i tuoi modelli 141
Sintassi 142
Examples 142
Examples 144
Examples 147
Parametri 149
Osservazioni 150
Examples 150
BinaryField 153
CharField 153
DateTimeField 153
ForeignKey 154
Examples 156
Aggiunta di un file di routing del database 156
Examples 158
Imposta lo spazio dei nomi URL per un'app riutilizzabile (Django 1.9+) 160
Parametri 162
Osservazioni 162
Examples 163
introduzione 166
Examples 166
Problema 167
Soluzione 168
Problema 169
Soluzione 170
Examples 173
Examples 177
Examples 179
Examples 183
variabili 183
sommario 186
Guida 187
Examples 189
Examples 196
Problema 196
Soluzione 196
Osservazioni 198
Examples 198
Osservazioni 200
Examples 200
views.py 200
urls.py 200
views.py 201
book.html 201
Examples 208
introduzione 209
Osservazioni 209
Examples 209
Examples 213
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/it/home 1
Capitolo 1: Iniziare con Django
Osservazioni
Django si autodefinisce "il framework web per perfezionisti con scadenze" e "Django rende più
facile creare migliori app Web in modo più rapido e con meno codice". Può essere visto come
un'architettura MVC. Al suo centro ha:
Versioni
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/it/home 2
Versione Data di rilascio
1.2 2010-05-17
1.1 2009-07-29
1.0 2008-09-03
Examples
Avvio di un progetto
Django è un framework di sviluppo web basato su Python. Django 1.11 (l'ultima versione stabile)
richiede l'installazione di Python 2.7 , 3.4 , 3.5 o 3.6 . Supponendo che pip sia disponibile,
l'installazione è semplice come eseguire il seguente comando. Tieni presente che, omettendo la
versione come mostrato di seguito, verrà installata l'ultima versione di django:
Per installare una versione specifica di django, supponiamo che la versione sia django 1.10.5 ,
esegui il seguente comando:
Le applicazioni Web create con Django devono risiedere all'interno di un progetto Django. È
possibile utilizzare il comando django-admin per avviare un nuovo progetto nella directory corrente:
dove myproject è un nome che identifica in modo univoco il progetto e può essere composto da
numeri , lettere e caratteri di sottolineatura .
myproject/
manage.py
myproject/
__init__.py
settings.py
urls.py
wsgi.py
$ cd myproject
$ python manage.py runserver
Ora che il server è in esecuzione, visita http://127.0.0.1:8000/ con il browser web. Vedrai la
https://riptutorial.com/it/home 3
seguente pagina:
Per impostazione predefinita, il comando runserver avvia il server di sviluppo sull'IP interno sulla
porta 8000 . Questo server si riavvierà automaticamente quando apporti modifiche al tuo codice.
Ma nel caso si aggiungano nuovi file, sarà necessario riavviare manualmente il server.
Se si desidera modificare la porta del server, passarla come argomento della riga di comando.
Nota che runserver è solo per le build di debug e test locali. I programmi server specializzati (come
Apache) dovrebbero sempre essere utilizzati in produzione.
Un progetto Django di solito contiene più apps . Questo è semplicemente un modo per strutturare il
tuo progetto in moduli più piccoli e manutenibili. Per creare un'app, vai alla tua cartella di progetto
(dove manage.py è), ed esegui il comando startapp (cambia myapp in quello che vuoi):
Questo genererà la cartella myapp e alcuni file necessari per te, come models.py e views.py .
# myproject/settings.py
# Application definition
INSTALLED_APPS = [
...
'myapp',
]
La struttura di cartelle di un progetto Django può essere modificata in base alle tue preferenze. A
https://riptutorial.com/it/home 4
volte la cartella del progetto viene rinominata in /src per evitare di ripetere i nomi delle cartelle.
Una tipica struttura di cartelle si presenta così:
Concetti di Django
django-admin è uno strumento da riga di comando fornito con Django. Viene fornito con diversi
comandi utili per iniziare e gestire un progetto Django. Il comando è lo stesso di ./manage.py , con
la differenza che non è necessario essere nella directory del progetto. La variabile di ambiente
DJANGO_SETTINGS_MODULE deve essere impostata.
Un progetto Django è un codice Python che contiene un file di impostazioni Django. Un progetto
può essere creato dall'amministratore di Django tramite il comando django-admin startproject NAME
. manage.py il progetto ha un file chiamato manage.py al livello più alto e un file URL di root chiamato
urls.py manage.py è una versione specifica del progetto di django-admin e consente di eseguire
comandi di gestione su quel progetto. Ad esempio, per eseguire il progetto localmente, utilizzare
python manage.py runserver . Un progetto è costituito da app Django.
models.py Django è un pacchetto Python che contiene un file di modelli ( models.py per
impostazione predefinita) e altri file come URL e viste specifici dell'app. django-admin startapp NAME
può essere creata tramite il comando django-admin startapp NAME (questo comando dovrebbe
essere eseguito all'interno della directory del progetto). Affinché un'app faccia parte di un progetto,
deve essere inclusa nell'elenco INSTALLED_APPS in settings.py . Se hai usato la configurazione
standard, Django viene fornito con diverse app delle sue app preinstallate che gestiranno cose
come l' autenticazione per te. Le app possono essere utilizzate in più progetti Django.
Django ORM raccoglie tutti i modelli di database definiti in models.py e crea tabelle di database in
base a tali classi di modelli. Per fare ciò, innanzitutto, imposta il tuo database modificando
https://riptutorial.com/it/home 5
l'impostazione DATABASES in settings.py . Quindi, una volta definiti i modelli di database , eseguire
python manage.py makemigrations seguito da python manage.py migrate per creare o aggiornare lo
schema del database in base ai modelli.
Questo creerà una cartella chiamata hello che conterrà i seguenti file:
hello/
├── hello/
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── manage.py
Passaggio 3 All'interno del modulo hello (la cartella contenente __init.py__ ) crea un file
chiamato 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/it/home 6
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$', views.hello)
]
Passaggio 6
Ciao mondo
Ambiente virtuale
Impostando un ambiente virtuale diverso per ogni progetto su cui lavori, vari progetti di Django
possono essere eseguiti su diverse versioni di Python e possono mantenere i loro set di
dipendenze, senza il rischio di conflitti.
Python 3.3+
Python 3.3+ include già un modulo venv standard, che di solito si chiama pyvenv . In ambienti in cui
il comando pyvenv non è disponibile, è possibile accedere alla stessa funzionalità invocando
direttamente il modulo come python3 -m venv .
$ pyvenv <env-folder>
# Or, if pyvenv is not available
$ python3 -m venv <env-folder>
Python 2
Se si utilizza Python 2, è possibile prima installarlo come un modulo separato da pip:
https://riptutorial.com/it/home 7
E quindi creare l'ambiente usando invece il comando virtualenv :
$ virtualenv <env-folder>
Linux come:
$ source <env-folder>/bin/activate
Windows come:
<env-folder>\Scripts\activate.bat
Questo cambia la tua richiesta di indicare che l'ambiente virtuale è attivo. (<env-folder>) $
D'ora in poi, tutto ciò che verrà installato usando pip sarà installato nella tua cartella env virtuale,
non in tutto il sistema.
(<env-folder>) $ deactivate
# Create a virtualenv
mkvirtualenv my_virtualenv
# Activate a virtualenv
workon my_virtualenv
https://riptutorial.com/it/home 8
virtualenv con pyenv-virtualenv:
#!/bin/sh
# This hook is sourced after this virtualenv is activated
Crea un nuovo file chiamato <env-folder>/.project . Il contenuto del file dovrebbe essere SOLO il
percorso della directory del progetto.
/path/to/project/directory
Ora avvia il tuo ambiente virtuale (usando source <env-folder>/bin/activate o workon my_virtualenv
) e il tuo terminale cambierà directory in /path/to/project/directory .
Questo esempio mostra un modo minimo per creare una pagina Hello World in Django. Questo ti
aiuterà a capire che il comando di django-admin startproject example crea fondamentalmente un
sacco di cartelle e file e che non hai necessariamente bisogno di quella struttura per eseguire il
tuo progetto.
https://riptutorial.com/it/home 9
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. Vai al terminale ed esegui il file con questo comando python file.py runserver .
Il modello di progetto Django di default va bene, ma una volta che hai implementato il tuo codice e
per esempio gli sviluppatori hanno messo le mani sul progetto, le cose si complicano. Quello che
puoi fare è separare il tuo codice sorgente dal resto che è necessario che sia nel tuo repository.
https://riptutorial.com/it/home 10
└── src
├── manage.py
└── project_name
├── __init__.py
└── service
├── __init__.py
├── settings
│ ├── common.py
│ ├── development.py
│ ├── __init__.py
│ └── staging.py
├── urls.py
└── wsgi.py
Mi piace mantenere la directory dei service denominata service per ogni progetto grazie al fatto
che posso utilizzare lo stesso Dockerfile su tutti i miei progetti. La suddivisione dei requisiti e delle
impostazioni è già ben documentata qui:
Utilizzo di più file di requisiti
Utilizzando più impostazioni
Dockerfile
Partendo dal presupposto che solo gli sviluppatori fanno uso di Docker (non tutti gli sviluppatori si
fidano di questi tempi). Questo potrebbe essere un dev devel.dockerfile dell'ambiente di
devel.dockerfile :
FROM python:2.7
ENV PYTHONUNBUFFERED 1
WORKDIR /run/service/src
ENTRYPOINT ["python", "manage.py"]
CMD ["runserver", "0.0.0.0:8000"]
L'aggiunta di soli requisiti consentirà di sfruttare la cache Docker durante la creazione: sarà
necessario ricostruire solo in base alla modifica dei requisiti.
Comporre
La composizione di Docker è utile, specialmente quando si dispone di più servizi per l'esecuzione
locale. docker-compose.yml :
version: '2'
services:
https://riptutorial.com/it/home 11
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
Il tuo ambiente di sviluppo dovrebbe essere il più vicino possibile all'ambiente prod, quindi mi
piace usare Nginx sin dall'inizio. Ecco un esempio di file di configurazione di 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;
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/;
}
}
https://riptutorial.com/it/home 12
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/it/home 13
Capitolo 2: Aggregazioni di modelli
introduzione
Le aggregazioni sono metodi che consentono l'esecuzione di operazioni su (singoli e / o gruppi di)
righe di oggetti derivati da un modello.
Examples
Media, Minima, Massima, Somma da 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/it/home 14
>>> categories = Category.objects.annotate(Count('product'))
Puoi fornire un nome personalizzato per il tuo attributo utilizzando un argomento di parole chiave:
>>> categories.order_by('num_products')
[<Category: Footwear>, <Category: Clothing>]
>>> categories.filter(num_products__gt=20)
[<Category: Clothing>]
Siamo in grado di eseguire un GROUP BY ... COUNT o un GROUP BY ... SUM query SQL equivalenti sui
Django ORM, con l'uso di annotate() , values() , order_by() e le django.db.models s' Count e Sum
metodi rispettosamente:
class Books(models.Model):
title = models.CharField()
author = models.CharField()
price = models.FloatField()
• Supponiamo che vogliamo contare quanti oggetti libro per autore distinto esistono nella
nostra tabella Books :
result = Books.objects.values('author')
.order_by('author')
.annotate(count=Count('author'))
• Ora il result contiene un set di query con due colonne: author e count :
author | count
------------|-------
OneAuthor | 5
OtherAuthor | 2
... | ...
https://riptutorial.com/it/home 15
GROUB BY ... SUM :
• Supponiamo che vogliamo sommare il prezzo di tutti i libri per autore distinto presenti nella
nostra tabella Books :
result = Books.objects.values('author')
.order_by('author')
.annotate(total_price=Sum('price'))
• Ora il result contiene un set di query con due colonne: author e total_price :
author | total_price
------------|-------------
OneAuthor | 100.35
OtherAuthor | 50.00
... | ...
https://riptutorial.com/it/home 16
Capitolo 3: Amministrazione
Examples
Cambia lista
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 dei cambiamenti" di Django Admin è la pagina che elenca tutti gli oggetti di un dato
modello.
@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
pass
Di default, userà il __str__() (o __unicode__() se tu su python2) del tuo modello per visualizzare il
"nome" dell'oggetto. Ciò significa che se non l'hai sovrascritto, vedrai un elenco di articoli, tutti
denominati "Articolo oggetto". Per modificare questo comportamento, puoi impostare il __str__() :
class Article(models.Model):
def __str__(self):
return self.title
Ora, tutti i tuoi articoli dovrebbero avere un nome diverso e più esplicito di "Articolo oggetto".
Tuttavia potresti voler visualizzare altri dati in questo elenco. Per questo, usa list_display :
@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
list_display = ['__str__', 'author', 'date_published', 'is_draft']
list_display non è limitato ai campi e alle proprietà del modello. può anche essere un metodo di
ModelAdmin :
https://riptutorial.com/it/home 17
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']
Dopo aver effettuato questa operazione, i campi di ricerca vengono visualizzati nella pagina
dell'elenco di amministratori con il segnaposto predefinito: " parola chiave ". Ma cosa succede se
si desidera modificare quel segnaposto su " Cerca per nome "?
@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', )
Puoi utilizzare la barra degli strumenti debug del browser per trovare l'ID o la classe Django
impostati su questa barra di ricerca e quindi scrivere il tuo codice js:
https://riptutorial.com/it/home 18
$(function () {
$('#searchbar').attr('placeholder', 'Search by name')
})
Anche la classe Media ti consente di aggiungere file css con l'oggetto dizionario:
class Media:
css = {
'all': ('css/admin/styles.css',)
}
.field_first_name {
background-color: #e6f2ff;
}
Se vuoi personalizzare altri comportamenti aggiungendo JS o alcuni stili css, puoi sempre
controllare id e classi di elementi nello strumento di debug del browser.
Per impostazione predefinita, Django ForeignKey rendering ForeignKey campi ForeignKey come input
<select> . Ciò può causare il caricamento molto lento delle pagine se nella tabella di riferimento
sono presenti migliaia o decine di migliaia di voci. E anche se hai solo centinaia di voci, è
abbastanza scomodo cercare una voce particolare tra tutte.
Un modulo esterno molto utile per questo è django-autocomplete-light (DAL). Ciò consente di
utilizzare i campi di completamento automatico invece dei campi <select> .
https://riptutorial.com/it/home 19
views.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/it/home 20
fields = ['__all__']
admin.py
@admin.register(Place)
class PlaceAdmin(admin.ModelAdmin):
form = PlaceForm
https://riptutorial.com/it/home 21
Capitolo 4: ArrayField - un campo specifico
PostgreSQL
Sintassi
• da django.contrib.postgres.fields importa ArrayField
• class ArrayField (base_field, size = None, ** opzioni)
• FooModel.objects.filter (array_field_name__contains = [oggetti, a, controllo])
• FooModel.objects.filter (array_field_name__contained_by = [oggetti, a, controllo])
Osservazioni
Nota che sebbene il parametro size sia passato a PostgreSQL, PostgreSQL non lo applicherà.
Quando si utilizza ArrayField si dovrebbe tenere a mente questa parola di avvertenza dalla
documentazione degli array Postgresql .
Suggerimento: gli array non sono insiemi; la ricerca di specifici elementi dell'array può
essere un segno di misdesign del database. Prendi in considerazione l'utilizzo di una
tabella separata con una riga per ogni elemento che sarebbe un elemento dell'array.
Questo sarà più facile da cercare, ed è probabile che scala in modo migliore per un
gran numero di elementi.
Examples
Un ArrayField di base
Per creare un ArrayField PostgreSQL, dovremmo dare a ArrayField il tipo di dati che vogliamo
archiviare come campo come primo argomento. Poiché archiviamo le valutazioni dei libri,
utilizzeremo FloatField .
class Book(models.Model):
ratings = ArrayField(FloatField())
class IceCream(models.Model):
scoops = ArrayField(IntegerField() # we'll use numbers to ID the scoops
, size=6) # our parlor only lets you have 6 scoops
https://riptutorial.com/it/home 22
Quando si utilizza il parametro size, viene passato a postgresql, che lo accetta e quindi lo ignora!
Quindi è abbastanza possibile aggiungere 7 interi al campo scoops sopra usando la console
postgresql.
Questa query restituisce tutti i coni con una pallina di cioccolato e uno scoop alla vaniglia.
Ricorda inoltre che django non creerà un indice per ArrayField . Se stai andando a cercarli, avrai
bisogno di un indice e dovrà essere creato manualmente con una chiamata a RunSQL nel tuo file
di migrazione.
Nesting ArrayFields
class SudokuBoard(models.Model):
numbers = ArrayField(
ArrayField(
models.IntegerField(),
size=9,
),
size=9,
)
Questa query restituisce tutti i coni con uno scoop alla menta o uno scoop alla vaniglia.
https://riptutorial.com/it/home 23
Capitolo 5: Associazione di stringhe alle
stringhe con HStoreField: un campo
specifico PostgreSQL
Sintassi
• FooModel.objects.filter (field_name__key_name = 'valore da interrogare')
Examples
Impostazione di HStoreField
class FooMigration(migrations.Migration):
# put your other migration stuff here
operations = [
HStoreExtension(),
...
]
-> Nota: assicurati di configurare HStoreField prima di continuare con questo esempio.
(sopra)
class Catalog(models.model):
name = models.CharField(max_length=200)
titles_to_authors = HStoreField()
Passa un dizionario Python nativo che associa stringhe a stringhe per create() .
https://riptutorial.com/it/home 24
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',
})
L'utilizzo contiene
Catalog.objects.filter(titles__contains={
'Pro Git': 'Scott Chacon and Ben Straub'})
Leggi Associazione di stringhe alle stringhe con HStoreField: un campo specifico PostgreSQL
online: https://riptutorial.com/it/django/topic/2670/associazione-di-stringhe-alle-stringhe-con-
hstorefield--un-campo-specifico-postgresql
https://riptutorial.com/it/home 25
Capitolo 6: Attività asincrone (sedano)
Osservazioni
Celery è una coda di attività che può eseguire lavori in background o pianificati e si integra
abbastanza bene con Django. Celery richiede qualcosa di conosciuto come broker dei messaggi
per passare i messaggi dall'invocazione ai lavoratori. Questo broker di messaggi può essere redis,
rabbitmq o anche Django ORM / db anche se questo non è un approccio raccomandato.
Prima di iniziare con l'esempio, dovrai configurare il sedano. Per configurare il sedano, creare un
file celery_config.py nell'app principale, parallelamente al file 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)
E nel file __init__.py dell'app principale, importa l'app di sedano. come questo
Per eseguire il gestore di sedici, utilizzare questo comando al livello in cui è manage.py.
Examples
Semplice esempio per aggiungere 2 numeri
https://riptutorial.com/it/home 26
Per iniziare:
@task
def add_number(x, y):
return x + y
Per recuperare il risultato del calcolo, è possibile utilizzare l'attributo .result sull'oggetto async.
Esempio
https://riptutorial.com/it/home 27
Capitolo 7: Backend di autenticazione
Examples
Email di back-end di autenticazione
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/it/home 28
Capitolo 8: Comandi di gestione
introduzione
I comandi di gestione sono script potenti e flessibili che possono eseguire azioni sul progetto
Django o sul database sottostante. Oltre ai vari comandi predefiniti, è possibile scrivere i propri!
Rispetto ai normali script Python, l'utilizzo del framework dei comandi di gestione significa che
alcune noiose operazioni di configurazione vengono eseguite automaticamente dietro le quinte.
Osservazioni
I comandi di gestione possono essere chiamati da:
Examples
Creazione ed esecuzione di un comando di gestione
Per eseguire azioni in Django utilizzando la riga di comando o altri servizi (in cui l'utente / richiesta
non viene utilizzato), è possibile utilizzare i management commands .
class Command(BaseCommand):
help = 'My custom django management command'
https://riptutorial.com/it/home 29
def handle(self, *args, **options):
bookid = options['book_id']
author = options['author']
# Your code goes here
# For example:
# books = Book.objects.filter(author="bob")
# for book in books:
# book.name = "Bob"
# book.save()
Qui il nome della classe Command è obbligatorio che estende BaseCommand o una delle sue
sottoclassi.
Il nome del comando di gestione è il nome del file che lo contiene. Per eseguire il comando
nell'esempio precedente, utilizzare quanto segue nella directory del progetto:
Se non capisci alcun comando o cerchi argomenti opzionali, puoi usare l'argomento -h come
questo
Qui command_name sarà il tuo nome comando desiderato, questo ti mostrerà il testo di aiuto dal
comando.
Starts a lightweight Web server for development and also serves static files.
positional arguments:
addrport Optional port number, or ipaddr:port
https://riptutorial.com/it/home 30
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.
Puoi sbarazzarti di manage.py e usare invece il comando django-admin . Per fare ciò, dovrai fare
manualmente ciò che manage.py fa:
export PYTHONPATH="/home/me/path/to/your_project"
export DJANGO_SETTINGS_MODULE="your_project.settings"
Ciò è particolarmente utile in una virtualizzazione in cui è possibile impostare queste variabili di
ambiente nello script postactivate .
django-admin comando django-admin ha il vantaggio di essere disponibile ovunque tu sia sul tuo
filesystem.
Django viene fornito con una serie di comandi di gestione incorporati, usando python manage.py
[command] o, quando manage.py ha diritti + x (eseguibili) semplicemente ./manage.py [command] . I
seguenti sono alcuni dei più usati:
./manage.py help
Esegui il tuo server Django su localhost: 8000; essenziale per i test locali
https://riptutorial.com/it/home 31
./manage.py runserver
Esegui una console python (o ipython se installata) con le impostazioni Django del tuo progetto
precaricato (il tentativo di accedere a parti del tuo progetto in un terminale python senza farlo
fallirebbe).
./manage.py shell
Crea un nuovo file di migrazione del database in base alle modifiche apportate ai tuoi modelli.
Vedi Migrazioni
./manage.py makemigrations
./manage.py migrate
./manage.py test
Prendere tutti i file statici del progetto e inserirli nella cartella specificata in STATIC_ROOT modo che
possano essere pubblicati in produzione.
./manage.py collectstatic
./manage.py createsuperuser
https://riptutorial.com/it/home 32
Capitolo 9: Come resettare le migrazioni di
django
introduzione
Man mano che sviluppi un'app di Django, ci potrebbero essere situazioni in cui puoi risparmiare
molto tempo semplicemente ripulendo e reimpostando le tue migrazioni.
Examples
Reimpostazione della migrazione di Django: eliminazione del database
esistente e migrazione come nuova
Cancella / cancella il tuo database Se stai usando SQLite per il tuo database, cancella questo file.
Se si utilizza MySQL / Postgres o qualsiasi altro sistema di database, sarà necessario rilasciare il
database e ricreare un nuovo database.
Ora dovrai eliminare tutti i file di migrazione tranne il file "init.py" che si trova nella cartella delle
migrazioni nella cartella dell'app.
/your_django_project/your_app/migrations
Ora che hai eliminato il database e il file di migrazione, esegui i seguenti comandi come faresti
con la migrazione la prima volta che avvii il progetto django.
https://riptutorial.com/it/home 33
Capitolo 10: Come usare Django con
Cookiecutter?
Examples
Installazione e configurazione del progetto django con Cookiecutter
• seme
• virtualenv
• PostgreSQL
Cambia directory nella cartella in cui desideri che il tuo progetto vivi. Ora esegui il seguente
comando per generare un progetto django:
$ cookiecutter https://github.com/pydanny/cookiecutter-django.git
https://riptutorial.com/it/home 34
use_python2 [n]: n
Maggiori dettagli sulle opzioni di generazione del progetto sono disponibili nella documentazione
ufficiale. Il progetto è ora configurato.
https://riptutorial.com/it/home 35
Capitolo 11: Configurazione del database
Examples
MySQL / MariaDB
Oltre a uno dei driver MySQL di Python ( mysqlclient la scelta consigliata per Django):
La codifica del database non può essere impostata da Django, ma deve essere
configurata a livello di database. Cerca default-character-set in my.cnf (o
/etc/mysql/mariadb.conf/*.cnf ) e imposta la codifica:
[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
'PORT': '3306',
#optional:
'OPTIONS': {
'charset' : 'utf8',
https://riptutorial.com/it/home 36
'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',
}
}
Se si utilizza il connettore MySQL di Oracle, la linea ENGINE dovrebbe avere il seguente aspetto:
'ENGINE': 'mysql.connector.django',
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/it/home 37
Usando Postresql avrai accesso ad alcune funzionalità extra:
Modelfields:
sqlite
sqlite è l'impostazione predefinita per Django. Non dovrebbe essere usato in produzione poiché è
solitamente lento.
#myapp/settings/settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': 'db/development.sqlite3',
'USER': '',
'PASSWORD': '',
'HOST': '',
'PORT': '',
},
}
infissi
Le fixture sono dati iniziali per il database. Il modo più semplice quando si hanno già alcuni dati
esistenti è usare il comando dumpdata
Questo creerà un file json che può essere importato di nuovo usando
Quando si utilizza loadddata senza specificare un file, Django cercherà una cartella fixtures nella
propria app o l'elenco delle directory fornite in FIXTURE_DIRS nelle impostazioni e utilizzerà invece il
suo contenuto.
/myapp
/fixtures
myfixtures.json
morefixtures.xml
https://riptutorial.com/it/home 38
I possibili formati di file sono: JSON, XML or 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"
}
}
]
- 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/it/home 39
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/it/home 40
Capitolo 12: CRUD in Django
Examples
** Esempio CRUD più semplice **
Se ritieni che questi passaggi non siano familiari, considera di iniziare da qui . Nota che questi
passaggi provengono dalla documentazione di Overflow dello stack.
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'myapp',
]
Crea un file chiamato urls.py nella directory myapp e lo aggiorna con la seguente 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),
]
Creare una cartella denominata templates all'interno della directory myapp . Quindi creare un file
denominato index.html all'interno della directory dei modelli . Completalo con il seguente
contenuto.
https://riptutorial.com/it/home 41
<!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>
Abbiamo anche bisogno di una vista per mostrare index.html che possiamo creare modificando il
file views.py in questo modo:
Ora hai la base su cui lavorerai. Il prossimo passo è creare un modello. Questo è l'esempio più
semplice possibile, quindi nella cartella models.py aggiungi il seguente codice.
Questo crea un modello di un oggetto Nome che aggiungeremo al database con i seguenti
comandi dalla riga di comando.
Dovresti vedere alcune operazioni eseguite da Django. Questi configurano le tabelle e creano un
superutente che può accedere al database di amministrazione da una vista amministratore con
Django. A proposito, registriamo il nostro nuovo modello con la visualizzazione admin. Vai su
admin.py e aggiungi il seguente codice.
admin.site.register(Name)
https://riptutorial.com/it/home 42
Tornando alla riga di comando ora è possibile avviare il server con il comando python manage.py
runserver . Dovresti poter visitare http: // localhost: 8000 / e vedere la tua app. Passare quindi a
http: // localhost: 8000 / admin in modo da poter aggiungere un nome al progetto. Accedi e
aggiungi un Nome sotto la tabella MYAPP, l'abbiamo mantenuto semplice per l'esempio, quindi
assicurati che sia inferiore a 100 caratteri.
Per accedere al nome è necessario visualizzarlo da qualche parte. Modifica la funzione di indice
all'interno di views.py per estrarre tutti gli oggetti Nome dal database.
<!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>
Ciò dimostra la lettura in CRUD. All'interno della directory myapp creare un file forms.py. Aggiungi
il seguente codice:
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/it/home 43
Aggiorna index.html nel modo seguente:
<!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)
Riavvia il tuo server e dovresti ora avere una versione funzionante dell'app con la C in create
https://riptutorial.com/it/home 44
completed.
https://riptutorial.com/it/home 45
Capitolo 13: Debug
Osservazioni
PDB
Pdb può anche stampare tutte le variabili esistenti in ambito globale o locale, digitando
rispettivamente globals() o locals() in (Pdb) prompt.
Examples
Utilizzo di Python Debugger (Pdb)
La maggior parte degli strumenti di debug di Django di base è pdb , una parte della libreria
standard di Python.
def index(request):
foo = 1
bar = 0
bug = foo/bar
# Pdb import
import pdb
https://riptutorial.com/it/home 46
def index(request):
foo = 1
bar = 0
bug = foo/bar
Ora sulla pagina il punto di interruzione del carico si attiverà (Pdb) nella shell, che bloccherà
anche il browser in sospeso.
È tempo di eseguire il debug di questa vista interagendo con lo script tramite shell:
> ../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
Nell'ultima riga vediamo che la nostra vista ha restituito una risposta OK e l'esecuzione come
dovrebbe.
settings.py :
https://riptutorial.com/it/home 47
Successivamente, includilo nelle app installate del progetto, ma fai attenzione: è sempre buona
norma utilizzare un diverso file settings.py per tali app e middleware di solo sviluppo come barra
degli strumenti di debug:
# If environment is dev...
DEBUG = True
INSTALLED_APPS += [
'debug_toolbar',
]
MIDDLEWARE += ['debug_toolbar.middleware.DebugToolbarMiddleware']
La barra degli strumenti di debug si basa anche su file statici, quindi dovrebbe essere inclusa
anche l'app appropriata:
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 :
Ecco fatto, la barra degli strumenti di debug comparirà sulle pagine del tuo progetto, fornendo
varie informazioni utili sui tempi di esecuzione, SQL, file statici, segnali, ecc.
https://riptutorial.com/it/home 48
HTML:
Inoltre, django-debug-toolbar richiede un tipo di contenuto di tag text/html , <html> e <body> per
renderizzare correttamente.
Nel caso in cui sei sicuro di aver configurato tutto correttamente, ma la barra degli
strumenti di debug non viene ancora renderizzata: usa questa soluzione "nucleare" per
cercare di capirlo.
farà sì che django sollevi AssertionError con il valore fornito come messaggio di errore quando
viene eseguita questa riga.
Se questo si verifica in una vista, o in qualsiasi codice chiamato da una vista, e DEBUG=True è
impostato, nel browser verrà visualizzato uno stacktrace completo e dettagliato con molte
informazioni di debug.
Invece di inseguire i bug con un debugger, considera di dedicare più tempo a migliorare il tuo
codice:
• Scrivi ed esegui i test . Python e Django dispongono di ottimi framework di test integrati,
che possono essere utilizzati per testare il codice molto più rapidamente rispetto a un
debugger manuale.
• Scrivere una documentazione adeguata per funzioni, classi e moduli. PEP 257 e Google's
Python Style Guide forniscono buone pratiche per la scrittura di buone docstring.
• Usa la registrazione per produrre l'output dal tuo programma - durante lo sviluppo e dopo la
distribuzione.
• Aggiungi assert ioni al tuo codice in posti importanti: riduce l'ambiguità, cattura i problemi
man mano che vengono creati.
https://riptutorial.com/it/home 49
Capitolo 14: Distribuzione
Examples
Esecuzione dell'applicazione Django con Gunicorn
1. Installa gunicorn
2. Dalla cartella del progetto django (stessa cartella in cui si trova manage.py), eseguire il
comando seguente per eseguire il progetto django corrente con gunicorn
È possibile utilizzare l'opzione --env per impostare il percorso per caricare le impostazioni
2. Passa alla radice dei sorgenti della tua app Django. Avrai bisogno di TK
3. Digita heroku create [app_name] . heroku create [app_name] . Se non si fornisce un nome app,
Heroku ne genererà uno a caso. L'URL della tua app sarà http://[app name].herokuapp.com
4. Crea un file di testo con il nome Procfile . Non mettere un'estensione alla fine.
Se hai un processo di lavoro, puoi aggiungerlo anche tu. Aggiungi un'altra riga
nel formato: worker-name: <bash command to start worker>
5. Aggiungi un requisito.txt.
https://riptutorial.com/it/home 50
6. È il momento dello spiegamento!
Questo ridimensiona il numero di "dynos" web in uno. Qui puoi saperne di più sui
dynos .
Suggerimento: heroku open apre l'URL della tua app heroku nel browser
predefinito.
7. Aggiungi componenti aggiuntivi . Dovrai configurare la tua app Django per legare con i
database forniti in Heroku come "componenti aggiuntivi". Questo esempio non copre questo,
ma un altro esempio è nella pipeline sulla distribuzione di database in Heroku.
Fabric è una libreria Python (2.5-2.7) e uno strumento da riga di comando per semplificare l'uso di
SSH per la distribuzione delle applicazioni o le attività di amministrazione dei sistemi. Ti permette
di eseguire funzioni arbitrarie di Python tramite la riga di comando.
#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/'):
with prefix('source ../env/bin/activate'):
https://riptutorial.com/it/home 51
# 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: non è possibile configurare le chiavi ssh per github e digitare manualmente login e
password, mentre fabfile esegue, lo stesso con le chiavi.
Se hai intenzione di ospitare il tuo sito Django su Heroku, puoi iniziare il tuo progetto usando il
Template di avvio Heroku Django:
Ha una configurazione pronta per la produzione per file statici, impostazioni database, Gunicorn,
ecc. E miglioramenti alla funzionalità di file statici di Django tramite WhiteNoise. Questo ti farà
risparmiare tempo, è completamente pronto per l'hosting su Heroku. Costruisci il tuo sito web in
cima a questo modello
git init
git add -A
git commit -m "Initial commit"
heroku create
git push heroku master
Questo è tutto!
1. nginx: server HTTP e reverse proxy gratuito, open source e ad alte prestazioni, con
prestazioni elevate;
2. gunicorn - "Green Unicorn" è un server HTTP WSGI Python per UNIX (necessario per
gestire il server);
https://riptutorial.com/it/home 52
3. supervisore - un sistema client / server che consente agli utenti di monitorare e controllare
un numero di processi su sistemi operativi UNIX-like. Utilizzato quando l'app o il sistema si
bloccano, riavvia la tua webcam django / sedano / sedano, ecc;
Per semplificare, supponiamo che la tua app si trovi in questa directory: /home/root/app/src/ e
useremo l'utente root (ma dovresti creare un utente separato per la tua app). Anche il nostro
ambiente virtuale si troverà in /home/root/app/env/ path.
Nginx
Iniziamo con nginx. Se nginx non è già sulla macchina, installalo con sudo apt-get install nginx .
In seguito devi creare un nuovo file di configurazione nella tua directory nginx /etc/nginx/sites-
enabled/yourapp.conf . Se c'è un file chiamato default.conf - rimuovilo.
Codice muggito in un file conf nginx, che proverà ad eseguire il tuo servizio usando il file socket;
Più avanti ci sarà una configurazione di gunicorn. Il file socket è usato qui per comunicare tra
nginx e gunicorn. Può anche essere fatto usando le porte.
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/it/home 53
}
GUNICORN
Ora il nostro script GUNICORN, che sarà responsabile dell'esecuzione dell'applicazione django
sul server. La prima cosa è installare gunicorn in ambiente virtuale 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
per poter eseguire lo script di avvio di gunicorn, è necessario che la modalità di esecuzione sia
abilitata
ora sarai in grado di avviare il tuo server gunicorn semplicemente usando ./gunicorn_start
SUPERVISORE
Come detto all'inizio, vogliamo che la nostra applicazione venga riavviata quando fallisce un
supervisore. Se supervisore non è ancora installato sul server con sudo apt-get install supervisor
https://riptutorial.com/it/home 54
.
Al primo installatore supervisore. Quindi crea un file .conf nella directory principale
/etc/supervisor/conf.d/your_conf_file.conf
[program:yourappname]
command = /home/root/app/src/gunicorn_start
user = root
stdout_logfile = /home/root/app/src/logs/gunicorn_supervisor.log
redirect_stderr = true
Fatto ciò, dobbiamo dire al nostro supervisore che abbiamo appena aggiunto un nuovo file di
configurazione. Per farlo, c'è un processo diverso per la diversa versione di Ubuntu.
Per ottenere la dimostrazione dal vivo di questa procedura, naviga questo video .
Il modo consigliato per l'implementazione della produzione richiede l'uso di Apache / Nginx per
servire il contenuto statico. Pertanto, quando DEBUG è falso statico e il contenuto multimediale non
viene caricato. Tuttavia, possiamo caricare il contenuto statico nella distribuzione senza dover
configurare il server Apache / Nginx per la nostra app utilizzando:
Questo è destinato esclusivamente per la distribuzione locale (ad esempio, LAN) e non dovrebbe
https://riptutorial.com/it/home 55
mai essere utilizzato nella produzione ed è disponibile solo se lo staticfiles app è in del progetto
INSTALLED_APPS impostazione.
https://riptutorial.com/it/home 56
Capitolo 15: Django dalla riga di comando.
Osservazioni
Mentre Django è principalmente per applicazioni web, ha un ORM potente e facile da usare che
può essere utilizzato anche per applicazioni e script da riga di comando. Esistono due diversi
approcci che possono essere utilizzati. Il primo è di creare un comando di gestione personalizzato
e il secondo di inizializzare l'ambiente Django all'inizio del tuo script.
Examples
Django dalla riga di comando.
Supponendo di aver impostato un progetto django e il file delle impostazioni si trova in un'app
chiamata main, ecco come si inizializza il codice
# 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/it/home 57
Capitolo 16: Django e reti sociali
Parametri
Ambientazione fa
https://riptutorial.com/it/home 58
Ambientazione fa
Examples
Modo semplice: python-social-auth
INSTALLARE
o scarica il codice da github. Ora è un buon momento per aggiungere questo al tuo file
requirements.txt .
CONFIGURAZIONE di settings.py
In settings.py aggiungi:
INSTALLED_APPS = (
...
'social.apps.django_app.default',
...
)
CONFIGURARE BACKENDS
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',
https://riptutorial.com/it/home 59
...
'django.contrib.auth.backends.ModelBackend',
)
SOCIAL_AUTH_FACEBOOK_KEY = 'YOURFACEBOOKKEY'
SOCIAL_AUTH_FACEBOOK_SECRET = 'YOURFACEBOOKSECRET'
SOCIAL_AUTH_LINKEDIN_KEY = 'YOURLINKEDINKEY'
SOCIAL_AUTH_LINKEDIN_SECRET = 'YOURLINKEDINSECRET'
Nota : è possibile ottenere le chiavi Nedded negli sviluppatori di Facebook e negli sviluppatori di
Linkedin e qui è possibile visualizzare l'elenco completo e il suo rispettivo modo di specificare la
chiave API e il segreto chiave.
Nota sulle chiavi segrete: le chiavi segrete dovrebbero essere tenute segrete. Ecco una
spiegazione dello Stack Overflow che è utile. Questo tutorial è utile per l'apprendimento delle
variabili ambientali.
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")],
'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',
https://riptutorial.com/it/home 60
'social.apps.django_app.context_processors.backends',
'social.apps.django_app.context_processors.login_redirect',
],
},
},
]
SOCIAL_AUTH_USER_MODEL = 'somepackage.models.CustomUser'
CONFIGURARE 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'))
...
)
./manage.py migrate
se usi un altro backend cambia semplicemente 'facebook' con il nome del backend.
Una volta registrati gli utenti, probabilmente vorrai creare la funzionalità per reinserirli. In alcuni
modelli, probabilmente vicino a dove è stato mostrato il modello di accesso, aggiungi il seguente
tag:
https://riptutorial.com/it/home 61
<a href="/logout">Logout</a>
def logout(request):
auth_logout(request)
return redirect('/')
Per tutti i miei progetti, Django-Allauth ne è rimasto uno che è facile da configurare e viene fornito
con molte funzionalità tra cui, a titolo esemplificativo:
Passaggi di installazione:
https://riptutorial.com/it/home 62
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',
Fatto con le modifiche nel file settings.py sopra, passa al file urls.py Può essere il yourapp/urls.py
o il tuo ProjectName/urls.py Normalmente, preferisco ProjectName/urls.py
urlpatterns = [
# other urls here
url(r'^accounts/', include('allauth.urls')),
# other urls here
]
https://riptutorial.com/it/home 63
Infine, python ./manage.py migrate per eseguire il commit delle migrazioni di Django-allauth nel
Database.
Come al solito, per poter accedere alla tua app utilizzando qualsiasi social network che hai
aggiunto, dovrai aggiungere i dettagli dell'account social della rete.
Potrebbe essere necessario disporre di account presso ciascun provider di autenticazione per
ottenere dettagli da compilare nelle sezioni Applicazioni sociali.
Per configurazioni dettagliate di ciò che puoi avere e modificare, consulta la pagina Configurazioni
.
https://riptutorial.com/it/home 64
Capitolo 17: Django Rest Framework
Examples
API di sola lettura barebone semplice
Supponendo che tu abbia un modello che assomiglia a quanto segue, ci metteremo a correre con
un'API di sola lettura barebone semplice guidata da Django REST Framework ("DRF").
models.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)
Il serializzatore è il componente che prenderà tutte le informazioni dal modello Django (in questo
caso il FeedItem ) e lo trasformerà in JSON. È molto simile alla creazione di classi di form in
Django. Se hai esperienza in questo, questo sarà molto comodo per te.
serializers.py
class FeedItemSerializer(serializers.ModelSerializer):
class Meta:
model = models.FeedItem
fields = ('title', 'url', 'description', 'style')
views.py
DRF offre molte classi di visualizzazione per gestire una varietà di casi d'uso. In questo esempio,
avremo solo un'API di sola lettura , quindi, anziché utilizzare un viewet più completo o una serie
di viste generiche correlate, utilizzeremo una singola sottoclasse di ListAPIView di DRF.
Lo scopo di questa classe è di collegare i dati con il serializzatore e avvolgerli tutti insieme per un
oggetto risposta.
class FeedItemList(generics.ListAPIView):
serializer_class = serializers.FeedItemSerializer
queryset = models.FeedItem.objects.all()
urls.py
https://riptutorial.com/it/home 65
Assicurati di puntare il percorso verso la tua vista DRF.
urlpatterns = [
...
url(r'path/to/api', views.FeedItemList.as_view()),
]
https://riptutorial.com/it/home 66
Capitolo 18: django-filtro
Examples
Usa il filtro Django con CBV
django-filter è un sistema generico per il filtraggio di Django QuerySet in base alle selezioni
dell'utente. La documentazione lo utilizza in una vista basata sulle funzioni come modello di
prodotto:
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']
Per utilizzare questo in un CBV, eseguire l'override di get_queryset() di ListView, quindi restituire il
querset filtri filtrato:
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
È possibile accedere agli oggetti filtrati nelle viste, ad esempio con paginazione, in f.qs Questo
impaginerà l'elenco degli oggetti filtrati.
https://riptutorial.com/it/home 67
Capitolo 19: Esecuzione di Celery con
Supervisor
Examples
Configurazione del sedano
SEDANO
1. Installazione - pip install django-celery
2. Inserisci
- 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/it/home 68
celery -A stack worker -l info se vuoi aggiungere anche
Supervisore in esecuzione
1. Crea uno script per avviare il gestore di sedano. Inserisci il tuo script nella tua app. Ad
esempio: 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
4. Aggiungi il file di configurazione per il tuo supervisore per iniziare il sedano. Collocarlo in
/etc/supervisor/conf.d/stack_supervisor.conf
[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/it/home 69
6. Comandi di base
Celery richiede a un broker di gestire il passaggio dei messaggi. Usiamo RabbitMQ perché è facile
da configurare ed è ben supportato.
Una volta completata l'installazione, creare un utente, aggiungere un host virtuale e impostare le
autorizzazioni.
sudo rabbitmq-server
Nel tuo file Django settings.py, l'URL del tuo broker sarebbe quindi simile
BROKER_URL = 'amqp://myuser:mypassword@localhost:5672/myvhost'
Questo comando avvia un operatore di Celery per eseguire tutte le attività definite nell'app django.
https://riptutorial.com/it/home 70
lavoratori di Celery siano sempre in esecuzione.
[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 volta che il nostro file di configurazione è stato creato e salvato, possiamo informare il
Supervisore del nostro nuovo programma attraverso il comando supervisorctl. Per prima cosa
chiediamo a Supervisor di cercare eventuali configurazioni di programma nuove o modificate nella
directory /etc/supervisor/conf.d con:
Una volta che i nostri programmi sono in esecuzione, ci sarà indubbiamente un momento in cui
vogliamo fermarci, riavviarci o vedere il loro stato.
https://riptutorial.com/it/home 71
Capitolo 20: Estensione o sostituzione del
modello utente
Examples
Modello utente personalizzato con email come campo di accesso principale.
models.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'
REQUIRED_FIELDS = []
https://riptutorial.com/it/home 72
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/it/home 73
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',{})
settings.py:
https://riptutorial.com/it/home 74
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)
Se si desidera eliminare il campo del username e utilizzare l'e email come identificativo utente
univoco, sarà necessario creare un modello User personalizzato estendendo AbstractBaseUser
anziché AbstractUser . Infatti, username ed email sono definiti in AbstractUser e non è possibile
sovrascriverli. Ciò significa che dovrai anche ridefinire tutti i campi che desideri definiti in
AbstractUser .
class UserManager(BaseUserManager):
use_in_migrations = True
https://riptutorial.com/it/home 75
def create_superuser(self, email, password, **extra_fields):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
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(
verbose_name=_("staff status"),
default=False,
https://riptutorial.com/it/home 76
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()
Creare una classe di modello UserProfile con la relazione di OneToOne sul modello User predefinito:
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 i Segnali Django, crea un nuovo UserProfile User immediatamente viene creato un
oggetto User . Questa funzione può essere nascosta sotto la classe del modello UserProfile nello
stesso file o posizionarla dove preferisci. Non m'importa, finché lo fai correttamente.
inlineformset_factory al salvataggio
https://riptutorial.com/it/home 77
Ora per your views.py , potresti avere qualcosa di simile a questo:
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/')
Il nostro modello
{% 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">
{% csrf_token %} {{ noodle_form.as_p }}
<div class="divider"></div>
https://riptutorial.com/it/home 78
{{ 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>
Il modello User incorporato di Django non è sempre appropriato per alcuni tipi di progetti. Su alcuni
siti potrebbe essere più logico utilizzare un indirizzo email al posto di un nome utente, ad esempio.
AUTH_USER_MODEL = 'myapp.MyUser'
Tieni presente che è altamente consigliato creare il AUTH_USER_MODEL prima di creare qualsiasi
migrazione o eseguire manage.py migrate per la prima volta. A causa delle limitazioni della funzione
di dipendenza da synamic di Django.
Ad esempio sul tuo blog potresti volere che altri autori siano in grado di accedere con un indirizzo
email invece del normale nome utente, quindi creiamo un modello User personalizzato con un
indirizzo email come USERNAME_FIELD :
class CustomUser(AbstractBaseUser):
email = models.EmailField(unique=True)
USERNAME_FIELD = 'email'
Per consentire a Django manage.py createsuperuser comando di un utente, sapere quali altri campi
sono richiesti, possiamo specificare un REQUIRED_FIELDS . Questo valore non ha alcun effetto in altre
parti di Django!
class CustomUser(AbstractBaseUser):
...
first_name = models.CharField(max_length=254)
last_name = models.CharField(max_length=254)
...
REQUIRED_FIELDS = ['first_name', 'last_name']
https://riptutorial.com/it/home 79
Per essere compatibili con l'altra parte di Django dobbiamo ancora specificare il valore is_active ,
le funzioni get_full_name() e 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
Dovresti anche creare un UserManager personalizzato per il tuo modello User , che consente a
Django di utilizzare le create_user() e 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
Il tuo codice non funzionerà nei progetti in cui fai riferimento al modello User ( e dove è stata
modificata l'impostazione AUTH_USER_MODEL ) direttamente.
Ad esempio: se si desidera creare un modello Post per un blog con un modello User
personalizzato, è necessario specificare il modello User personalizzato in questo modo:
https://riptutorial.com/it/home 80
from django.conf import settings
from django.db import models
class Post(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
https://riptutorial.com/it/home 81
Capitolo 21: F () espressioni
introduzione
Un'espressione F () è un modo per Django di utilizzare un oggetto Python per fare riferimento al
valore del campo del modello o della colonna annotata nel database senza dover inserire il valore
nella memoria di Python. Ciò consente agli sviluppatori di evitare determinate condizioni di gara e
di filtrare i risultati in base ai valori del campo del modello.
Sintassi
• da django.db.models import F
Examples
Evitare le condizioni di gara
Vedi questa domanda Q & A se non sai quali sono le condizioni di gara.
article = Article.objects.get(pk=69)
article.views_count += 1
article.save()
Se due client accedono contemporaneamente a questo articolo, ciò che potrebbe accadere è che
la seconda richiesta HTTP esegua Article.objects.get(pk=69) prima che il primo esegua
article.save() . Pertanto, entrambe le richieste avranno views_count = 1337 , incrementarlo e
salvare views_count = 1338 nel database, mentre in realtà dovrebbe essere 1339 .
article = Article.objects.get(pk=69)
article.views_count = F('views_count') + 1
article.save()
https://riptutorial.com/it/home 82
Supponiamo di voler rimuovere 2 upvotes da tutti gli articoli dell'autore con id 51 .
Farlo solo con Python eseguirà N query ( N è il numero di articoli nel queryset):
Cosa succede se invece di trascinare tutti gli articoli in Python, passandoci sopra, diminuendo gli
upvotes e salvando ogni aggiornato nel database, c'era un altro modo?
Usando un'espressione F() , puoi farlo in una query:
Article.objects.filter(author_id=51).update(upvotes=F('upvotes') - 2)
Perché è meglio?
• Invece di fare il lavoro in Python, passiamo il carico nel database che è messo a punto per
fare queste domande.
• Riduce efficacemente il numero di query del database necessarie per ottenere il risultato
desiderato.
F()espressioni F() possono essere utilizzate per eseguire operazioni aritmetiche ( + , - , * ecc.)
Tra i campi del modello, al fine di definire una ricerca / connessione algebrica tra di esse.
class MyModel(models.Model):
int_1 = models.IntegerField()
int_2 = models.IntegerField()
• Ora lascia supporre che vogliamo recuperare tutti gli oggetti di MyModel tabella che di int_1 e
int_2 campi soddisfano questa equazione: int_1 + int_2 >= 5 . Utilizzando annotate() e
filter() otteniamo:
result = MyModel.objects.annotate(
diff=F(int_1) + F(int_2)
).filter(diff__gte=5)
Sebbene l'esempio utilizzi i campi Integer , questo metodo funzionerà su ogni campo in cui è
possibile applicare un'operazione aritmetica.
https://riptutorial.com/it/home 83
Leggi F () espressioni online: https://riptutorial.com/it/django/topic/2765/f----espressioni
https://riptutorial.com/it/home 84
Capitolo 22: formsets
Sintassi
• NewFormSet = formset_factory (SomeForm, extra = 2)
• formset = NewFormSet (initial = [{'some_field': 'Field Value', 'other_field': 'Other Field
Value',}]))
Examples
Formset con dati inizializzati e unitializzati
Formset è un modo per rendere più moduli in una pagina, come una griglia di dati. Es: Questo
ChoiceForm potrebbe essere associato a qualche domanda di ordinamento. come, i bambini sono
più intelligenti tra quale età?
appname/forms.py
Nel vostro punto di vista è possibile utilizzare formset_factory costruttore che prende prende Form
come parametro la sua ChoiceForm in questo caso e extra che descrive quante forme aggiuntivi
diverso inizializzati form / moduli deve essere reso, e si può ciclo sopra il formset oggetto come
qualsiasi altro iterabile.
Se il formset non è inizializzato con i dati, stampa il numero di moduli uguale a extra + 1 e se il
formset è inizializzato, stampa initialized + extra caso di numero extra di moduli vuoti diversi da
quelli inizializzati.
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(),}
])
se si esegue il loop su un formset object come questo per form in formset: print (form.as_table ())
<tr>
<th><label for="id_form-0-choice">Choice:</label></th>
https://riptutorial.com/it/home 85
<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/it/home 86
Capitolo 23: Fusi orari
introduzione
I fusi orari sono spesso una seccatura per gli sviluppatori. Django offre alcune ottime utility a tua
disposizione per rendere i fusi orari facili da usare.
Anche se il tuo progetto funziona in un singolo fuso orario, è comunque buona norma archiviare i
dati come UTC nel tuo database per gestire i casi di ora legale. Se si opera su più fusi orari, la
memorizzazione dei dati temporali come UTC è indispensabile.
Examples
Abilita supporto fuso orario
Per prima cosa, assicurati che USE_TZ = True nel file settings.py . Imposta anche un valore
predefinito del fuso orario su TIME_ZONE come TIME_ZONE='UTC' . Visualizza l'elenco completo dei fusi
orari qui .
Se USE_TZ è False, TIME_ZONE sarà il fuso orario che Django utilizzerà per memorizzare tutti i dati.
Quando USE_TZ è abilitato, TIME_ZONE è il fuso orario predefinito che Django utilizzerà per
visualizzare i datetimes nei modelli e per interpretare i dati di data immessi nei moduli.
Con il supporto fuso orario abilitato, django memorizzerà i dati datetime nel database come il fuso
orario UTC
Gli oggetti datetime.datetime di Python hanno un attributo tzinfo che viene utilizzato per
memorizzare le informazioni sul fuso orario. Quando l'attributo è impostato, l'oggetto è considerato
Aware, quando l'attributo non è impostato è considerato un Naive.
Per garantire che un fuso orario sia ingenuo o consapevole, puoi utilizzare .is_naive() e
.is_aware()
Se avete USE_TZ abilitati nel tuo settings.py file, un datetime avrà informazioni sul fuso orario
collegato ad esso fino a quando il difetto TIME_ZONE si trova in settings.py
Sebbene questo fuso orario predefinito possa essere buono in alcuni casi, probabilmente non è
sufficiente, soprattutto se si gestiscono utenti in più fusi orari. Per ottenere ciò, è necessario
utilizzare il middleware.
import pytz
https://riptutorial.com/it/home 87
class TimezoneMiddleware(object):
"""
Middleware to properly handle the users timezone
"""
response = self.get_response(request)
return response
Ci sono alcune cose nuove in corso. Per saperne di più sul middleware e su cosa controlla questa
parte della documentazione . In __call__ l'impostazione dei dati del fuso orario. Inizialmente ci
assicuriamo che l'utente sia autenticato, per assicurarci di avere i dati del fuso orario per questo
utente. Quando lo sappiamo, attiviamo il fuso orario per la sessione degli utenti utilizzando
timezone.activate() . Per convertire la stringa del fuso orario abbiamo qualcosa utilizzabile da
datetime, usiamo pytz.timezone(str) .
Ora, quando gli oggetti datetime sono accessibili nei modelli, verranno automaticamente convertiti
dal formato "UTC" del database a qualsiasi fuso orario in cui si trova l'utente. Basta accedere
all'oggetto datetime e il suo fuso orario verrà impostato assumendo che il middleware precedente
sia impostato propriamente.
{{ my_datetime_value }}
Se desideri un controllo a grana fine se viene utilizzato il fuso orario dell'utente, dai un'occhiata a
quanto segue:
{% 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 %}
Nota, questo metodo descritto funziona solo in Django 1.10 e oltre. Per supportare django da
precedente a 1.10, guarda a MiddlewareMixin
https://riptutorial.com/it/home 88
Capitolo 24: Gestori e Queryys personalizzati
Examples
Definire un manager di base usando Querysets e il metodo `as_manager`
Per evitare di scrivere query comuni su tutto il nostro codebase e invece di riferirle usando
un'astrazione più facile da ricordare. Esempio: decidi tu stesso quale versione è più leggibile:
Un altro vantaggio è che se domani decidiamo che tutti gli psychologists sono anche
dermatologists , possiamo facilmente modificare la query nel nostro manager e farla finita.
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):
...
manager = ProfileManager()
NOTA : una volta definito un manager sul nostro modello, gli objects non saranno più definiti per il
modello.
https://riptutorial.com/it/home 89
select_related per tutte le query
class Book(models.Model):
name= models.CharField(max_length=50)
author = models.ForeignKey(Author)
class Author(models.Model):
name = models.CharField(max_length=50)
In vista
books = Book.objects.select_related('author').all()
Manager personalizzato
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()
Molto spesso capita di trattare con modelli che hanno qualcosa come un campo published . Questi
tipi di campi sono quasi sempre usati per recuperare oggetti, così ti troverai a scrivere qualcosa
come:
https://riptutorial.com/it/home 90
my_news = News.objects.filter(published=True)
troppe volte. Puoi utilizzare i gestori personalizzati per gestire queste situazioni, in modo che tu
possa scrivere qualcosa come:
my_news = News.objects.published()
Creare un file managers.py nella directory app, e definire una nuova models.Manager classe:
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()
my_news = News.objects.published(title__icontains='meow')
https://riptutorial.com/it/home 91
Capitolo 25: impostazioni
Examples
Impostazione del fuso orario
Puoi impostare il fuso orario che verrà utilizzato da Django nel file settings.py . Esempi:
Quando si esegue in un ambiente Windows , questo deve essere impostato allo stesso fuso
orario del sistema .
USE_TZ = False
Le best practice di Django richiedono l'uso di UTC per l'archiviazione delle informazioni nel
database:
Anche se il tuo sito web è disponibile in un unico fuso orario, è comunque buona
norma memorizzare i dati in UTC nel tuo database. Il motivo principale è Daylight
Saving Time (DST). Molti paesi hanno un sistema di DST, in cui gli orologi vengono
spostati in avanti in primavera e indietro in autunno. Se lavori in ora locale, è probabile
che tu incontri errori due volte l'anno, quando le transizioni avvengono.
https://docs.djangoproject.com/en/stable/topics/i18n/timezones/
Una volta che hai tutte le impostazioni, vorrai usarle nel tuo codice. Per fare ciò, aggiungi la
seguente importazione al tuo file:
È quindi possibile accedere alle proprie impostazioni come attributi del modulo delle settings , ad
esempio:
if not settings.DEBUG:
email_user(user, message)
https://riptutorial.com/it/home 92
È una cattiva idea di percorsi di codice complessi nella tua applicazione. Uno dovrebbe sempre
usare url relativi in modo che il codice possa funzionare senza problemi su macchine diverse. Il
modo migliore per configurarlo è definire una variabile come questa
import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
Quindi utilizzare questa variabile BASE_DIR per definire tutte le altre impostazioni.
E così via. Ciò garantisce che puoi trasferire il tuo codice su macchine diverse senza
preoccupazioni.
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
Un'alternativa è usare il modulo unipath (che puoi installare con pip install unipath ).
TEMPLATE_PATH = BASE_DIR.child('templates')
STATICFILES_DIRS = [
BASE_DIR.child('static'),
]
Poiché è probabile che le configurazioni cambino tra gli ambienti di distribuzione, questo è un
modo molto interessante per modificare la configurazione senza dover scavare nel codice
sorgente dell'app, oltre a tenere segreti al di fuori dei file dell'applicazione e del repository del
codice sorgente.
In Django, le impostazioni principali si trovano come settings.py nella cartella del tuo progetto.
Poiché si tratta di un semplice file Python, è possibile utilizzare il modulo os di Python dalla libreria
standard per accedere all'ambiente (e persino avere i valori predefiniti appropriati).
settings.py
https://riptutorial.com/it/home 93
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 puoi cambiare la tua tecnologia di database, in modo che tu possa usare sqlite3 sul
tuo computer di sviluppo (e questo dovrebbe essere un predefinito corretto per il commit su un
sistema di controllo del codice sorgente). Anche se questo è possibile, non è consigliabile:
Il layout di progetto predefinito di Django crea un singolo settings.py . Questo è spesso utile per
dividerlo in questo modo:
myprojectroot/
myproject/
__init__.py
settings/
__init__.py
base.py
dev.py
prod.py
tests.py
Ciò consente di lavorare con impostazioni diverse a seconda che si tratti di sviluppo, produzione,
test o altro.
Quando si passa dal layout predefinito a questo layout, il settings.py originale diventa
settings/base.py Quando ogni altro sottomodulo eseguirà una "sottoclasse" di settings/base.py
iniziando from .base import * . Ad esempio, ecco come possono essere le settings/dev.py :
https://riptutorial.com/it/home 94
# -*- 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']
# 1 alternativo
Perché i comandi di django-admin funzionino correttamente, devi impostare la variabile di ambiente
DJANGO_SETTINGS_MODULE (che di default è myproject.settings ). In fase di sviluppo, lo imposterai su
myproject.settings.dev . In produzione, lo imposterai su myproject.settings.prod . Se si utilizza un
virtualenv, è meglio impostarlo nello script postactivate :
#!/bin/sh
export PYTHONPATH="/home/me/django_projects/myproject:$VIRTUAL_ENV/lib/python3.4"
export DJANGO_SETTINGS_MODULE="myproject.settings.dev"
N. 2 alternativo
Se si desidera lasciare DJANGO_SETTINGS_MODULE alla sua configurazione predefinita (
myproject.settings ), è sufficiente indicare al modulo delle settings configurazione da caricare
inserendo l'importazione nel file __init__.py .
Nell'esempio sopra, lo stesso risultato potrebbe essere ottenuto avendo un __init__.py impostato
su:
Ogni file di requisiti deve corrispondere al nome di un file di impostazioni. Leggi Utilizzo di più
impostazioni per ulteriori informazioni.
Struttura
djangoproject
https://riptutorial.com/it/home 95
├── 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
E in tutti gli altri file, includere le dipendenze di base con -r base.txt e aggiungere specifiche
dipendenze necessarie per l'ambiente corrente.
# 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`
Quando si utilizza un VCS come Git o SVN, ci sono alcuni dati segreti che non devono mai essere
sottoposti a versionamento (se il repository è pubblico o privato).
Una pratica comune per nascondere queste impostazioni dal controllo di versione è creare un file
secrets.json alla radice del progetto ( grazie a " Two Scoops of Django " per l'idea ):
https://riptutorial.com/it/home 96
{
"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'),
},
}
Crediti: Two Scoops of Django: Best Practices per Django 1.8, di Daniel Roy Greenfeld e Audrey
RoyGreenfeld. Copyright 2015 Two Scoops Press (ISBN 978-0981467344)
Nei siti PaaS come Heroku, è normale ricevere le informazioni del database come una singola
variabile di ambiente URL, invece di diversi parametri (host, porta, utente, password ...).
Uso:
https://riptutorial.com/it/home 97
import dj_database_url
if os.environ.get('DATABASE_URL'):
DATABASES['default'] =
dj_database_url.config(default=os.environ['DATABASE_URL'])
https://riptutorial.com/it/home 98
Capitolo 26: Integrazione continua con
Jenkins
Examples
Script Pipeline di Jenkins 2.0+
Le versioni moderne di Jenkins (versione 2.x) sono dotate di un "Build Pipeline Plugin" che può
essere utilizzato per orchestrare attività CI complesse senza creare una moltitudine di lavori
interconnessi e consentire di controllare facilmente la configurazione di build / test.
Ecco una semplice configurazione per i siti Django che richiedono l'installazione solo dei moduli
python specificati del sito.
#!/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'
}
Ecco un esempio di uno script della pipeline che crea un contenitore Docker, quindi esegue i test
al suo interno. Si presuppone che il punto di accesso sia manage.py o invoke / fabric con un
comando runtests disponibile.
#!/usr/bin/groovy
node {
stage 'Checkout'
checkout scm
sh 'git submodule update --init --recursive'
https://riptutorial.com/it/home 99
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/it/home 100
Capitolo 27: Internazionalizzazione
Sintassi
• gettext (messaggio)
• ngettext (singolare, plurale, numero)
• ugettext (messaggio)
• ungettext (singolare, plurale, numero)
• pgettext (contesto, messaggio)
• npgettext (context, singular, plural, number)
• gettext_lazy (messaggio)
• ngettext_lazy (singolare, plurale, numero = Nessuno)
• ugettext_lazy (messaggio)
• ungettext_lazy (singular, plural, number = None)
• pgettext_lazy (contesto, messaggio)
• npgettext_lazy (context, singular, plural, number = None)
• gettext_noop (messaggio)
• ugettext_noop (messaggio)
Examples
Introduzione all'internazionalizzazione
Impostare
settings.py
https://riptutorial.com/it/home 101
Marcare le stringhe come traducibili
Il primo passo nella traduzione è contrassegnare le stringhe come traducibili . Questo li sta
passando attraverso una delle funzioni gettext (vedi la sezione Sintassi ). Ad esempio, ecco un
esempio di definizione del modello:
class Child(models.Model):
class Meta:
verbose_name = _("child")
verbose_name_plural = _("children")
Tutte le stringhe incapsulate in _() ora sono contrassegnate come traducibili. Quando vengono
stampati, saranno sempre visualizzati come stringa incapsulata, qualunque sia la lingua scelta
(poiché non è ancora disponibile la traduzione).
Tradurre le stringhe
Questo esempio è sufficiente per iniziare con la traduzione. La maggior parte delle volte vorrai
solo contrassegnare le stringhe come traducibili per anticipare la futura internazionalizzazione
del tuo progetto. Quindi, questo è coperto in un altro esempio .
https://riptutorial.com/it/home 102
>>> 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'
• La traduzione non può essere attivata (lingua non selezionata) quando viene valutato
_("some string")
• Alcune stringhe possono essere valutate solo all'avvio (ad esempio in attributi di classe
come le definizioni dei campi di modello e modulo)
Traduzione in modelli
{% load i18n %}
https://riptutorial.com/it/home 103
Se first_name e last_name sono già nel tuo contesto, puoi persino omettere la clausola with :
Tuttavia, solo le variabili di contesto "di primo livello" possono essere utilizzate. Questo NON
funzionerà:
{% blocktrans %}
My name is {{ user.first_name }} {{ user.last_name }}
{% endblocktrans %}
Ciò è dovuto principalmente al fatto che il nome della variabile viene utilizzato come segnaposto
nei file di traduzione.
Infine, indipendentemente dalla libreria i18n , puoi passare stringhe traducibili ai tag modello
usando la sintassi _("") .
{{ site_name|default:_("It works!") }}
{% firstof var1 var2 _("translatable fallback") %}
Questo è un sistema di django template magico incorporato per simulare una sintassi di chiamata
di una funzione, ma questa non è una chiamata di funzione. _("It works!") Passò al tag del
template di default come una stringa '_("It works!")' Che viene poi analizzata una stringa
traducibile, proprio come il name sarebbe analizzato come variabile e il "name" sarebbe analizzato
come una stringa.
Tradurre le stringhe
Per tradurre le stringhe, dovrai creare i file di traduzione. Per fare ciò, django viene fornito con i
comandi di gestione makemessages .
$ django-admin makemessages -l fr
processing locale fr
Il comando precedente scoprirà tutte le stringhe contrassegnate come traducibili all'interno delle
app installate e creerà un file di lingua per ogni app per la traduzione francese. Ad esempio, se si
dispone di una sola app myapp contenente stringhe traducibili, verrà creato un file
myapp/locale/fr/LC_MESSAGES/django.po . Questo file potrebbe essere simile al seguente:
https://riptutorial.com/it/home 104
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR
#
#, 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 ""
Dovrai prima riempire i segnaposti (sottolineati con le maiuscole). Quindi traduci le stringhe. msgid
è la stringa contrassegnata come traducibile nel tuo codice. msgstr è dove devi scrivere la
traduzione della stringa appena sopra.
Quando una stringa contiene segnaposto, dovrai includerli anche nella tua traduzione. Ad
esempio, tradurrà l'ultimo messaggio come segue:
#: 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 volta completato il file di traduzione, dovrai compilare i file .po in file .mo . Questo viene fatto
chiamando il comando di gestione di compilemessages :
$ django-admin compilemessages
Per aggiornare i file di traduzione quando apporti modifiche al tuo codice, puoi eseguire di nuovo
https://riptutorial.com/it/home 105
django-admin makemessages -l fr . Questo aggiornerà i file .po , mantenendo le tue traduzioni
esistenti e aggiungendone di nuove. Le stringhe eliminate saranno ancora disponibili nei
commenti. Per aggiornare i file .po per tutte le lingue, esegui django-admin makemessages -a . Una
volta aggiornati i file .po , non dimenticare di eseguire nuovamente i django-admin compilemessages
per generare file .mo .
Un tipico caso d'uso è quando si desidera registrare un messaggio per gli sviluppatori (in inglese)
ma si desidera anche visualizzarlo sul client (nella lingua richiesta). È possibile passare una
variabile a gettext , ma il suo contenuto non verrà scoperto come stringa traducibile perché
è, per definizione, variabile. .
logger = logging.getLogger(__name__)
Il messaggio di errore non apparirà nel file .po e dovrai ricordare che esiste per aggiungerlo
manualmente. Per risolvere questo problema, puoi usare gettext_noop .
Ora la stringa "Oops, something went wrong!" sarà scoperto e disponibile nel file .po quando
generato. E l'errore verrà comunque registrato in inglese per gli sviluppatori.
Insidie comuni
traduzioni sfocate
A volte i makemessages possono pensare che la stringa trovata per la traduzione sia in qualche
modo simile alla traduzione già esistente. Lo farà quando lo contrassegnerà nel file .po con un
commento fuzzy speciale come questo:
#: templates/randa/map.html:91
#, fuzzy
msgid "Country"
msgstr "Länderinfo"
https://riptutorial.com/it/home 106
Anche se la traduzione è corretta o l'hai aggiornata per correggerne una, non verrà utilizzata per
tradurre il tuo progetto se non rimuovi fuzzy riga di commento fuzzy .
Stringhe multilinea
makemessages analizza i file in vari formati, dal semplice testo al codice python e non è progettato
per seguire ogni possibile regola per avere stringhe multi-linea in questi formati. La maggior parte
delle volte funziona perfettamente con le stringhe a linea singola, ma se hai una costruzione come
questa:
translation = _("firstline"
"secondline"
"thirdline")
Raccoglierà solo la prima firstline per la traduzione. La soluzione per questo è evitare l'uso di
stringhe multiline quando possibile.
https://riptutorial.com/it/home 107
Capitolo 28: JSONField - un campo specifico
PostgreSQL
Sintassi
• JSONField (** opzioni)
Osservazioni
• Django's JSONField memorizza i dati in una colonna Postgres JSONB , che è disponibile solo in
Postgres 9.4 e versioni successive.
• JSONField è ottimo quando vuoi uno schema più flessibile. Ad esempio se vuoi cambiare le
chiavi senza dover effettuare alcuna migrazione dei dati, o se non tutti gli oggetti hanno la
stessa struttura.
• Se stai memorizzando i dati con chiavi statiche, considera l'utilizzo di più campi normali
invece di JSONField di JSONField , poiché JSONField interrogazione su JSONField può diventare
piuttosto noiosa.
Concatenare query
Puoi concatenare le query insieme. Ad esempio, se un dizionario esiste all'interno di un elenco,
aggiungere due trattini bassi e la query del dizionario.
Examples
Creazione di un campo JSON
class IceCream(models.Model):
metadata = JSONField()
https://riptutorial.com/it/home 108
Creazione di un oggetto con dati in un campo JSON
Passare i dati in formato Python nativo, ad esempio list , dict , str , None , bool , ecc.
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'],
})
Ottieni tutti i coni gelato ordinati dalla gente che ama il cioccolato:
IceCream.objects.filter(metadata__buyer__favorite_flavor='chocolate')
Questo esempio ordina per data['json_objects_key'] all'interno JSONField data nome JSONField :
data = JSONField()
https://riptutorial.com/it/home 109
Leggi JSONField - un campo specifico PostgreSQL online:
https://riptutorial.com/it/django/topic/1759/jsonfield---un-campo-specifico-postgresql
https://riptutorial.com/it/home 110
Capitolo 29: Le forme
Examples
Esempio 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'}))
Widget è la rappresentazione di Django dei tag di input dell'utente HTML e può essere utilizzato
per il rendering di html personalizzato per i campi del modulo (ad esempio: come una casella di
testo viene renderizzata per l'input del contenuto qui)
attrs sono attributi che verranno copiati così come lo sono per l'html renderizzato per il modulo.
https://riptutorial.com/it/home 111
from django.db import models
from django.contrib.auth.models import User
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',)
Si noti che sotto la classe Meta nel modulo ho aggiunto una funzione init che possiamo usare
durante l'inizializzazione del modulo da views.py per eliminare un campo modulo (o alcune altre
azioni). Lo spiegherò più tardi.
Quindi questo modulo può essere utilizzato per scopi di registrazione dell'utente e vogliamo tutti i
campi definiti nella classe Meta del modulo. Ma cosa succede se vogliamo utilizzare lo stesso
modulo quando modifichiamo l'utente, ma quando lo facciamo non vogliamo mostrare il campo
admin del modulo?
def edit_profile(request,user_id):
context = RequestContext(request)
user = get_object_or_404(User, id=user_id)
profile = get_object_or_404(UserModuleProfile, user_id=user_id)
admin_check = False
https://riptutorial.com/it/home 112
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)
Come puoi vedere ho mostrato qui un semplice esempio di modifica usando il modulo che
abbiamo creato in precedenza. Nota che quando ho inizializzato il modulo ho passato una
variabile admin_check aggiuntiva che contiene True o False .
Ora Se noti il modulo che abbiamo scritto in precedenza puoi vedere che in init proviamo a
catturare il parametro admin_check che passiamo da qui. Se il valore è False, semplicemente
eliminiamo il campo admin dal modulo e lo usiamo. E poiché questo è un modello di modulo, il
campo admin non può essere nullo nel modello, controlliamo semplicemente se il post del modulo
ha il campo admin nel post del modulo, altrimenti lo impostiamo su False nel codice della vista nel
seguente codice della vista.
https://riptutorial.com/it/home 113
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
Anche qui lavorerai con ImageField , quindi ricorda di installare in questo caso la libreria Pillow (
pip install pillow ). In caso contrario, si avrà tale errore:
Pillow è un fork di PIL, la Python Imaging Library, che non viene più mantenuta. Il cuscino è
retrocompatibile con PIL.
Django viene fornito con due campi modulo per caricare file sul server, FileField e ImageField , il
seguente è un esempio di utilizzo di questi due campi nel nostro modulo
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>
</body>
</html>
https://riptutorial.com/it/home 114
Convalida dei campi e impegno per modellare (Modifica e-mail utente)
Ci sono già moduli implementati in Django per cambiare la password dell'utente, un esempio è
SetPasswordForm .
Non ci sono, tuttavia, moduli per modificare l'e-mail dell'utente e penso che il seguente esempio
sia importante per capire come utilizzare correttamente un modulo.
• Le e-mail sono infatti cambiate - molto utili se è necessario convalidare l'e-mail o aggiornare
la posta scimpanzè;
• Sia l'e-mail sia l'e-mail di conferma sono le stesse: il modulo ha due campi per l'e-mail,
quindi l'aggiornamento è meno soggetto a errori.
E alla fine, salva la nuova e-mail nell'oggetto utente (aggiorna l'e-mail dell'utente). Si noti che il
metodo __init__() richiede un oggetto utente.
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',
)
return new_email1
def clean_new_email2(self):
new_email1 = self.cleaned_data.get('new_email1')
new_email2 = self.cleaned_data.get('new_email2')
https://riptutorial.com/it/home 115
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/it/home 116
Capitolo 30: Meta: linee guida per la
documentazione
Osservazioni
Questa è un'estensione di "Meta: Documentation Guidelines" di Python per Django.
Queste sono solo proposte, non raccomandazioni. Sentiti libero di modificare qualsiasi cosa qui se
non sei d'accordo o hai qualcos'altro da dire.
Examples
Le versioni non supportate non richiedono menzioni speciali
È improbabile che qualcuno usi una versione non supportata di Django, ea proprio rischio. Se mai
qualcuno lo fa, deve preoccuparsi di sapere se esiste una funzionalità nella versione fornita.
Considerando quanto sopra, è inutile menzionare le specificità di una versione non supportata.
1.6
Questo tipo di blocco è inutile perché nessuna persona sana di mente usa Django <1.6.
1.8
Questo tipo di blocco è inutile perché nessuna persona sana di mente usa Django <1,8.
Questo vale anche per gli argomenti. Al momento della stesura di questo esempio, le viste basate
sulla classe 1.3-1.9 versioni supportate sono 1.3-1.9 . Possiamo tranquillamente supporre che
questo sia effettivamente equivalente a All versions . Questo evita anche l'aggiornamento di tutte
le versioni supportate da argomenti ogni volta che viene rilasciata una nuova versione.
1. Correzioni di sicurezza, bug di perdita di dati, bug che si bloccano, bug di funzionalità
importanti nelle funzionalità appena introdotte e regressioni da versioni precedenti di Django.
2. Correzioni di sicurezza e bug di perdita di dati.
https://riptutorial.com/it/home 117
Capitolo 31: middleware
introduzione
Middleware in Django è un framework che consente al codice di agganciarsi all'elaborazione di
risposta / richiesta e di modificare l'input o l'output di Django.
Osservazioni
Il middleware deve essere aggiunto all'elenco settings.py MIDDLEWARE_CLASSES prima che venga
incluso nell'esecuzione. L'elenco predefinito che Django fornisce quando si crea un nuovo
progetto è il seguente:
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',
]
Queste sono tutte funzioni che verranno eseguite in ordine su ogni richiesta (una volta prima che
raggiunga il codice di visualizzazione in views.py e una volta in ordine inverso per la richiamata
process_response , prima della versione 1.10). Fanno una varietà di cose come l'iniezione del token
Cross Site Request Forgery (csrf) .
Examples
Aggiungi dati alle richieste
Django rende davvero facile aggiungere ulteriori dati alle richieste per l'uso all'interno della vista.
Ad esempio, possiamo analizzare il sottodominio sul META della richiesta e collegarlo come una
proprietà separata sulla richiesta utilizzando il 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/it/home 118
request.subdomain = None
if len(host_s) > 2:
request.subdomain = host_s[0]
Se si aggiungono dati con middleware alla richiesta, è possibile accedere a tali dati aggiunti di
recente lungo la linea. Qui utilizzeremo il sottodominio analizzato per determinare qualcosa di
simile a quale organizzazione sta accedendo alla tua applicazione. Questo approccio è utile per le
app distribuite con un'impostazione DNS con sottodomini jolly che puntano tutti a una singola
istanza e la persona che accede all'app desidera che una versione sottoposta a skin sia
dipendente dal punto di accesso.
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
Ricorda che l'ordine conta quando il middleware dipende l'uno dall'altro. Per le richieste, è
necessario che il middleware dipendente venga inserito dopo la dipendenza.
MIDDLEWARE_CLASSES = [
...
'myapp.middleware.SubdomainMiddleware',
'myapp.middleware.OrganizationMiddleware',
...
]
Se non ce l'hai, devi creare la cartella middleware all'interno della tua app seguendo la struttura:
yourproject/yourapp/middleware
Il middleware delle cartelle deve essere inserito nella stessa cartella di settings.py, urls, templates
...
Importante: non dimenticare di creare il file init .py vuoto all'interno della cartella
middleware in modo che la tua app riconosca questa cartella
Invece di avere una cartella separata contenente le classi del middleware, è anche possibile
mettere le tue funzioni in un singolo file, yourproject/yourapp/middleware.py .
https://riptutorial.com/it/home 119
Ora dovremmo creare un file per il nostro middleware personalizzato. In questo esempio
supponiamo di volere un middleware che filtra gli utenti in base al loro indirizzo IP, creiamo un file
chiamato 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
Fatto! Ora ogni richiesta da ogni cliente chiamerà il tuo middleware personalizzato ed elaborerà il
tuo codice personalizzato!
Supponiamo che tu abbia implementato una logica per rilevare i tentativi di modificare un oggetto
nel database mentre il client che ha presentato le modifiche non ha avuto le ultime modifiche. In
tal caso, si ConfictError(detailed_message) un'eccezione personalizzata
ConfictError(detailed_message) .
Ora si desidera restituire un codice di stato HTTP 409 (Confict) quando si verifica questo errore. In
genere, puoi usarlo come middleware invece di gestirlo in ogni vista che potrebbe sollevare
questa eccezione.
class ConfictErrorHandlingMiddleware:
def process_exception(self, request, exception):
if not isinstance(exception, ConflictError):
return # Propagate other exceptions, we only handle ConflictError
https://riptutorial.com/it/home 120
context = dict(confict_details=str(exception))
return TemplateResponse(request, '409.html', context, status=409)
Django 1.10 ha introdotto un nuovo stile middleware in cui process_request e process_response sono
uniti.
In questo nuovo stile, un middleware è un callable che restituisce un altro callable . Bene, in realtà
il primo è una fabbrica di middleware e il secondo è il vero middleware .
La factory middleware prende come argomento singolo il middleware successivo nello stack
middleware o la vista stessa quando viene raggiunto il fondo dello stack.
Il miglior esempio per illustrare come funziona il middleware di nuovo stile è probabilmente quello
di mostrare come creare un middleware compatibile con le versioni precedenti:
class MyMiddleware:
https://riptutorial.com/it/home 121
Capitolo 32: migrazioni
Parametri
makemigrations --name <migration_name> Genera una migrazione per my_app con il nome
<my_app> migration_name
Examples
Lavorare con le migrazioni
Django usa le migrazioni per propagare le modifiche apportate ai tuoi modelli al tuo database. Il
più delle volte django può generarli per te.
Questo creerà un file di migrazione nel sottomodulo di migration di app_name . La prima migrazione
sarà denominata 0001_initial.py , l'altra inizierà con 0002_ , quindi 0003 , ...
https://riptutorial.com/it/home 122
Se ometti <app_name> questo creerà le migrazioni per tutti i tuoi INSTALLED_APPS .
Chiama anche ripristinare le migrazioni, questo può essere fatto passando il nome della migrate
command . Dato l'elenco di migrazioni di cui sopra (mostrato da django-admin showmigrations ):
Migrazioni manuali
A volte, le migrazioni generate da Django non sono sufficienti. Ciò è particolarmente vero quando
si desidera effettuare migrazioni di dati .
class Article(models.Model):
title = models.CharField(max_length=70)
Questo modello ha già dati esistenti e ora vuoi aggiungere uno SlugField :
class Article(models.Model):
title = models.CharField(max_length=70)
slug = models.SlugField(max_length=70)
Hai creato le migrazioni per aggiungere il campo, ma ora ti piacerebbe impostare lo slug per tutti
gli articoli esistenti, in base al loro title .
https://riptutorial.com/it/home 123
$ 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()
...
>>>
Ma dovrai farlo in tutti i tuoi ambienti (ad esempio il tuo desktop dell'ufficio, il tuo laptop, ...), tutti i
tuoi colleghi dovranno farlo anche tu, e dovrai pensarci su come mettere in scena e quando spingi
vivere.
Per farlo una volta per tutte, lo faremo in una migrazione. Per prima cosa crea una migrazione
vuota:
Questo creerà un file di migrazione vuoto. Aprilo, contiene uno scheletro di base. Supponiamo che
la tua precedente migrazione sia stata denominata 0023_article_slug e che questa sia denominata
0024_auto_20160719_1734 . Ecco cosa scriveremo nel nostro file di migrazione:
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.
]
Migrazioni false
https://riptutorial.com/it/home 124
Quando viene eseguita una migrazione, Django memorizza il nome della migrazione in una tabella
django_migrations.
Se la tua app ha già modelli e tabelle di database e non ha migrazioni. Per prima cosa crea le
migrazioni iniziali per la tua app.
introduzione
A volte le migrazioni entrano in conflitto, con il risultato di rendere la migrazione non riuscita.
Questo può accadere in un sacco di scenerio, tuttavia può verificarsi regolarmente durante lo
sviluppo di un'app con un team.
I conflitti di migrazione comuni si verificano durante l'utilizzo del controllo del codice sorgente,
soprattutto quando viene utilizzato il metodo funzione-per-ramo. Per questo scenario useremo un
modello chiamato Reporter con gli attributi name e address .
Due sviluppatori a questo punto svilupperanno una funzionalità, quindi entrambi avranno questa
https://riptutorial.com/it/home 125
copia iniziale del modello Reporter . Lo sviluppatore A aggiunge age che risulta nel file
0002_reporter_age.py . Lo sviluppatore B aggiunge un campo bank_account che viene
0002_reporter_bank_account in 0002_reporter_bank_account . Una volta che questi sviluppatori
uniscono il loro codice e tentano di migrare le migrazioni, si è verificato un conflitto di migrazione.
Questo conflitto si verifica perché queste migrazioni modificano entrambi lo stesso modello,
Reporter . Inoltre, i nuovi file iniziano entrambi con 0002.
Unione di migrazioni
Ci sono diversi modi per farlo. Quanto segue è nell'ordine consigliato:
2. Quando questo file extra non è benvenuto nell'ambiente di sviluppo per motivi personali,
un'opzione è quella di eliminare le migrazioni in conflitto. Quindi, è possibile eseguire una
nuova migrazione utilizzando il normale comando makemigrations . Quando vengono scritte le
migrazioni personalizzate, ad esempio migrations.RunPython , è necessario tenere conto
dell'utilizzo di questo metodo.
Prima di tutto, supponiamo che questo sia il tuo modello iniziale, all'interno di un'applicazione
chiamata discography :
class Album(models.Model):
name = models.CharField(max_length=255)
artist = models.CharField(max_length=255)
Ora, ti rendi conto che vuoi usare una ForeignKey per l'artista. Questo è un processo un po
'complesso, che deve essere fatto in diversi passaggi.
class Album(models.Model):
name = models.CharField(max_length=255)
artist = models.CharField(max_length=255)
artist_link = models.ForeignKey('Artist', null=True)
class Artist(models.Model):
name = models.CharField(max_length=255)
https://riptutorial.com/it/home 126
... e creare una migrazione per questo cambiamento.
Passaggio 2, compilare il nuovo campo. Per fare ciò, devi creare una migrazione vuota.
Una volta che hai questa migrazione vuota, vuoi aggiungere una singola operazione RunPython ad
essa per collegare i tuoi record. In questo caso, potrebbe assomigliare a questo:
Ora che i tuoi dati vengono trasferiti nel nuovo campo, potresti effettivamente essere fatto e
lasciare tutto come è, usando il nuovo campo artist_link per tutto. Oppure, se vuoi fare un po 'di
pulizia, vuoi creare altre due migrazioni.
Per la tua prima migrazione, vorrai cancellare il tuo campo originale, artist . Per la tua seconda
migrazione, rinomina il nuovo campo artist_link con l' artist .
Questo viene fatto in più passaggi per garantire che Django riconosca le operazioni correttamente.
https://riptutorial.com/it/home 127
Capitolo 33: Modelli
introduzione
Nel caso base, un modello è una classe Python che esegue il mapping su una singola tabella di
database. Gli attributi della mappa della classe alle colonne nella tabella e un'istanza della classe
rappresentano una riga nella tabella del database. I modelli ereditano da django.db.models.Model
che fornisce una ricca API per aggiungere e filtrare i risultati dal database.
Examples
Creare il tuo primo modello
I modelli sono in genere definiti nel file models.py nella sottodirectory dell'applicazione. La classe
Model del modulo django.db.models è una buona classe iniziale per estendere i tuoi modelli. Per
esempio:
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)
Insieme agli attributi definiamo un metodo __str__ questo restituisce il titolo del libro che verrà
usato come rappresentazione di string dove necessario, piuttosto che come predefinito.
https://riptutorial.com/it/home 128
Dopo aver creato un nuovo modello o modificato i modelli esistenti, sarà necessario generare
migrazioni per le modifiche e quindi applicare le migrazioni al database specificato. Questo può
essere fatto usando il sistema di migrazione integrato di Django. Utilizzo dell'utilità manage.py nella
directory root del progetto:
Il comando precedente creerà gli script di migrazione necessari nella sottodirectory delle
migrations dell'applicazione. Se si omette il parametro <appname> , verranno elaborate tutte le
applicazioni definite nell'argomento INSTALLED_APPS di settings.py . Se lo ritieni necessario, puoi
modificare le migrazioni.
È possibile controllare quali migrazioni sono richieste senza effettivamente creare la migrazione
utilizzare l'opzione --dry-run, ad esempio:
Il comando precedente eseguirà gli script di migrazione generati nel primo passaggio e aggiornerà
fisicamente il database.
Se il modello del database esistente viene modificato, è necessario il seguente comando per
apportare le modifiche necessarie.
Django creerà la tabella con il nome <appname>_<classname> per impostazione predefinita. A volte
non vuoi usarlo. Se vuoi cambiare il nome predefinito, puoi annunciare il nome della tabella
impostando db_table nella classe Meta :
class YourModel(models.Model):
parms = models.CharField()
class Meta:
db_table = "custom_table_name"
Se vuoi vedere quale codice SQL verrà eseguito da una certa migrazione, esegui questo
comando:
Django> 1.10
La nuova opzione makemigrations --check rende il comando di uscita con uno stato diverso da zero
quando vengono rilevate modifiche del modello senza migrazioni.
https://riptutorial.com/it/home 129
Vedi Migrazioni per maggiori dettagli sulle migrazioni.
Relazione molti-a-uno
class Author(models.Model):
name = models.CharField(max_length=50)
Opzione più generica. Può essere utilizzato ovunque tu voglia rappresentare una relazione
Relazione molti-a-molti
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)
In questo modo, possiamo effettivamente mantenere più metadati su una relazione tra due entità.
Come si può vedere, un cliente può essere abbonato a diversi servizi tramite diversi tipi di
abbonamento. L'unica differenza in questo caso è che per aggiungere nuove istanze alla relazione
M2M, non è possibile utilizzare il metodo di scelta rapida pizza.toppings.add(topping) , invece,
dovrebbe essere creato un nuovo oggetto della classe through ,
Subscription.objects.create(client=client, service=service, subscription_type='p')
https://riptutorial.com/it/home 130
In altre lingue, le through tables sono anche note come JoinColumn , Intersection table
o mapping table
Relazione uno-a-uno
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)
Usa questi campi quando avrai sempre una relazione di composizione tra i due modelli.
Django ORM è un'astrazione potente che ti consente di archiviare e recuperare dati dal database
senza dover scrivere query SQL.
class Author(models.Model):
name = models.CharField(max_length=50)
class Book(models.Model):
name = models.CharField(max_length=50)
author = models.ForeignKey(Author)
Supponendo che tu abbia aggiunto il codice sopra a un'applicazione django ed esegui il comando
migrate (in modo che il tuo database sia creato). Inizia la shell di Django di
Questo avvia la shell python standard ma con importate librerie Django rilevanti, in modo che tu
possa concentrarti direttamente sulle parti importanti.
Inizia importando i modelli che abbiamo appena definito (presumo che ciò avvenga in un file
models.py )
>>> Author.objects.all()
[]
>>> Book.objects.all()
[]
https://riptutorial.com/it/home 131
>>> hawking = Author(name="Stephen hawking")
>>> hawking.save()
>>> history_of_time = Book(name="history of time", author=hawking)
>>> history_of_time.save()
oppure utilizzare la funzione crea per creare oggetti modello e salvare in un codice di linea
>>> 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>]
Per ottenere tutti i libri pubblicati da Stephen Hawking (libro Lookup dal suo autore)
>>> hawking.book_set.all()
[<Book: Book object>]
_setè la notazione usata per "Reverse lookups" cioè, mentre il campo di ricerca è sul modello
Book, possiamo usare book_set su un oggetto autore per ottenere tutti i suoi libri.
Ad un certo punto del tuo utilizzo di Django, potresti trovarti a voler interagire con le tabelle che
sono già state create o con le viste del database. In questi casi, non vorrai che Django gestisca le
tabelle attraverso le sue migrazioni. Per impostare questo, è necessario aggiungere solo una
variabile alla classe Meta del modello: managed = False .
Ecco un esempio di come è possibile creare un modello non gestito per interagire con una vista
del database:
class Dummy(models.Model):
something = models.IntegerField()
https://riptutorial.com/it/home 132
class Meta:
managed = False
Questo può essere associato a una vista definita in SQL come segue.
Una volta creato questo modello, puoi utilizzarlo come faresti con qualsiasi altro modello:
>>> Dummy.objects.all()
[<Dummy: Dummy object>, <Dummy: Dummy object>, <Dummy: Dummy object>]
>>> Dummy.objects.filter(something=42)
[<Dummy: Dummy object>]
Modelli avanzati
Un modello può fornire molte più informazioni rispetto ai soli dati su un oggetto. Vediamo un
esempio e scomporlo in ciò che è utile per:
@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']
URL assoluto
La prima funzione definita è get_absolute_url . In questo modo, se si dispone di un libro, è
https://riptutorial.com/it/home 133
possibile ottenere un collegamento ad esso senza manipolare il tag url, risolvere, attributo e simili.
Chiama semplicemente book.get_absolute_url e ottieni il link giusto. Come bonus, il tuo oggetto
nell'amministratore di django otterrà un pulsante "Visualizza sul sito".
Il decoratore di classi ti consente di definire il metodo una volta sia per __str__ che __unicode__ su
python 2 senza causare alcun problema su python 3. Se ti aspetti che la tua app funzioni su
entrambe le versioni, questa è la strada da percorrere.
Campo di lumaca
Il campo slug è simile a un campo char ma accetta meno simboli. Per impostazione predefinita,
solo lettere, numeri, caratteri di sottolineatura o trattini. È utile se vuoi identificare un oggetto
usando una bella rappresentazione, ad esempio nell'URL.
La classe Meta
La classe Meta ci consente di definire molte più informazioni sull'intera collezione di oggetti. Qui è
impostato solo l'ordine predefinito. Ad esempio, è utile con l'oggetto ListView. Prende una lista
ideale di campo da usare per l'ordinamento. Qui, il libro verrà ordinato prima per data di
pubblicazione e poi per titolo se la data è la stessa.
Gli altri attributi di frequenza sono verbose_name e verbose_name_plural . Di default, sono generati dal
nome del modello e dovrebbero andare bene. Ma la forma plurale è ingenua, semplicemente
aggiungendo un 's' al singolare, quindi potresti volerlo impostare in modo esplicito in alcuni casi.
Valori calcolati
Una volta che un oggetto modello è stato recuperato, diventa un'istanza pienamente realizzata
della classe. Di conseguenza, è possibile accedere a qualsiasi metodo aggiuntivo nei moduli e nei
serializzatori (come Django Rest Framework).
L'utilizzo delle proprietà python è un modo elegante per rappresentare valori aggiuntivi che non
sono memorizzati nel database a causa di circostanze variabili.
def expire():
return timezone.now() + timezone.timedelta(days=7)
class Coupon(models.Model):
expiration_date = models.DateField(default=expire)
https://riptutorial.com/it/home 134
@property
def is_expired(self):
return timezone.now() > self.expiration_date
Mentre nella maggior parte dei casi è possibile integrare dati con annotazioni sui propri querysets,
i valori calcolati come proprietà del modello sono ideali per i calcoli che non possono essere
valutati semplicemente nell'ambito di una query.
Inoltre, le proprietà, dal momento che sono dichiarate sulla classe python e non come parte dello
schema, non sono disponibili per l'esecuzione di query.
# 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>
<Book: Book object> , l'output predefinito, non ci è di aiuto. Per risolvere questo problema,
aggiungiamo un metodo __str__ .
@python_2_unicode_compatible
class Book(models.Model):
name = models.CharField(max_length=50)
author = models.CharField(max_length=50)
def __str__(self):
return '{} by {}'.format(self.name, self.author)
https://riptutorial.com/it/home 135
Nota che il decoratore python_2_unicode_compatible è necessario solo se vuoi che il tuo codice sia
compatibile con python 2. Questo decoratore copia il metodo __str__ per creare un metodo
__unicode__ . django.utils.encoding da django.utils.encoding .
>>> print(himu_book)
Himu Mama by Humayun Ahmed
Molto meglio!
La rappresentazione della stringa viene anche utilizzata quando il modello viene utilizzato in un
campo ModelForm per i campi ForeignKeyField e ManyToManyField .
Model mixins
Negli stessi casi, diversi modelli potrebbero avere gli stessi campi e le stesse procedure nel ciclo
di vita del prodotto. Per gestire queste somiglianze senza avere l'ereditarietà di ripetizione del
codice potrebbe essere utilizzato. Invece di ereditare un'intera classe, il modello di progettazione
mixin ci consente di ereditare ( o alcuni include include ) alcuni metodi e attributi. Vediamo un
esempio:
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)
depth = models.DecimalField(max_digits=5, decimal_places=2)
Per trasformare un modello in una classe astratta, dovrai menzionare abstract=True nella sua
https://riptutorial.com/it/home 136
classe Meta interna. Django non crea tabelle per i modelli astratti nel database. Tuttavia, per i
modelli Envelope e Package , le tabelle corrispondenti verranno create nel database.
Inoltre i campi alcuni metodi modello saranno necessari in più di un modello. Quindi questi metodi
potrebbero essere aggiunti ai mixin per prevenire la ripetizione del codice. Ad esempio, se
creiamo un metodo per impostare la data di consegna su PostableMixin , sarà accessibile da
entrambi i suoi figli:
class PostableMixin(models.Model):
class Meta:
abstract=True
...
...
self.delivery_datetime = dt
self.save()
Un modello per impostazione predefinita utilizza una chiave primaria con incremento automatico
(numero intero). Questo ti darà una sequenza di chiavi 1, 2, 3.
Diversi tipi di chiavi primarie possono essere impostati su un modello con piccole modifiche al
modello.
import uuid
from django.db import models
class ModelUsingUUID(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
https://riptutorial.com/it/home 137
Eredità
L'ereditarietà di più tabelle creerà una tabella per i campi comuni e uno per esempio di modello
figlio:
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)
creerà 2 tabelle, una per il Place e una per il Restaurant con un campo OneToOne nascosto da Place
per i campi comuni.
si noti che questo richiederà una query aggiuntiva alle tabelle dei luoghi ogni volta che si recupera
un oggetto ristorante.
https://riptutorial.com/it/home 138
Capitolo 34: Processori di contesto
Osservazioni
Utilizza processori di contesto per aggiungere variabili accessibili ovunque nei tuoi modelli.
Specificare una funzione, o funzioni che restituiscono le dict delle variabili desiderate, quindi
aggiungere tali funzioni a TEMPLATE_CONTEXT_PROCESSORS .
Examples
Utilizzare un processore di contesto per accedere alle impostazioni.DEBUG
nei modelli
in myapp/context_processors.py :
def debug(request):
return {'DEBUG': settings.DEBUG}
in settings.py :
TEMPLATES = [
{
...
'OPTIONS': {
'context_processors': [
...
'myapp.context_processors.debug',
],
},
},
]
TEMPLATE_CONTEXT_PROCESSORS = (
...
'myapp.context_processors.debug',
)
Utilizzo di un processore di contesto per accedere alle voci del blog più
https://riptutorial.com/it/home 139
recenti in tutti i modelli
Supponendo che tu abbia un modello definito Post definito nel tuo file models.py che contiene post
di blog e che abbia un campo 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
Assicurati di aggiungere il nuovo processore di contesto al file settings.py nella variabile TEMPLATES
:
TEMPLATES = [
{
...
'OPTIONS': {
'context_processors': [
...
'myapp.context_processors.recent_blog_posts',
],
},
},
]
(Nelle versioni di Django precedenti alla 1.9, questo era impostato direttamente in settings.py
usando una variabile TEMPLATE_CONTEXT_PROCESSORS .)
Non è più necessario passare più recenti post di blog attraverso le singole visualizzazioni! Basta
usare recent_blog_posts in qualsiasi modello.
Ad esempio, in home.html puoi creare una barra laterale con link a post recenti:
<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/it/home 140
Oppure in blog.html potresti creare una visualizzazione più dettagliata di ogni post:
<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>
Processore di contesto per determinare il modello in base all'appartenenza al gruppo (oa qualsiasi
query / logica). Ciò consente ai nostri utenti pubblici / regolari di ottenere un modello e il nostro
gruppo speciale per ottenerne uno diverso.
frontend / 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/it/home 141
Capitolo 35: RangeFields: un gruppo di
campi specifici di PostgreSQL
Sintassi
• dall'importazione django.contrib.postgres.fields * RangeField
• IntegerRangeField (** opzioni)
• BigIntegerRangeField (** opzioni)
• FloatRangeField (** opzioni)
• DateTimeRangeField (** opzioni)
• DateRangeField (** opzioni)
Examples
Compresi i campi dell'intervallo numerico nel modello
class Book(models.Model):
name = CharField(max_length=200)
ratings_range = IntegerRange()
È più semplice e più semplice inserire valori come una tupla Python invece di un NumericRange .
L'utilizzo contiene
Questa query seleziona tutti i libri con una valutazione inferiore a tre.
https://riptutorial.com/it/home 142
bad_books = Books.objects.filter(ratings_range__contains=(1, 3))
Utilizzando contenuto_by
Questa query ottiene tutti i libri con valutazioni superiori o uguali a zero e inferiori a sei.
Usando la sovrapposizione
Appointment.objects.filter(time_span__overlap=(6, 10))
Questa query seleziona tutti i libri con una valutazione superiore o uguale a quattro.
Varia le operazioni
# Events which, at least partially, take place during the selected period.
Event.objects.filter(timeslot__overlap=period)
https://riptutorial.com/it/home 143
Capitolo 36: Registrazione
Examples
Accesso al servizio Syslog
È possibile configurare Django per l'output del log su un servizio syslog locale o remoto. Questa
configurazione utilizza il python integrato SysLogHandler .
https://riptutorial.com/it/home 144
Configurazione di registrazione di base di Django
Django utilizza internamente il sistema di registrazione Python. Vi sono molti modi per configurare
la registrazione di un progetto. Ecco 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',
},
}
}
formattatori
Può essere utilizzato per configurare l'aspetto dei registri quando vengono stampati sull'output. È
possibile definire molti formattatori impostando una stringa chiave su ogni formattatore diverso. Un
formattatore viene quindi utilizzato quando si dichiara un gestore.
handlers
Può essere usato per configurare dove verranno stampati i registri. Nell'esempio sopra, vengono
inviati a stdout e stderr. Esistono varie classi di gestori:
'rotated_logs': {
'class': 'logging.handlers.RotatingFileHandler',
'filename': '/var/log/my_project.log',
'maxBytes': 1024 * 1024 * 5, # 5 MB
'backupCount': 5,
'formatter': 'default'
'level': 'DEBUG',
},
Ciò produrrà i file di registro immessi per filename . In questo esempio, verrà creato un nuovo file
di registro quando il corrente raggiunge la dimensione di 5 MB (il vecchio viene rinominato in
my_project.log.1) e gli ultimi 5 file verranno conservati per l'archiviazione.
https://riptutorial.com/it/home 145
'mail_admins': {
'level': 'ERROR',
'class': 'django.utils.log.AdminEmailHandler'
},
Questo invierà ciascun log da eamil agli utenti specificati nella variabile di impostazione ADMINS . Il
livello è impostato su ERROR , quindi solo i log con livello ERROR verranno inviati via e-mail. Questo è
estremamente utile per rimanere informati su potenziali errori 50x su un server di produzione.
Altri gestori possono essere utilizzati con Django. Per un elenco completo, leggere la
documentazione corrispondente. Come i formattatori, è possibile definire molti gestori in uno
stesso progetto, impostando per ciascuno una stringa di chiavi diversa. Ogni gestore può essere
utilizzato in un logger specifico.
logger
In LOGGING , l'ultima parte configura per ciascun modulo il livello minimo di registrazione, i gestori da
utilizzare, ecc.
https://riptutorial.com/it/home 146
Capitolo 37: Relazioni molti-a-molti
Examples
Con un modello passante
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/it/home 147
Relazione semplice da molti a molti.
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)
Qui definiamo una relazione in cui un club ha molte Person e membri e una persona può essere
membro di diversi Club .
Sebbene definiamo solo due modelli, django crea effettivamente tre tabelle nel database per noi.
Questi sono myapp_person , myapp_club e myapp_club_members. Django crea automaticamente un
indice univoco sulle 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)
Ti darò
Tom
Bill
https://riptutorial.com/it/home 148
Capitolo 38: Riferimento del campo del
modello
Parametri
Parametro Dettagli
https://riptutorial.com/it/home 149
Parametro Dettagli
unique_for_month Simile a unique_for_date , tranne che i controlli sono limitati per il mese.
Osservazioni
• Puoi scrivere i tuoi campi se lo ritieni necessario
• È possibile sovrascrivere le funzioni della classe del modello di base, più comunemente la
funzione save()
Examples
Campi numerici
AutoField
https://riptutorial.com/it/home 150
class MyModel(models.Model):
pk = models.AutoField()
Per impostazione predefinita, ogni modello riceve un campo chiave primaria (chiamato
id ). Pertanto, non è necessario duplicare un campo id nel modello ai fini di una chiave
primaria.
BigIntegerField
class MyModel(models.Model):
number_of_seconds = models.BigIntegerField()
IntegerField
IntegerField viene utilizzato per memorizzare valori interi da -2147483648 a 2147483647 ( 4 Bytes
).
class Food(models.Model):
name = models.CharField(max_length=255)
calorie = models.IntegerField(default=0)
PositiveIntegerField
Come un campo intero, ma deve essere positivo o uguale a zero (0). Il campo PositiveInteger
viene utilizzato per memorizzare valori interi da 0 a 2147483647 ( 4 Bytes ). Questo può essere
utile in campo che dovrebbe essere semanticamente positivo. Ad esempio se stai registrando cibi
con le sue calorie, non dovrebbe essere negativo. Questo campo impedisce i valori negativi
tramite le sue convalide.
class Food(models.Model):
name = models.CharField(max_length=255)
calorie = models.PositiveIntegerField(default=0)
https://riptutorial.com/it/home 151
SmallIntegerField
SmallIntegerField viene utilizzato per memorizzare valori interi da -32768 a 32767 ( 2 Bytes ).
Questo campo è utile per valori non non estremi.
class Place(models.Model):
name = models.CharField(max_length=255)
temperature = models.SmallIntegerField(null=True)
PositiveSmallIntegerField
SmallIntegerField viene utilizzato per memorizzare valori interi da 0 a 32767 ( 2 Bytes ). Proprio
come SmallIntegerField questo campo è utile per valori che non vanno così alti e dovrebbero
essere semanticamente positivi. Ad esempio, può memorizzare l'età che non può essere 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
)
...
La definizione delle scelte come variabili di classe o variabili del modulo in base alla
situazione è un buon modo per usarle. Se le scelte sono passate al campo senza nomi
amiche di quanto creerà confusione.
https://riptutorial.com/it/home 152
DecimalField
class Place(models.Model):
name = models.CharField(max_length=255)
atmospheric_pressure = models.DecimalField(max_digits=5, decimal_places=3)
BinaryField
Questo è un campo specializzato, usato per memorizzare dati binari. Accetta solo byte . I dati
sono serializzati in base64 su storage.
Poiché si stanno memorizzando dati binari, questo campo non può essere utilizzato in un filtro.
class MyModel(models.Model):
my_binary_data = models.BinaryField()
CharField
Il CharField viene utilizzato per memorizzare lunghezze di testo definite. Nell'esempio seguente
possono essere memorizzati fino a 128 caratteri di testo nel campo. L'inserimento di una stringa
più lunga comporterà l'innalzamento di un errore di convalida.
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/it/home 153
• auto_now_add imposta il valore del campo sul datetime corrente al momento della creazione
dell'oggetto.
• auto_now imposta il valore del campo sul datetime corrente ogni volta che viene salvato il
campo.
ForeignKey
Il campo ForeignKey viene utilizzato per creare una relazione many-to-one tra i modelli. Non come
la maggior parte degli altri campi richiede argomenti posizionali. L'esempio seguente dimostra la
relazione tra auto e proprietario:
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)
Il primo argomento del campo è la classe a cui è correlato il modello. Il secondo argomento
posizionale è on_delete argomento on_delete . Nelle versioni attuali questo argomento non è
richiesto, ma sarà richiesto in Django 2.0. La funzionalità predefinita dell'argomento è mostrata
come segue:
class Car(model.Model)
owner = models.ForeignKey('Person', on_delete=models.CASCADE)
...
Ciò causerà l'eliminazione degli oggetti Car dal modello quando il relativo proprietario
viene eliminato dal modello Persona. Questa è la funzionalità predefinita.
class Car(model.Model)
owner = models.ForeignKey('Person', on_delete=models.PROTECT)
...
https://riptutorial.com/it/home 154
Ciò impedirà l'eliminazione degli oggetti Person se sono collegati ad almeno un
oggetto Car. Tutti gli oggetti Car che fanno riferimento a un oggetto Persona devono
essere prima eliminati. E poi l'oggetto Persona può essere cancellato.
https://riptutorial.com/it/home 155
Capitolo 39: Router di database
Examples
Aggiunta di un file di routing del database
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']
}
}
Utilizzare un file dbrouters.py per specificare quali modelli devono operare su quali database per
ogni classe di operazione del database, ad esempio per i dati remoti archiviati in remote_data , si
potrebbe desiderare quanto segue:
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/it/home 156
obj2._meta.app_label == 'remote':
return False
return None
DATABASE_ROUTERS = ['path.to.DbRouter', ]
Il normale metodo obj.save() utilizzerà il database predefinito oppure, se viene utilizzato un router
di database, utilizzerà il database come specificato in db_for_write . Puoi sovrascriverlo usando:
obj.save(using='other_db')
obj.delete(using='other_db')
MyModel.objects.using('other_db').all()
https://riptutorial.com/it/home 157
Capitolo 40: Routing URL
Examples
Come Django gestisce una richiesta
Django gestisce una richiesta instradando il percorso dell'URL in entrata a una funzione di
visualizzazione. La funzione di visualizzazione è responsabile di restituire una risposta al client
che effettua la richiesta. URL diversi vengono generalmente gestiti da diverse funzioni di
visualizzazione. Per indirizzare la richiesta ad una specifica funzione di visualizzazione, Django
controlla la configurazione dell'URL (o URLconf in breve). Il modello di progetto predefinito
definisce URLconf in <myproject>/urls.py .
Il tuo URLconf dovrebbe essere un modulo python che definisce un attributo chiamato urlpatterns
, che è una lista di django.conf.urls.url() di django.conf.urls.url() . Ogni istanza di url() deve
almeno definire un'espressione regolare (una regex) da abbinare all'URL e una destinazione, che
è una funzione di visualizzazione o un URLconf differente. Se un pattern URL ha come target una
funzione di visualizzazione, è una buona idea assegnargli un nome per fare facilmente riferimento
al modello in un secondo momento.
# 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'),
]
Questo URLconf definisce tre pattern URL, tutti mirati a una vista: home , about e blog-detail .
La regex contiene un'ancora di inizio '^', immediatamente seguita da un'ancora di fine '$'. Questo
modello corrisponderà alle richieste in cui il percorso dell'URL è una stringa vuota e le indirizza
alla vista home definita in myapp.views .
Questa regex contiene un'ancora di inizio, seguita dalla stringa letterale about/ , e dall'ancora di
fine. Questo corrisponderà all'URL /about/ e lo indirizzerà alla visualizzazione about . Poiché ogni
URL non vuoto inizia con un / , Django taglia comodamente la prima barra per te.
https://riptutorial.com/it/home 158
Questa regex è un po 'più complessa. Definisce l'ancora di partenza e il blog/ stringa letterale
blog/ , come il modello precedente. La parte successiva, (?P<id>\d+) , è chiamata gruppo di
cattura. Un gruppo che cattura, come suggerisce il nome, cattura una parte della stringa e Django
passa la stringa catturata come argomento alla funzione di visualizzazione.
La sintassi di un gruppo che cattura è (?P<name>pattern) . name definisce il nome del gruppo, che è
anche il nome che Django usa per passare l'argomento alla vista. Il modello definisce quali
caratteri sono abbinati al gruppo.
anno (breve)
[0-9]{2} mese Due numeri, da zero a nove
giorno del mese
Django elabora ogni pattern URL nello stesso ordine in cui sono definiti in urlpatterns . Questo è
importante se più pattern possono corrispondere allo stesso URL. Per esempio:
urlpatterns = [
url(r'blog/(?P<slug>[\w-]+)/$', blog_detail, name='blog-detail'),
url(r'blog/overview/$', blog_overview, name='blog-overview'),
]
https://riptutorial.com/it/home 159
Nel precedente URLconf, il secondo modello non è raggiungibile. Lo schema corrisponderebbe
all'URL /blog/overview/ , ma invece di chiamare la vista blog_overview , l'URL corrisponderà
innanzitutto al modello di blog-detail del blog-detail e chiamerà la vista blog_detail con un
argomento slug='overview' .
Per assicurarsi che l'URL /blog/overview/ sia indirizzato alla vista blog_overview , lo schema deve
essere posizionato sopra il modello dei blog-detail del blog-detail :
urlpatterns = [
url(r'blog/overview/$', blog_overview, name='blog-overview'),
url(r'blog/(?P<slug>[\w-]+)/$', blog_detail, name='blog-detail'),
]
Imposta lo spazio dei nomi URL per un'app riutilizzabile (Django 1.9+)
Configura URLconf della tua app per utilizzare automaticamente uno spazio dei nomi URL
impostando l'attributo app_name :
# In <myapp>/urls.py
from django.conf.urls import url
app_name = 'myapp'
urlpatterns = [
url(r'^$', overview, name='overview'),
]
Questo imposterà lo spazio 'myapp' nomi dell'applicazione su 'myapp' quando è incluso nel root
URLconf>. L'utente della tua app riusabile non deve eseguire alcuna configurazione se non
includere gli URL:
# In <myproject>/urls.py
from django.conf.urls import include, url
urlpatterns = [
url(r'^myapp/', include('myapp.urls')),
]
La tua app riusabile può ora invertire gli URL utilizzando lo spazio dei nomi dell'applicazione:
L'URL rootonf può ancora impostare uno spazio dei namespace dell'istanza con il parametro
namespace :
# In <myproject>/urls.py
urlpatterns = [
url(r'^myapp/', include('myapp.urls', namespace='mynamespace')),
https://riptutorial.com/it/home 160
]
Sia lo spazio dei nomi dell'applicazione che lo spazio dei nomi dell'istanza possono essere
utilizzati per invertire gli URL:
https://riptutorial.com/it/home 161
Capitolo 41: segnali
Parametri
UserProfile ()
La classe UserProfile estende il modello utente predefinito Django .
Class
metodo Il metodo create_profile () viene eseguito ogni volta che viene rilasciato
create_profile () un segnale post_save modello utente Django.
Osservazioni
Ora, i dettagli.
I segnali Django sono un modo per informare la tua app di determinati compiti (come un modello
pre o post-salvataggio o eliminazione) quando ha luogo.
Questi segnali ti consentono di eseguire azioni a tua scelta immediatamente che il segnale viene
rilasciato.
Ad esempio, ogni volta che viene creato un nuovo utente Django, il Modello utente rilascia un
segnale, associando parametri come sender=User consente di indirizzare in modo specifico
l'ascolto dei segnali a un'attività specifica che si verifica, in questo caso, una nuova creazione
utente .
Tuttavia, l'esempio sopra riportato è quello di spiegare in termini pratici un tipico caso d'uso
quando si usano i segnali come un'aggiunta utile.
"Con un grande potere viene una grande responsabilità". Può essere allettante avere segnali
sparsi per l'intera app o progetto solo perché sono fantastici. Bene, non farlo. Perché sono cool
non li rende la soluzione ideale per ogni situazione semplice che viene in mente.
I segnali sono ottimi, come al solito, non tutto. Login / Logout, i segnali sono fantastici. Modelli
chiave che rilascino segnali, come il Modello utente, se disponibili.
La creazione di segnali per ogni modello della tua app può diventare travolgente a un certo punto
https://riptutorial.com/it/home 162
e sconfiggere l'intera idea dell'uso sparring di Django Signals.
• Il segnale si riferisce a un modello particolare e può essere spostato in uno dei metodi di
quel modello, eventualmente chiamato da save() .
• Il segnale può essere sostituito con un metodo di gestione modello personalizzato.
• Il segnale si riferisce a una vista particolare e può essere spostato in quella vista
Examples
Estensione dell'esempio del profilo utente
Questo esempio è uno snippet tratto dal profilo utente Django esteso come un Pro
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='user')
website = models.URLField(default='', blank=True)
bio = models.TextField(default='', blank=True)
class UserProfile(models.Model):
https://riptutorial.com/it/home 163
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'):
...
Utilizzando il pre_save possiamo determinare se un'azione di save sul nostro database riguardava
l'aggiornamento di un oggetto esistente o la creazione di uno nuovo.
@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')
Ora ogni volta che viene eseguita un'azione di save , il segnale pre_save verrà eseguito e
stamperà:
I segnali di Django sono limitati a precise firme di classe al momento della registrazione, e quindi i
modelli sottoclasse non vengono immediatamente registrati sullo stesso segnale.
class Event(models.Model):
user = models.ForeignKey(User)
class StatusChange(Event):
...
class Comment(Event):
...
https://riptutorial.com/it/home 164
def send_activity_notification(sender, instance: Event, raw: bool, **kwargs):
"""
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)
post_save.connect(send_activity_notification, StatusChange)
post_save.connect(send_activity_notification, Comment)
Con Python 3.6, puoi sfruttare alcuni metodi di classe aggiuntivi incorporati in classi per
automatizzare questa associazione.
class Event(models.Model):
@classmethod
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
post_save.connect(send_activity_notification, cls)
https://riptutorial.com/it/home 165
Capitolo 42: set di query
introduzione
Un Queryset è fondamentalmente un elenco di oggetti derivati da un Model , da una raccolta di
query di database.
Examples
Domande semplici su un modello standalone
Ecco un semplice modello che utilizzeremo per eseguire alcune query di test:
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)
Modello semplice name ricerca per stringa specifica (sensibile al maiuscolo / minuscolo):
MyModel.objects.filter(name__contains="ch")
Modello semplice name ricerca per stringa specifica (senza distinzione tra maiuscole e minuscole):
https://riptutorial.com/it/home 166
MyModel.objects.filter(name__icontains="ch")
Dato il modello:
class MyModel(models.Model):
name = models.CharField(max_length=10)
model_num = models.IntegerField()
flag = models.NullBooleanField(default=False)
Possiamo utilizzare oggetti Q per creare condizioni AND , OR nella query di ricerca. Ad esempio,
supponiamo di volere tutti gli oggetti che hanno flag=True OR model_num>15 .
Quanto sopra si traduce in WHERE flag=True OR model_num > 15 modo simile per un AND che si
dovrebbe fare.
Q oggetti Q ci permettono anche di fare NOT query con l'uso di ~ . Diciamo che volevamo ottenere
tutti gli oggetti che hanno flag=False AND model_num!=15 , dovremmo fare:
Se si utilizzano oggetti Q e parametri "normali" in filter() , gli oggetti Q devono prima venire. La
seguente query cerca i modelli con ( flag impostato su True o un numero di modello maggiore di 15
) e un nome che inizia con "H".
Nota: gli oggetti Q possono essere utilizzati con qualsiasi funzione di ricerca che accetta
argomenti di parole chiave come filter , exclude , get . Assicurati che quando usi con get ,
restituirai un solo oggetto o verrà sollevata l'eccezione MultipleObjectsReturned .
Problema
# models.py:
class Library(models.Model):
name = models.CharField(max_length=100)
books = models.ManyToManyField(Book)
https://riptutorial.com/it/home 167
class Book(models.Model):
title = models.CharField(max_length=100)
# views.py
def myview(request):
# Query the database.
libraries = Library.objects.all()
Soluzione
Usa prefetch_related su ManyToManyField se sai che dovrai accedere più tardi a un campo che è 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/it/home 168
# 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
# ...
Tuttavia, una volta eseguito il queryset, i dati recuperati non possono essere modificati senza
colpire nuovamente il database. Il seguente eseguirà query aggiuntive per esempio:
# 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)
Quanto segue può essere ottimizzato usando un oggetto Prefetch , introdotto in Django 1.7:
Problema
I querysets di Django sono valutati in modo pigro. Per esempio:
# 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/it/home 169
# 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
# ...
Il codice sopra fa in modo che django interroghi il database per l'autore di ogni libro. Questo è
inefficiente ed è meglio avere una sola query.
Soluzione
Usa select_related su ForeignKey se sai che dovrai accedere successivamente 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()
# total : 1 query
https://riptutorial.com/it/home 170
Ottieni SQL per il queryset di Django
L'attributo query su queryset fornisce una sintassi equivalente SQL per la query.
Avvertimento:
Questo output dovrebbe essere utilizzato solo a scopo di debug. La query generata
non è specifica per il back-end. Di conseguenza, i parametri non vengono citati
correttamente, lasciandoli vulnerabili all'iniezione SQL e la query potrebbe non essere
nemmeno eseguibile sul back-end del database.
MyModel.objects.first()
MyModel.objects.last()
MyModel.objects.filter(name='simple').first()
MyModel.objects.filter(name='simple').last()
È opportuno utilizzare oggetti F() ogni volta che è necessario fare riferimento al valore di un altro
campo nella query. Di per sé, gli oggetti F() non significano nulla, e non possono e non devono
essere chiamati al di fuori di un queryset. Sono usati per fare riferimento al valore di un campo
sullo stesso queryset.
https://riptutorial.com/it/home 171
SomeModel(models.Model):
...
some_field = models.IntegerField()
... un utente può interrogare oggetti in cui il valore some_field è il doppio del suo id facendo
riferimento al valore del campo id mentre si filtra usando F() come questo:
SomeModel.objects.filter(some_field=F('id') * 2)
F('id') semplicemente riferimento al valore id per quella stessa istanza. Django lo usa per creare
un'istruzione SQL corrispondente. In questo caso qualcosa di simile a questo:
Senza le espressioni F() ciò sarebbe possibile con SQL raw o filtro in Python (che riduce le
prestazioni soprattutto quando ci sono molti oggetti).
Riferimenti:
Nota: questo esempio pubblicato proviene dalla risposta sopra elencata con il consenso di
TinyInstance.
https://riptutorial.com/it/home 172
Capitolo 43: Sicurezza
Examples
Protezione Cross Site Scripting (XSS)
Gli attacchi XSS consistono nell'iniettare codice HTML (o JS) in una pagina. Vedi Che cos'è cross-
site scripting per ulteriori informazioni.
Per evitare questo attacco, per impostazione predefinita, Django sfugge alle stringhe passate
attraverso una variabile di modello.
context = {
'class_name': 'large" style="font-size:4000px',
'paragraph': (
"<script type=\"text/javascript\">alert('hello world!');</script>"),
}
Se hai delle variabili contenenti HTML di cui ti fidi e in realtà vuoi eseguire il rendering, devi dire
esplicitamente che è sicuro:
Se hai un blocco contenente più variabili che sono tutte sicure, puoi disabilitare localmente
l'escape automatico:
{% 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>
Puoi anche contrassegnare una stringa come sicura al di fuori del modello:
context = {
'class_name': 'large" style="font-size:4000px',
'paragraph': mark_safe(
"<script type=\"text/javascript\">alert('hello world!');</script>"),
https://riptutorial.com/it/home 173
}
Alcune utilità Django come format_html restituiscono già stringhe contrassegnate come sicure:
context = {
'var': format_html('<b>{}</b> {}', 'hello', '<i>world!</i>'),
}
Protezione da Clickjacking
Il clickjacking è una tecnica dannosa di ingannare un utente Web per fare clic su
qualcosa di diverso da ciò che l'utente percepisce su cui sta facendo clic. Per saperne
di più
# settings.py
MIDDLEWARE_CLASSES = [
...
'django.middleware.clickjacking.XFrameOptionsMiddleware',
...
]
Questo middleware imposta l'intestazione 'X-Frame-Options' su tutte le tue risposte, a meno che
non sia esplicitamente esentato o impostato (non sovrascritto se già impostato nella risposta). Di
default è impostato su "SAMEORIGIN". Per cambiare questo, usa l'impostazione X_FRAME_OPTIONS :
X_FRAME_OPTIONS = 'DENY'
@xframe_options_sameorigin
def my_view(request, *args, **kwargs):
https://riptutorial.com/it/home 174
"""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 falsificazione della richiesta tra siti, anche nota come attacco con un clic o sessione
in corso e abbreviata come CSRF o XSRF, è un tipo di exploit dannoso di un sito Web
in cui vengono trasmessi comandi non autorizzati da un utente ritenuto affidabile dal
sito Web. Per saperne di più
Per abilitare la protezione CSRF, aggiungi CsrfViewMiddleware alle tue classi middleware. Questo
middleware è abilitato per impostazione predefinita.
# settings.py
MIDDLEWARE_CLASSES = [
...
'django.middleware.csrf.CsrfViewMiddleware',
...
]
Questo middleware imposterà un token in un cookie sulla risposta in uscita. Ogni volta che una
richiesta in entrata utilizza un metodo non sicuro (qualsiasi metodo tranne GET , HEAD , OPTIONS e
TRACE ), il cookie deve corrispondere a un token che viene inviato come dati del modulo
csrfmiddlewaretoken o come intestazione X-CsrfToken . Ciò garantisce che il client che avvia la
richiesta sia anche il proprietario del cookie e, per estensione, la sessione (autenticata).
Se viene eseguita una richiesta su HTTPS , il controllo referrer rigoroso è abilitato. Se l'intestazione
HTTP_REFERER non corrisponde all'host della richiesta corrente o di un host in CSRF_TRUSTED_ORIGINS (
novità in 1.9 ), la richiesta viene respinta.
I moduli che utilizzano il metodo POST devono includere il token CSRF nel modello. Il tag del
modello {% csrf_token %} un campo nascosto e garantisce che il cookie sia impostato sulla
risposta:
<form method='POST'>
{% csrf_token %}
...
</form>
Le singole viste che non sono vulnerabili agli attacchi CSRF possono essere rese esenti
utilizzando il decoratore @csrf_exempt :
https://riptutorial.com/it/home 175
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def my_view(request, *args, **kwargs):
"""Allows unsafe methods without CSRF protection"""
return HttpResponse(...)
Sebbene non sia raccomandato, è possibile disabilitare CsrfViewMiddleware se molte delle viste non
sono vulnerabili agli attacchi CSRF. In questo caso puoi utilizzare il decoratore @csrf_protect per
proteggere le singole visualizzazioni:
@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/it/home 176
Capitolo 44: Struttura del progetto
Examples
Deposito> Progetto> Sito / Conf
Per un progetto Django con requirements e deployment tools sotto il controllo del codice sorgente.
Questo esempio si basa su concetti tratti dai due scoop di Django . Hanno pubblicato un modello :
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
Qui le apps e le cartelle conf contengono rispettivamente user created applications e la core
configuration folder per il progetto.
static cartelle static e di templates nella directory del project contengono rispettivamente file
statici e file html markup che vengono utilizzati globalmente in tutto il progetto.
https://riptutorial.com/it/home 177
E tutte le cartelle di app blog , accounts e search possono anche (principalmente) contenere cartelle
static e templates .
static cartella static e di templates nelle app potrebbe anche contenere una cartella con il nome
dell'app ex. blog questa è una convenzione usata per prevenire l'inquinamento dello spazio dei
nomi, quindi facciamo riferimento ai file come /blog/base.html piuttosto che /base.html che fornisce
maggiore chiarezza sul file a cui stiamo facendo riferimento e mantiene lo spazio dei nomi.
Esempio: la cartella dei templates all'interno del blog e delle applicazioni di search contiene un file
con nome base.html e quando si fa riferimento al file nelle views l'applicazione viene confusa in
quale file eseguire il rendering.
(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/it/home 178
Capitolo 45: Tag e filtri modello
Examples
Filtri personalizzati
Filtri consente di applicare una funzione a una variabile. Questa funzione può richiedere 0 o 1
argomento. Ecco la sintassi:
{{ 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
Tag semplici
https://riptutorial.com/it/home 179
Il modo più semplice per definire un tag modello personalizzato è utilizzare un simple_tag . Questi
sono molto semplici da configurare. Il nome della funzione sarà il nome del tag (sebbene sia
possibile sovrascriverlo) e gli argomenti saranno token ("parole" separati da spazi, ad eccezione
degli spazi racchiusi tra virgolette). Supporta anche argomenti di parole chiave.
Diciamo che vogliamo questo tag molto inutile per renderizzare in questo modo:
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 consente di contrassegnare <br/> come HTML sicuro, ma non il contenuto delle
outputs .
A volte ciò che vuoi fare è troppo complesso per un filter o un semplice simple_tag . Fow questo
è necessario creare una funzione di compilazione e un renderer.
Esempio Descrizione
https://riptutorial.com/it/home 180
Esempio Descrizione
modello
Il motivo per cui non possiamo farlo con un semplice tag è che plural e capfirst non sono né
variabili né stringhe, sono "parole chiave". Ovviamente potremmo decidere di passarli come
stringhe 'plural' e 'capfirst' , ma potrebbe entrare in conflitto con i campi con questi nomi. {%
verbose_name obj 'plural' %} significa "nome dettagliato plurale di obj " o "nome dettagliato di
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:
https://riptutorial.com/it/home 181
raise TemplateSyntaxError((
"'{}' tag only accept one field name at most. {} is the second "
"field name encountered."
).format(tag_name, bit)
field_name = parser.compile_filter(bit)
E ora il renderer:
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/it/home 182
Capitolo 46: templating
Examples
variabili
È possibile accedere alle variabili fornite nel contesto della vista utilizzando la notazione doppia
coppia:
class UserView(TemplateView):
""" Supply the request user object to the template """
template_name = "user.html"
In user.html :
Le variabili del modello non possono accedere ai metodi che accettano argomenti.
{% 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 %}
Si accede agli URL utilizzando il formato {% url 'name' %} , dove i nomi corrispondono ai nomi nel
tuo urls.py
https://riptutorial.com/it/home 183
{% url next %} : gli URL possono essere variabili
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()
È possibile utilizzare un modello in una vista basata sulla funzione come segue:
def view(request):
return render(request, "template.html")
https://riptutorial.com/it/home 184
Se si desidera utilizzare le variabili del modello, è possibile farlo come segue:
def view(request):
context = {"var1": True, "var2": "foo"}
return render(request, "template.html", context=context)
Quindi, in template.html , puoi fare riferimento alle tue variabili in questo modo:
<html>
{% if var1 %}
<h1>{{ var2 }}</h1>
{% endif %}
</html>
Filtri modello
Il sistema di template Django ha tag e filtri integrati, che sono funzioni all'interno del template per
rendere il contenuto in un modo specifico. È possibile specificare più filtri con pipe e i filtri possono
avere argomenti, proprio come nella sintassi delle variabili.
Per aggiungere i tuoi filtri modello, crea una cartella denominata templatetags all'interno della
cartella dell'app. Quindi aggiungi un __init__.py e il file il tuo file che conterrà i filtri:
#/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%}
Trucchi
https://riptutorial.com/it/home 185
Anche se all'inizio i filtri sembrano semplici, consente di fare alcune cose interessanti:
Quando un oggetto viene esposto al contesto del modello, sono disponibili i suoi metodi senza
argomenti. Questo è utile quando queste funzioni sono "getter". Ma può essere pericoloso se
questi metodi alterano alcuni dati o hanno alcuni effetti collaterali. Anche se probabilmente ti fidi
dello scrittore di modelli, potrebbe non essere a conoscenza degli effetti collaterali di una funzione
o pensare di chiamare l'attributo sbagliato per errore.
class Foobar(models.Model):
points_credit = models.IntegerField()
Ciò incrementerà il numero di punti ogni volta che viene chiamato il modello. E potresti anche non
accorgertene.
Per evitare ciò, è necessario impostare l'attributo alters_data su True per i metodi con effetti
collaterali. Ciò renderà impossibile chiamarli da un modello.
sommario
• {% extends%} : dichiara il modello fornito come argomento come padre del modello
corrente. Utilizzo: {% extends 'parent_template.html' %} .
https://riptutorial.com/it/home 186
• {% block%} {% endblock%} : questo è usato per definire sezioni nei tuoi template, così che
se un altro template estende questo, sarà in grado di sostituire qualunque codice html sia
stato scritto al suo interno. I blocchi sono identificati dal loro nome. Utilizzo: {% block content
%} <html_code> {% endblock %} .
• {% include%} : questo inserirà un modello all'interno di quello corrente. Tieni presente che il
modello incluso riceverà il contesto della richiesta e puoi dargli anche variabili
personalizzate. Utilizzo di base: {% include 'template_name.html' %} , utilizzo con variabili: {%
include 'template_name.html' with variable='value' variable2=8 %}
Guida
Supponiamo che tu stia costruendo il tuo codice lato front-end con layout comuni per tutto il codice
e non vuoi ripetere il codice per ogni modello. Django ti offre tag costruiti per farlo.
Supponiamo di avere un sito web di blog con 3 modelli che condividono lo stesso layout:
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 %}
Qui abbiamo esteso il layout di base in modo che il suo layout HTML sia ora disponibile nel
blog.html blog.html. Il concetto di { % block %} è l'ereditarietà del modello che ti consente di creare
un modello di base "scheletro" che contiene tutti gli elementi comuni del tuo sito e definisce i
blocchi che i modelli figlio possono sovrascrivere.
3) Supponiamo che tutti i tuoi 3 modelli abbiano anche lo stesso div HTML che definisce alcuni
https://riptutorial.com/it/home 187
post popolari. Invece di scrivere 3 volte, crea un nuovo template 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/it/home 188
Capitolo 47: Test unitario
Examples
Test: un esempio completo
Questo presuppone che tu abbia letto la documentazione sull'avvio di un nuovo progetto Django.
Supponiamo che l'app principale del progetto sia denominata td (abbreviazione di testing driven).
Per creare il tuo primo test, crea un file denominato test_view.py e copia incolla il seguente
contenuto in esso.
class ViewTest(TestCase):
def test_hello(self):
c = Client()
resp = c.get('/hello/')
self.assertEqual(resp.status_code, 200)
./manage.py test
Perché succede? Perché non abbiamo definito una visione per questo! Facciamolo. Crea un file
chiamato views.py e inserisci il seguente codice
urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'^hello/', views.hello),
....
]
https://riptutorial.com/it/home 189
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
Esempi di prova
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/it/home 190
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):
...
Alcuni punti
Infine, in caso di dubbio, scrivi un test. I cambiamenti del comportamento banale vengono catturati
prestando attenzione ai dettagli e lunghi pezzi di codice dimenticati non finiscono per causare
problemi inutili.
tl; dr : crea una classe base che definisce due oggetti utente (ad esempio user e another_user ).
Crea gli altri tuoi modelli e definisci tre istanze del Client .
Ora accedi a tutti i tuoi URL pubblici e privati da questi tre oggetti client e imposta la risposta che ti
aspetti. Di seguito ho mostrato la strategia per un oggetto Book che può essere private (di
proprietà di pochi utenti privilegiati) o public (visibile a tutti).
class BaseViewTestCase(TestCase):
@classmethod
def setUpClass(cls):
super(BaseViewTestCase, cls).setUpClass()
cls.client = Client()
cls.another_client = Client()
cls.unlogged_client = Client()
https://riptutorial.com/it/home 191
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)})
def test_user_sees_book(self):
https://riptutorial.com/it/home 192
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)
Il database e i test
Django utilizza impostazioni di database speciali durante i test in modo che i test possano
utilizzare normalmente il database, ma per impostazione predefinita vengono eseguiti su un
database vuoto. Le modifiche al database in un test non saranno viste da un altro. Ad esempio,
entrambi i seguenti test supereranno:
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)
infissi
Se si desidera disporre di oggetti di database utilizzati da più test, crearli nel metodo setUp del
caso di test. Inoltre, se hai definito fixtures nel tuo progetto django, possono essere inclusi in
questo modo:
class MyTest(TestCase):
fixtures = ["fixture1.json", "fixture2.json"]
Per impostazione predefinita, django è alla ricerca di fixture nella directory fixtures in ogni app.
Ulteriori directory possono essere impostate utilizzando l'impostazione FIXTURE_DIRS :
# myapp/settings.py
FIXTURE_DIRS = [
os.path.join(BASE_DIR, 'path', 'to', 'directory'),
]
https://riptutorial.com/it/home 193
# 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"
}
},
]
Per accelerare le esecuzioni dei test, è possibile indicare al comando di gestione di riutilizzare il
database di test (e impedire che venga creato prima e eliminato dopo ogni esecuzione di prova).
Questo può essere fatto usando il flag keepdb (o shorthand -k ) in questo modo:
È possibile limitare i test eseguiti dal manage.py test specificando quali moduli devono essere
rilevati dal test runner:
# If you split the tests file into a module with several tests files for an app
$ python manage.py test app1.tests.test_models
Se vuoi eseguire una serie di test, puoi passare uno schema di nomi di file. Ad esempio, potresti
voler eseguire solo test che coinvolgono i tuoi modelli:
https://riptutorial.com/it/home 194
$ python manage.py test -p test_models*
Creating test database for alias 'default'...
.................................................
----------------------------------------------------------------------
Ran 115 tests in 3.869s
OK
Infine, è possibile interrompere la suite di test al primo errore, usando --failfast . Questo
argomento consente di ottenere rapidamente il potenziale errore riscontrato nella suite:
FAILED (failures=1)
FAILED (failures=1)
https://riptutorial.com/it/home 195
Capitolo 48: Transazioni di database
Examples
Transazioni atomiche
Problema
Per impostazione predefinita, Django commette immediatamente modifiche al database. Quando
si verificano eccezioni durante una serie di commit, questo può lasciare il tuo database in uno
stato indesiderato:
Soluzione
Il modulo django.db.transaction consente di combinare più modifiche al database in una
transazione atomica :
[a] una serie di operazioni di database tali che si verificano tutte o non si verifica nulla.
Applicato allo scenario sopra, questo può essere applicato come decoratore :
@transaction.atomic
def create_category(name, products):
https://riptutorial.com/it/home 196
category = Category.objects.create(name=name)
product_api.add_products_to_category(category, products)
activate_category(category)
Ora, se si verifica un'eccezione in qualsiasi fase della transazione, non verrà eseguito il commit
delle modifiche al database.
https://riptutorial.com/it/home 197
Capitolo 49: Uso di Redis con Django -
Backend di cache
Osservazioni
Utilizzando django-redis-cache o django-redis sono entrambe soluzioni efficaci per la
memorizzazione di tutti gli elementi memorizzati nella cache. Mentre è certamente possibile
impostare Redis direttamente come SESSION_ENGINE , una strategia efficace consiste nell'impostare
la cache (come sopra) e dichiarare la cache predefinita come SESSION_ENGINE . Mentre questo è
veramente l'argomento di un altro articolo di documentazione, la sua rilevanza porta all'inclusione.
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
Examples
Utilizzando django-redis-cache
Una potenziale implementazione di Redis come utility di caching del back-end è il pacchetto
django-redis-cache .
Modifica il tuo settings.py per includere un oggetto CACHES (vedi la documentazione di Django sulla
cache ).
CACHES = {
'default': {
'BACKEND': 'redis_cache.RedisCache',
'LOCATION': 'localhost:6379',
'OPTIONS': {
'DB': 0,
}
}
}
Usando il django-redis
Una potenziale implementazione di Redis come utility di caching del back-end è il pacchetto
django-redis .
https://riptutorial.com/it/home 198
$ pip install django-redis
Modifica il tuo settings.py per includere un oggetto CACHES (vedi la documentazione di Django sulla
cache ).
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/it/home 199
Capitolo 50: Viste basate sulla classe
Osservazioni
Quando si usa CBV, spesso abbiamo bisogno di sapere esattamente quali metodi possiamo
sovrascrivere per ogni classe generica. Questa pagina della documentazione di django elenca
tutte le classi generiche con tutti i loro metodi appiattiti e gli attributi di classe che possiamo usare.
Inoltre, il sito Web Classy Class Based View fornisce le stesse informazioni con una bella
interfaccia interattiva.
Examples
Viste basate sulla classe
Una pagina statica sulla pagina potrebbe non avere nulla di speciale, tranne il modello usato. Usa
un TemplateView ! Tutto quello che devi fare è impostare un nome per il modello. Lavoro fatto. Il
prossimo.
views.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'),
]
Si noti come non usiamo direttamente AboutView . Questo perché ci si aspetta un callable e questo
è esattamente ciò che as_view() restituisce.
Dati contestuali
https://riptutorial.com/it/home 200
A volte, il tuo modello ha bisogno di un po 'più di informazioni. Ad esempio, vorremmo avere
l'utente nell'intestazione della pagina, con un link al suo profilo accanto al link di disconnessione.
In questi casi, utilizzare il metodo get_context_data .
views.py
class BookView(DetailView):
template_name = "book.html"
book.html
<h3>Active publishers</h3>
<ul>
{% for publisher in publishers %}
<li>{{ publisher.name }}</li>
{% endfor %}
</ul>
Elenco e dettagli
Le viste del modello vanno bene per la pagina statica e potresti usarle per tutto con
get_context_data ma sarebbe a malapena migliore dell'uso della funzione come viste.
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/it/home 201
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
Questo è tutto ciò che serve per generare una vista che elenchi tutti gli oggetti di un modello e le
viste di un oggetto singolare. L'elenco è persino impaginato. Puoi fornire template_name se vuoi
qualcosa di specifico. Per impostazione predefinita, viene generato dal nome del modello.
Il contesto è popolato con l'elenco di oggetti sotto il nome due, object_list e una seconda build
dal nome del modello, qui pokemon_list . Se hai impaginato la lista, devi occuparti anche del link
precedente e successivo. L'oggetto Paginator può essere d'aiuto, è disponibile anche nei dati di
contesto.
Come in precedenza, il contesto viene popolato con l'oggetto del modello sotto l' object nome e il
pokemon , il secondo derivato dal nome del modello.
app / urls.py
from django.conf.urls import url
https://riptutorial.com/it/home 202
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'),
]
In questo snippet, l'url per la vista dettagliata viene creato utilizzando la chiave primaria. È anche
possibile usare una lumaca come argomento. Questo dà un URL più bello che è più facile da
ricordare. Tuttavia richiede la presenza di un campo chiamato slug nel tuo modello.
Per l'impaginazione, utilizza una pagina per ottenere parametri o inserire una pagina direttamente
nell'URL.
Scrivere una vista per creare oggetti può essere piuttosto noioso. Devi visualizzare un modulo,
devi convalidarlo, devi salvare l'oggetto o restituire il modulo con un errore. A meno che non si usi
una delle viste di modifica generiche .
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')
CreateView e UpdateView hanno due attributi, model e fields obbligatori. Per impostazione
predefinita, entrambi utilizzano un nome di modello basato sul nome del modello con suffisso
"_form". Puoi modificare solo il suffisso con l'attributo template_name_suffix. DeleteView mostra
un messaggio di conferma prima di eliminare l'oggetto.
https://riptutorial.com/it/home 203
Sia UpdateView che DeleteView devono recuperare l'oggetto. Usano lo stesso metodo di DetailView ,
estraendo la variabile dall'URL e facendo corrispondere i campi dell'oggetto.
form contiene il modulo con tutti i campi necessari. Qui, verrà visualizzato con un paragrafo per
ogni campo a causa di as_p .
Il tag csrf_token è richiesto a causa della protezione di django contro la falsificazione delle
richieste. L'azione attributo è lasciata vuota poiché l'url che visualizza il modulo è uguale a quello
che gestisce la cancellazione / salvataggio.
Rimangono due problemi con il modello, se si utilizza lo stesso esempio con l'elenco e l'esempio
di dettaglio. In primo luogo, creare e aggiornare si lamenterà di un URL di reindirizzamento
mancante. Questo può essere risolto aggiungendo un get_absolute_url al modello pokemon. Il
secondo problema è la conferma dell'eliminazione che non mostra informazioni significative. Per
risolvere questo problema, la soluzione più semplice è aggiungere una rappresentazione di
stringa.
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):
https://riptutorial.com/it/home 204
name = models.CharField(max_length=24)
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
Esempio 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 le viste generiche basate sulla classe, è molto semplice e facile creare le viste CRUD dai
nostri modelli. Spesso, l'amministratore di Django integrato non è abbastanza o non è preferito e
abbiamo bisogno di lanciare le nostre visualizzazioni CRUD. I CBV possono essere molto utili in
questi casi.
Esempio:
class CampaignCreateView(CreateView):
model = Campaign
fields = ('title', 'description')
success_url = "/campaigns/list"
https://riptutorial.com/it/home 205
Una volta che il successo della creazione, l'utente viene reindirizzato a success_url . Possiamo
anche definire un metodo get_success_url e utilizzare reverse o reverse_lazy per ottenere l'URL di
successo.
Ora, dobbiamo creare un modello per questa vista. Il modello deve essere denominato nel formato
<app name>/<model name>_form.html . Il nome del modello deve essere in maiuscolo. Ad esempio, se
il mio nome dell'app è dashboard , per la vista create sopra devo creare un modello denominato
dashboard/campaign_form.html .
Nel modello, una variabile form contiene il modulo. Ecco un codice di esempio per il modello:
Se visitiamo l'URL, dovremmo vedere un modulo con i campi che abbiamo scelto. Quando
inviamo, cercherà di creare una nuova istanza del modello con i dati e salvarla. In caso di
successo, l'utente verrà reindirizzato all'URL di successo. In caso di errori, il modulo verrà
visualizzato di nuovo con i messaggi di errore.
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():
https://riptutorial.com/it/home 206
self.form_save(post_form)
if comment_form.is_valid():
self.form_save(comment_form)
return self.render_to_response(context)
https://riptutorial.com/it/home 207
Capitolo 51: Visualizzazioni
introduzione
Una funzione di visualizzazione, o vista in breve, è semplicemente una funzione Python che
accetta una richiesta Web e restituisce una risposta Web. -Django Documentazione-
Examples
[Introduzione] Vista semplice (Hello World Equivalent)
Creiamo una vista molto semplice per rispondere a un modello "Hello World" in 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/it/home 208
Capitolo 52: Visualizzazioni generiche
introduzione
Le viste generiche sono viste che eseguono una determinata azione predefinita, come la
creazione, la modifica o l'eliminazione di oggetti o semplicemente la visualizzazione di un modello.
Le viste generiche devono essere distinte dalle viste funzionali, che sono sempre scritte a mano
per eseguire le attività richieste. In breve, si può dire che le viste generiche devono essere
configurate, mentre le viste funzionali devono essere programmate.
Le viste generiche possono risparmiare molto tempo, specialmente quando si devono eseguire
molte attività standardizzate.
Osservazioni
Questi esempi mostrano che le viste generiche generalmente semplificano le attività
standardizzate. Invece di programmare tutto da capo, puoi configurare ciò che altre persone
hanno già programmato per te. Questo ha senso in molte situazioni, in quanto consente di
concentrarsi maggiormente sulla progettazione dei progetti piuttosto che sui processi in
background.
Quindi, dovresti sempre usarli? No. Hanno senso solo se i tuoi compiti sono abbastanza
standardizzati (caricamento, modifica, eliminazione di oggetti) e più ripetitivi sono i tuoi compiti.
L'utilizzo di una vista generica specifica solo una volta e quindi l'annullamento di tutti i suoi metodi
per eseguire attività molto specifiche potrebbe non avere senso. Potresti star meglio con una vista
funzionale qui.
Tuttavia, se disponi di molte viste che richiedono questa funzionalità o se le tue attività
corrispondono esattamente alle attività definite di una vista generica specifica, le visualizzazioni
generiche sono esattamente ciò di cui hai bisogno per semplificarti la vita.
Examples
Esempio minimo: viste funzionali e generiche
Esempio per una vista funzionale per creare un oggetto. Escludendo i commenti e le righe vuote,
abbiamo bisogno di 15 righe di codice:
# imports
from django.shortcuts import render_to_response
from django.http import HttpResponseRedirect
https://riptutorial.com/it/home 209
# view functioon
def create_object(request):
Esempio di una 'vista generica basata su classi' per eseguire la stessa operazione. Abbiamo solo
bisogno di 7 linee di codice per ottenere lo stesso compito:
class CreateObject(CreateView):
model = SampleObject
form_class = SampleObjectForm
success_url = 'url_to_redirect_to'
L'esempio precedente funziona solo se le tue attività sono interamente attività standard. Ad
esempio, non aggiungi qui un contesto extra.
def create_object(request):
page_title = 'My Page Title'
# ...
Questo è più difficile (o: controtestivo) da ottenere con visualizzazioni generiche. Poiché sono
basati su classi, devi eseguire l'override di uno o più metodi della classe per ottenere il risultato
desiderato. Nel nostro esempio, abbiamo bisogno di sovrascrivere il metodo get_context_data
della classe in questo modo:
https://riptutorial.com/it/home 210
class CreateObject(CreateView):
model = SampleObject
form_class = SampleObjectForm
success_url = 'url_to_redirect_to'
Qui, abbiamo bisogno di quattro righe aggiuntive da codificare invece di una sola, almeno per la
prima variabile di contesto che vogliamo aggiungere.
Il vero potere delle viste generiche si sviluppa quando le combini con Mixins. Un mixin è solo
un'altra classe definita da te i cui metodi possono essere ereditati dalla tua classe di
visualizzazione.
Supponi di volere che ogni vista mostri la variabile aggiuntiva 'page_title' nel modello. Invece di
sovrascrivere il metodo get_context_data ogni volta che definisci la vista, crei un mixin con questo
metodo e consenti alle tue opinioni di ereditare da questo mix. Sembra più complicato di quanto
non sia in realtà:
# Your Mixin
class CustomMixin(object):
La bellezza di questo è che il tuo codice diventa molto più strutturato di quanto non avvenga per le
visualizzazioni funzionali. La tua intera logica dietro compiti specifici si trova in un posto e solo in
un posto. Inoltre, risparmierai enormi quantità di tempo, specialmente quando hai molte viste che
svolgono sempre le stesse attività, tranne che con oggetti diversi
https://riptutorial.com/it/home 211
Leggi Visualizzazioni generiche online: https://riptutorial.com/it/django/topic/9452/visualizzazioni-
generiche
https://riptutorial.com/it/home 212
Capitolo 53: Widget del modulo
Examples
Semplice widget di inserimento del testo
L'esempio più semplice di widget è l'inserimento di testo personalizzato. Ad esempio, per creare
un <input type="tel"> , devi sottoclasse TextInput e imposta input_type su 'tel' .
class PhoneInput(TextInput):
input_type = 'tel'
Widget composito
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/it/home 213
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/it/home 214
Titoli di coda
S.
Capitoli Contributors
No
Aggregazioni di
2 Ian Clark, John Moutafis, ravigadila
modelli
ArrayField - un campo
4 Antoine Pinsard, e4c5, noɥʇʎԀʎzɐɹƆ
specifico PostgreSQL
Associazione di
stringhe alle stringhe
5 con HStoreField: un noɥʇʎԀʎzɐɹƆ
campo specifico
PostgreSQL
Attività asincrone
6 iankit, Mevin Babu
(sedano)
Backend di
7 knbk, Rahul Gupta
autenticazione
Come resettare le
9 Cristus Cleetus
migrazioni di django
https://riptutorial.com/it/home 215
Configurazione del Ahmad Anwar, Antoine Pinsard, Evans Murithi, Kid Binary,
11
database knbk, lxer, Majid, Peter Mortensen
13 Debug Antoine Pinsard, Ashutosh, e4c5, Kid Binary, knbk, Sayse, Udi
Django Rest
17 The Brewmaster
Framework
Esecuzione di Celery
19 RéÑjïth, sebb
con Supervisor
22 formsets naveen.panwar
Gestori e Queryys
24 abidibo, knbk, sudshekhar, Trivial
personalizzati
Integrazione continua
26 pnovotnak
con Jenkins
https://riptutorial.com/it/home 216
JSONField - un
Antoine Pinsard, Daniil Ryzhkov, Matthew Schinckel, noɥʇʎԀ
28 campo specifico
ʎzɐɹƆ, Omar Shehata, techydesigner
PostgreSQL
RangeFields: un
gruppo di campi
35 Antoine Pinsard, noɥʇʎԀʎzɐɹƆ
specifici di
PostgreSQL
Riferimento del Burhan Khalid, Husain Basrawala, knbk, Matt Seymour, Rod
38
campo del modello Xavier, scriptmonster, techydesigner, The_Cthulhu_Kid
https://riptutorial.com/it/home 217
Justin, knbk, Louis Barranqueiro, Maxime Lorant,
MicroPyramid, nima, ravigadila, Sanyam Khurana, The
Brewmaster
Transazioni di
48 Ian Clark
database
Visualizzazioni
52 nikolas-berlin
generiche
https://riptutorial.com/it/home 218