Django
[TOC]
Ci sono un elevato numero di funzioni che possono essere usate per facilitare e modularizzare compiti “standard”.
Gle elementi MVVC sono gestiti in 3 file separati:
models.py
-> i modelliviews.py
-> le visteurls.py
-> i controllerIl componente Model dell'applicazione è implementato direttamente come collezione di classi Python, che poi andranno a rappresentare le tabelle del database. Il codice SQL per creare lo schema viene generato automaticamente da Django quando si esegue il deployment del modello.
Si crea un n 'virtual object database' accessibile e usabile direttamente attraverso linguaggio di programmazione ad oggetti.
Si usano template per generare diversi tipi di output, e accesso ai dati del model attraverso API Python.
il file urls.py
serve per mappare gli URL richiesti sulle view che restituiscono le pagine richieste. Si possono usare
funzioni built-in e espressioni regolari per mappare gli URL richiesti.
Favorire lo sviluppo rapido dell'applicazione, scrivendo meno codice senza ripeterlo, e interagendo con il DB principalmente con codice SQL autogenerato.
Limitare al massimo le interazioni con il DB. I dati sono accessibii da ogni modulo e i join vengono creati automaticamente dallo strato di interfacciamento software. Rimane possibile scrivere direttamente codice SQL, ma solo quando è veramente necessario.
URL puliti e riutilizzabili: evitare le estensioni negli URL.
Lo scopo è separare la logica dalla presentazione. Si evita la ridondanza, si è più protetti contro codice malevolo e si facilita l'estendibilità per il futuro.
Nessun bisogno di creare nuove classi, sono essenzialmente realizzate attraverso delle funzioni Python. Si usano oggetti che incapsulano le richieste HTTP.
mysite (dir top-level)
|_ manage.py
|_ mysite (package Python)
| |_ __init__.py
| |_ settings.py
| |_ urls.py
|_ app1 (package Python)
|_ __init__.py
|_ models.py
|_ vies.py
|_ ...
Un singolo progetto Django può essere spezzato in diverse sotto-applicazioni (ognuna sarà un package separato, come app1
),
che avrà tutti i suoi componenti MVC (model, views, urls). Applicazioni diverse possono interagire importado i package.
manage.py
script per automatizzare le operazioni di Django.
mysite/mysite
cartella della applicazione principale (omonima )del progetto
settings.py
impostazioni per il funzionamento dell'applicazione, tra cui: definizione dei path dell'applicazione e configurazione di
accesso a DB
urls.py
configurazione degli URL per il progetto (livello root).
Creo il progetto direttamente da pycharm, oppure con il comando:
django-admin.py startproject mysite
Per usare MySQL devo prima creare il DB:
$ mysql --user=root -p
mysql> CREATE DATABASE djangodb;
mysql> CREATE USER 'djangouser'@'localhost' IDENTIFIED BY 'rue1iep5';
mysql> GRANT ALL PRIVILEGES ON djangodb.* TO 'djangouser'@'localhost' WITH GRANT OPTION;
mysql> show databases;
Devo aggiungere la connessione al DB creato nel file settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'djangodb',
'USER': 'djangouser',
'PASSWORD': 'rue1iep5',
'HOST': '',
'PORT': '',
}
}
Per PostgreSQL:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'djangodb',
'USER': 'djangouser',
'PASSWORD': 'rue1iep5',
'HOST': '',
'PORT': '',
}
}
All'interno del progetto creo una nuova app
$ python manage.py startapp polls
Creo i modelli all'interno di polls/models.py
from django.db import models
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
def __unicode__(self):
return self.question_text
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
class Choice(models.Model):
question = models.ForeignKey(Question)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
def __unicode__(self):
return self.choice_text
Aggiungo l'app alla lista delle app disponibili in mysite/settings.py
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'polls',
)
Ora tutto è pronto per sfruttare le comodità di django:
sincronizziamo il D
$ python manage.py makemigrations polls
creiamo le tabelle
$ python manage.py migrate
SQL generato (mostra il codice SQL generato)
$ python manage.py sqlmigrate polls 0001
Controllo
$ python manage.py check
Python shell
$ python manage.py shell
Le migrazioni sono uno strumento estremamente potente che permette modifiche in corso d'opera senza perdere i dati già inseriti. I passaggi per applicare le modifiche consistono in:
python manage.py makemigrations
python manage.py migrate
A questo punto il model mette a disposizione una serie di metodi e utility per interrogare il DB, ad esempio
Statement | descrizione |
---|---|
q = Question(question_text="What's new?", pub_date=timezone.now()) | crea un nuovo oggetto Question |
q.save() | salva sul DB (sincronizzazione esplicita) |
Question.objects.all() | select di tutti gli elementi della tabella Question (se non è definito __unicode__ (__str__ in python 3) da una rappresentazione inutile,come quando non si fa l'override di toString() in JAVA) |
Question.objects.get(id=1) | con get si possono recuperare singoli oggetti come una WHERE sugli attributi della classe |
Question.objects.filter(<predicato> ) | ritorna la lista degli oggetti filtrati sulla base del predicato |
Question.objects.exclude(<predicato> ) | ritorna la lista degli oggetti filtrati che non soddisfano il predicato di filtraggio |
q.choice_set.all() | fa il join tra la tabella Question e la tabella Choice (relazione one-to-many) |
c = q.choice_set.create(choice_text='Just hacking again', votes=0) | crea l'oggetto choice, lo aggiunge al set della question q (fa la insert) e lo ritorna |
q.choice_set.count() | fa il count delle Choice associate a una Question |
Choice.objects.filter(question__pub_date__year = current_year) |
I predicati di filtraggio sono nella forma <nomeCampo>__criterio=<valore>
. Alcuni possibili predicati di filtraggio sono:
Criterio | Esempio |
---|---|
Sottocampi | __year, __month |
Substring | __startswith, __contains |
Operatori di confronto | __gte, __gt |
Uguaglianza | __exact |
Viene generata automaticamente da Django ed è pensata per gli amministratori dei siti e i content publisher. Permette i gestire tutti i modelli e i dati in essi contenuti. L'interfaccia è raggiungibile a
127.0.0.1:8000/admin
La prima cosa da fare è creare un superuser Django:
$ python manage.py createsuperuser
Inserire le info e rilanciare il server.
Per aggiungere un' app alla pagine admin modifico il file <nome_app>/admin.py
from .models import Question
admin.site.register(Question)
Ora basta ricaricare la pagina admin
Si personalizza modificando il file admin.py
dell'applicazione, creadno una classe che descriva come vogliamo personalizzare l'interfaccia del modello.
#non funzia, capire perchè
class QuestionAdmin(admin.ModelAdmin):
fields = ['pub_date', 'question']
admin.site.register(Question, QuestionAdmin)
Si possono raggruppare in sezioni i campi (comodo quando se ne hanno tanti)
class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
(None, {'fields': ['question_text']}),
('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
]
admin.site.register(Question, QuestionAdmin)
E' possibile aggiungere anche le info prese dalla tabella che andrebbe in join con Question, ovvero Choice, in modo da avere tutto inline, anche in inserimento.
class ChoiceInline(admin.StackedInline):
model = Choice
# number of choices for each question
extra = 3
Ulteriori customizzazioni possono essere fatte ad esempio per mostrare info aggiuntive e non solo quelle del metodo __unicode__
che è ciò che viene fatto di default.
class QuestionAdmin(admin.ModelAdmin):
# …
inlines = [ChoiceInline]
list_display = ('question_text', 'pub_date', 'was_published_recently')
All'interno di list_display
si possono mettere sia attributi del modello che risultati di metodi. Per quanto riguarda i risultati di metodi, non è consentito l'ordinamento, ma si può aggiungere nel seguento modo:
class Question(models.Model):
#...
# enable ordering
was_published_recently.admin_order_field = 'pub_date'
# show a symbol instead of True
was_published_recently.boolean = True
# deine the column name
was_published_recently.short_description = 'Published recently?'
Per specificare un opzione di filtraggio, aggiuntere al file admin.py
list_filter = ['pub_date'] #in class QuestionAdmin
Per le funzioni di ricerca invece, sempre in class QuestionAdmin
:
search_fields = ['question_text']
# non funzia
date_hierarchy = 'pub_date'
(modifichiamo la pagina admin)
La prima cosa da fare è aggiungere il path delle cartella template, in modo che django sappia dove prendere i template. Modificare il file settings.py
TEMPLATES = [
{
'BACKEND': \
'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')], #nuova riga
'APP_DIRS': True,
….
}
creare una cartella in template di nome admin e copiarci il template base_site.html
che si trova in :
/usr/local/lib/python2.7/dist-packages/django/contrib/admin/templates/admin/base_site.html
dopodichè si modifica il file. Ogni template Django può essere sovrascritto ini questo modo: copia dalla directory di default a quella del progetto e modifica del file.
I template-loader cercano i template all'interno della cartella template al cui interno sarà presente una cartella per ogni progetto/package Python. Se 'APP_DIRSè
Trueall'interno di
settings.py`, si assume che ci sia una sotto-directory templates per ogni applicazione/package del progetto.
Sostanzialmente i template sono un insieme di blocchi del tipo:
{% block NOMEBLOCCO %}{% endblock %}
Quando un template eredita da un altro, i blocchi ridefiniti vanno a sostituire la definizione originale dei blocchi.
E' possibile manipolare l'output delle variabili mediante filtri. I filtri sono definiti attraverso l'uso di pipe:
{{variabile | filtro}}
Alcuni filtri sono:
Filtro | Descrizione | esempio --|--| |default|se la variabile è falsa o vuota viene mostrato il parametro del filtro | {{ value | default:"nothing" }} | length | mostra la lunghezza del dato | | join | separa con , e spazio | {{ list | join:", " }} | lower | | upper | |capfirst | |add:X | |date:"M d, Y" | | {{my_date|date:"Y-m-d"}} |first, |last | |truncatechars:X, |truncatewords:X | mostra solo i primi X caratteri/parole |
Ereditarietà:
{% extends “base.html” %}
Tag con costrutti condizionali if:
{% if athlete_list %}
Number of athletes: {{ athlete_list|length }}
{% else %}
No athletes.
{% endif %}
{% if user.is_authenticated %}
Hello, {{ user.username }}.
{% endif %}
{% for story in story_list %}
<a href="{{ story.get_absolute_url }}">
{{ story.headline|upper }}
</a>
{% endfor %}
In django pagine Web e contenuti sono distribuiti attraverso il meccanismo delle view, implementate tramite una funzione python. Per associare un URL a una view, si esegue il mapping nel file ulrs.py
.
Gli URL sono nella forma :
/newsarchive/<year>/<month>/
dove year e month sono parametri.
Ogni view è definita come funzione nel file view.py
, e deve ritornare un oggetto di tipo HttpResponse
from django.http import HttpResponse
def index(request):
return HttpResponse("You're at the poll index.")
request
consente di accedere ai dettagli della richiesta.
una volta mappati gli URL ad esempio:
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.index, name='index'),
]
dobbiamo integrare lo spazion di URL dell' applicazione con quelli del progetto.
from django.conf.urls import patterns, include, url
from django.contrib import admin
urlpatterns = [
url(r'^polls/', include('polls.urls')),
url(r'^admin/', include(admin.site.urls)),
]
Ora andando alla pagina localhost:8000/polls
otteniamo una risposta perchè:
Quando arriva la richiesta Django va a cercare il mapping di questo indirizzo nel file principale urls.py
e capisce grazie a r'^polls/'
che a tutte le pagine che iniziano con polls
fanno match con con polls.urls
quindi andrà a cercare il mapping del resto dell' URL in questo file. la parte polls
viene tolta perchè ha già fatto match in mysite/urls.py
quindi ciò che rimane è una stringa vuota, che viene gestita nel file polls/urls.py
grazie all' espressione regolare r'^$'
che fa match, appunto, con tutte le stringhe vuote.
###** Regular expression in Python/Django**
Written with StackEdit.