Neuro17
6/25/2015 - 8:26 PM

Django

Django

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Django</title>
<link rel="stylesheet" href="https://stackedit.io/res-min/themes/base.css" />
<script type="text/javascript" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML"></script>
</head>
<body><div class="container"><p><div class="toc">
<ul>
<li><ul>
<li><a href="#mvc-in-django">MVC in Django</a><ul>
<li><a href="#model">Model</a></li>
<li><a href="#view">View</a></li>
<li><a href="#controller">Controller</a></li>
<li><a href="#filosofia-di-progetto">Filosofia di progetto</a><ul>
<li><a href="#api-per-il-db">API per il DB</a></li>
<li><a href="#url-nel-controller">URL nel controller</a></li>
<li><a href="#utilizzo-di-template-per-le-view">Utilizzo di template per le view</a></li>
<li><a href="#view-1">View</a></li>
</ul>
</li>
<li><a href="#struttura-di-un-progetto-django">Struttura di un progetto Django</a></li>
</ul>
</li>
<li><a href="#tutorial-base">Tutorial base</a></li>
<li><a href="#interfaccia-di-amministrazione">Interfaccia di amministrazione</a><ul>
<li><a href="#customizzare-linterfaccia-admin">Customizzare l’interfaccia admin</a></li>
</ul>
</li>
<li><a href="#template-tutorial">Template tutorial</a><ul>
<li><a href="#template-filtri">Template - filtri</a></li>
<li><a href="#template-controllo-di-flusso">Template: controllo di flusso</a></li>
</ul>
</li>
<li><a href="#view-2">View</a><ul>
<li><a href="#regular-expression-in-pythondjango">* Regular expression in Python/Django*</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
</p>



<h2 id="mvc-in-django"><strong>MVC in Django</strong></h2>

<p>Ci sono un elevato numero di funzioni che possono essere usate per facilitare e modularizzare compiti “standard”.</p>

<ul>
<li>interazione con db</li>
<li>autenticazione</li>
<li>etc</li>
</ul>

<p>Gle elementi MVVC sono gestiti in 3 file separati:</p>

<ul>
<li><code>models.py</code>   -&gt; i modelli</li>
<li><code>views.py</code>    -&gt; le viste</li>
<li><code>urls.py</code>     -&gt; i controller</li>
</ul>



<h3 id="model"><strong>Model</strong></h3>

<p>Il componente Model dell’applicazione è implementato direttamente come collezione di classi Python, che poi andranno  <br>
a rappresentare le tabelle del database. Il codice SQL per creare lo schema viene generato automaticamente da Django <br>
quando si esegue il deployment del modello.</p>

<p>Si crea un n ‘virtual object database’ accessibile e usabile direttamente attraverso linguaggio di programmazione ad oggetti.</p>



<h3 id="view"><strong>View</strong></h3>

<p>Si usano template per generare diversi tipi di output, e accesso ai dati del model attraverso API Python.</p>



<h3 id="controller"><strong>Controller</strong></h3>

<p>il file <code>urls.py</code> serve per mappare gli URL richiesti sulle view che restituiscono le pagine richieste. Si possono usare <br>
funzioni built-in e espressioni regolari per mappare gli URL richiesti.</p>



<h3 id="filosofia-di-progetto"><strong>Filosofia di progetto</strong></h3>

<p>Favorire lo sviluppo rapido dell’applicazione, scrivendo meno codice senza ripeterlo, e interagendo con il DB principalmente <br>
con codice SQL autogenerato.</p>



<h4 id="api-per-il-db"><strong>API per il DB</strong></h4>

<p>Limitare al massimo le interazioni con il DB. I dati sono accessibii da ogni modulo e i join vengono creati automaticamente <br>
dallo strato di interfacciamento software. Rimane possibile scrivere direttamente codice SQL, ma solo quando è veramente <br>
necessario.</p>



<h4 id="url-nel-controller"><strong>URL nel controller</strong></h4>

<p>URL puliti e riutilizzabili: evitare le estensioni negli URL.</p>



<h4 id="utilizzo-di-template-per-le-view"><strong>Utilizzo di template per le view</strong></h4>

<p>Lo scopo è separare la logica dalla presentazione. Si evita la ridondanza, si è più protetti contro codice malevolo e si <br>
facilita l’estendibilità per il futuro.</p>



<h4 id="view-1"><strong>View</strong></h4>

<p>Nessun bisogno di creare nuove classi, sono essenzialmente realizzate attraverso delle funzioni Python. Si usano oggetti  <br>
che incapsulano le richieste HTTP.</p>



<h3 id="struttura-di-un-progetto-django"><strong>Struttura di un progetto Django</strong></h3>

<pre data-initialized="true" data-gclp-id="1"><code> mysite (dir top-level)
 |_ manage.py
 |_ mysite (package Python)
 |   |_ __init__.py 
 |   |_ settings.py
 |   |_ urls.py
 |_ app1 (package Python)
     |_ __init__.py
     |_ models.py
     |_ vies.py
     |_ ...
</code></pre>

<p>Un singolo progetto Django può essere spezzato in diverse sotto-applicazioni (ognuna sarà un package separato, come <code>app1</code>), <br>
che avrà tutti i suoi componenti MVC (model, views, urls). Applicazioni diverse possono interagire importado i package.</p>

<ul>
<li><p><code>manage.py</code> <br>
script per automatizzare le operazioni di Django.</p></li>
<li><p><code>mysite/mysite</code> <br>
cartella della applicazione principale (omonima )del progetto</p></li>
<li><p><code>settings.py</code> <br>
impostazioni per il funzionamento dell’applicazione, tra cui: definizione dei path dell’applicazione e configurazione di  <br>
accesso a DB</p></li>
<li><p><code>urls.py</code> <br>
configurazione degli URL per il progetto (livello root).   </p></li>
</ul>



<h2 id="tutorial-base"><strong>Tutorial base</strong></h2>

<p>Creo il progetto direttamente da pycharm, oppure con il comando:</p>

<pre data-initialized="true" data-gclp-id="2"><code>django-admin.py startproject mysite
</code></pre>

<p>Per usare MySQL devo prima creare il DB:</p>

<pre data-initialized="true" data-gclp-id="3"><code>$ mysql --user=root -p
mysql&gt; CREATE DATABASE djangodb;
mysql&gt; CREATE USER 'djangouser'@'localhost' IDENTIFIED BY 'rue1iep5';
mysql&gt; GRANT ALL PRIVILEGES ON djangodb.* TO 'djangouser'@'localhost' WITH GRANT OPTION; 
mysql&gt; show databases;
</code></pre>

<p>Devo aggiungere la connessione al DB creato nel file <code>settings.py</code></p>

<pre data-initialized="true" data-gclp-id="4"><code>DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', 
        'NAME': 'djangodb',
        'USER': 'djangouser',
        'PASSWORD': 'rue1iep5',
        'HOST': '',
        'PORT': '',
    }
}
</code></pre>

<p>Per PostgreSQL:</p>

<pre data-initialized="true" data-gclp-id="5"><code>DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'djangodb',
        'USER': 'djangouser',
        'PASSWORD': 'rue1iep5',
        'HOST': '',
        'PORT': '',
    }
}
</code></pre>

<p>All’interno del progetto creo una nuova app</p>

<pre data-initialized="true" data-gclp-id="6"><code>$ python manage.py startapp polls
</code></pre>

<p>Creo i modelli all’interno di <code>polls/models.py</code></p>

<pre data-initialized="true" data-gclp-id="7"><code>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 &gt;= 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
</code></pre>

<p>Aggiungo l’app alla lista delle app disponibili in <code>mysite/settings.py</code></p>

<pre data-initialized="true" data-gclp-id="8"><code>INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'polls',
)
</code></pre>

<p>Ora tutto è pronto per sfruttare le comodità di django:</p>

<ul>
<li><p>sincronizziamo il D</p>

<pre data-initialized="true" data-gclp-id="9"><code>$ python manage.py makemigrations polls
</code></pre></li>
<li><p>creiamo le tabelle</p>

<pre data-initialized="true" data-gclp-id="10"><code>$ python manage.py migrate
</code></pre></li>
<li><p>SQL generato (mostra il codice SQL generato)</p>

<pre data-initialized="true" data-gclp-id="11"><code>$ python manage.py sqlmigrate polls 0001
</code></pre></li>
<li><p>Controllo</p>

<pre data-initialized="true" data-gclp-id="12"><code>$ python manage.py check
</code></pre></li>
<li><p>Python shell </p>

<pre data-initialized="true" data-gclp-id="13"><code>$ python manage.py shell
</code></pre></li>
</ul>

<p>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:</p>

<ul>
<li>modificare il modello</li>
<li>lanciare <code>python manage.py makemigrations</code></li>
<li>lanciare <code>python manage.py migrate</code></li>
</ul>

<p>A questo punto il model mette a disposizione una serie di metodi e utility per interrogare il DB, ad esempio</p>

<table>
<thead>
<tr>
  <th>Statement</th>
  <th>descrizione</th>
</tr>
</thead>
<tbody><tr>
  <td>q = Question(question_text=”What’s new?”, pub_date=timezone.now())</td>
  <td>crea un nuovo oggetto Question</td>
</tr>
<tr>
  <td>q.save()</td>
  <td>salva sul DB (sincronizzazione esplicita)</td>
</tr>
<tr>
  <td>Question.objects.all()</td>
  <td>select di tutti gli elementi della tabella Question (se non è definito <code>__unicode__</code> (<code>__str__</code> in python 3) da una rappresentazione inutile,come quando non si fa l’override di toString() in JAVA)</td>
</tr>
<tr>
  <td>Question.objects.get(id=1)</td>
  <td>con <code>get</code> si possono recuperare <strong>singoli</strong> oggetti come una <code>WHERE</code> sugli attributi della classe</td>
</tr>
<tr>
  <td>Question.objects.filter(<code>&lt;predicato&gt;</code>)</td>
  <td>ritorna la lista degli oggetti filtrati sulla base del predicato</td>
</tr>
<tr>
  <td>Question.objects.exclude(<code>&lt;predicato&gt;</code>)</td>
  <td>ritorna la lista degli oggetti filtrati che non soddisfano il predicato di filtraggio</td>
</tr>
<tr>
  <td>q.choice_set.all()</td>
  <td>fa il join tra la tabella Question e la tabella Choice (relazione one-to-many)</td>
</tr>
<tr>
  <td>c = q.choice_set.create(choice_text=’Just hacking again’, votes=0)</td>
  <td>crea l’oggetto choice, lo aggiunge al set della question <code>q</code> (fa la insert) e lo ritorna</td>
</tr>
<tr>
  <td>q.choice_set.count()</td>
  <td>fa il count delle Choice associate a una Question</td>
</tr>
<tr>
  <td>Choice.objects.filter(question__pub_date__year = current_year)</td>
  <td></td>
</tr>
</tbody></table>


<p>I predicati di filtraggio sono nella forma <code>&lt;nomeCampo&gt;__criterio=&lt;valore&gt;</code>. Alcuni possibili predicati di filtraggio sono:</p>

<table>
<thead>
<tr>
  <th>Criterio</th>
  <th>Esempio</th>
</tr>
</thead>
<tbody><tr>
  <td>Sottocampi</td>
  <td>__year, __month</td>
</tr>
<tr>
  <td>Substring</td>
  <td>__startswith, __contains</td>
</tr>
<tr>
  <td>Operatori di confronto</td>
  <td>__gte, __gt</td>
</tr>
<tr>
  <td>Uguaglianza</td>
  <td>__exact</td>
</tr>
</tbody></table>




<h2 id="interfaccia-di-amministrazione"><strong>Interfaccia di amministrazione</strong></h2>

<p>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 </p>

<pre data-initialized="true" data-gclp-id="14"><code>127.0.0.1:8000/admin 
</code></pre>

<p>La prima cosa da fare è creare un superuser Django:</p>

<pre data-initialized="true" data-gclp-id="15"><code>$ python manage.py createsuperuser
</code></pre>

<p>Inserire le info e rilanciare il server.</p>

<p>Per aggiungere un’ app alla pagine admin modifico il file <code>&lt;nome_app&gt;/admin.py</code></p>

<pre data-initialized="true" data-gclp-id="16"><code>from .models import Question
admin.site.register(Question)
</code></pre>

<p>Ora basta ricaricare la pagina admin</p>



<h3 id="customizzare-linterfaccia-admin"><strong>Customizzare l’interfaccia admin</strong></h3>

<p>Si personalizza modificando il file <code>admin.py</code> dell’applicazione, creadno una classe che descriva come vogliamo personalizzare l’interfaccia del modello.</p>

<pre data-initialized="true" data-gclp-id="17"><code>#non funzia, capire perchè
class QuestionAdmin(admin.ModelAdmin):
    fields = ['pub_date', 'question']
admin.site.register(Question, QuestionAdmin)
</code></pre>

<p>Si possono raggruppare in sezioni i campi (comodo quando se ne hanno tanti)</p>

<pre data-initialized="true" data-gclp-id="18"><code>class QuestionAdmin(admin.ModelAdmin):
    fieldsets = [
        (None, {'fields': ['question_text']}),
        ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
    ]
admin.site.register(Question, QuestionAdmin)
</code></pre>

<p>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.</p>

<pre data-initialized="true" data-gclp-id="19"><code>class ChoiceInline(admin.StackedInline):
    model = Choice

    # number of choices for each question
    extra = 3
</code></pre>

<p>Ulteriori customizzazioni possono essere fatte ad esempio per mostrare info aggiuntive e non solo quelle del metodo <code>__unicode__</code> che è ciò che viene fatto di default.</p>

<pre data-initialized="true" data-gclp-id="20"><code> class QuestionAdmin(admin.ModelAdmin):
     # …
     inlines = [ChoiceInline]
     list_display = ('question_text', 'pub_date', 'was_published_recently')
</code></pre>

<p>All’interno di <code>list_display</code> 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:</p>

<pre data-initialized="true" data-gclp-id="21"><code>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?'
</code></pre>

<p>Per specificare un opzione di filtraggio, aggiuntere al file <code>admin.py</code></p>

<pre data-initialized="true" data-gclp-id="22"><code>list_filter = ['pub_date'] #in class QuestionAdmin
</code></pre>

<p>Per le funzioni di ricerca invece, sempre in <code>class QuestionAdmin</code>:</p>

<pre data-initialized="true" data-gclp-id="23"><code>search_fields = ['question_text']
# non funzia
date_hierarchy = 'pub_date'
</code></pre>



<h2 id="template-tutorial"><strong>Template tutorial</strong></h2>

<p>(modifichiamo la pagina admin) <br>
La prima cosa da fare è aggiungere il path delle cartella template, in modo che django sappia dove prendere i template. Modificare il file <code>settings.py</code></p>

<pre data-initialized="true" data-gclp-id="24"><code>TEMPLATES = [
 {
 'BACKEND': \
 'django.template.backends.django.DjangoTemplates',
 'DIRS': [os.path.join(BASE_DIR, 'templates')], #nuova riga 
 'APP_DIRS': True,
 ….
 }
</code></pre>

<p>creare una cartella in template di nome admin e copiarci il template <code>base_site.html</code> che si trova in :</p>

<pre data-initialized="true" data-gclp-id="25"><code>/usr/local/lib/python2.7/dist-packages/django/contrib/admin/templates/admin/base_site.html
</code></pre>

<p>dopodichè si modifica il file. Ogni template Django può essere sovrascritto ini <br>
questo modo: copia dalla directory di default a quella del progetto e modifica del file.</p>

<p>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<code>è</code>True<code>all'interno di</code>settings.py`, si assume che ci sia una sotto-directory templates per ogni applicazione/package del progetto.</p>

<p>Sostanzialmente i template sono un insieme di blocchi del tipo: </p>

<pre data-initialized="true" data-gclp-id="26"><code>{% block NOMEBLOCCO %}{% endblock %}
</code></pre>

<p>Quando un template eredita da un altro, i blocchi ridefiniti vanno a sostituire la definizione originale dei blocchi.</p>



<h3 id="template-filtri"><strong>Template - filtri</strong></h3>

<p>E’ possibile manipolare l’output delle variabili mediante filtri. <br>
I filtri sono definiti attraverso l’uso di pipe:</p>

<pre data-initialized="true" data-gclp-id="27"><code>{{variabile | filtro}}
</code></pre>

<p>Alcuni filtri sono:</p>

<table>
<thead>
<tr>
  <th>Filtro</th>
  <th>Descrizione</th>
  <th>esempio</th>
</tr>
</thead>
<tbody><tr>
  <td>|default</td>
  <td>se la variabile è falsa o vuota viene mostrato il parametro del filtro</td>
  <td>{{ value | default:”nothing” }}</td>
</tr>
<tr>
  <td>| length</td>
  <td>mostra la lunghezza del dato</td>
  <td></td>
</tr>
<tr>
  <td>| join</td>
  <td>separa con , e spazio</td>
  <td>{{ list | join:”, ” }}</td>
</tr>
<tr>
  <td>| lower</td>
  <td></td>
  <td></td>
</tr>
<tr>
  <td>| upper</td>
  <td></td>
  <td></td>
</tr>
<tr>
  <td>|capfirst</td>
  <td></td>
  <td></td>
</tr>
<tr>
  <td>|add:X</td>
  <td></td>
  <td></td>
</tr>
<tr>
  <td>|date:”M d, Y”</td>
  <td></td>
  <td>{{my_date|date:”Y-m-d”}}</td>
</tr>
<tr>
  <td>|first, |last</td>
  <td></td>
  <td></td>
</tr>
<tr>
  <td>|truncatechars:X, |truncatewords:X</td>
  <td>mostra solo i primi X caratteri/parole</td>
  <td></td>
</tr>
</tbody></table>




<h3 id="template-controllo-di-flusso"><strong>Template: controllo di flusso</strong></h3>

<p>Ereditarietà:</p>

<pre data-initialized="true" data-gclp-id="28"><code>{% extends “base.html” %} 
</code></pre>

<p>Tag con costrutti condizionali if:</p>

<pre data-initialized="true" data-gclp-id="29"><code>{% 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 %}
    &lt;a href="{{ story.get_absolute_url }}"&gt;
         {{ story.headline|upper }} 
    &lt;/a&gt;
{% endfor %}
</code></pre>



<h2 id="view-2"><strong>View</strong></h2>

<p>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 <code>ulrs.py</code>. <br>
Gli URL sono nella forma :</p>

<pre data-initialized="true" data-gclp-id="30"><code> /newsarchive/&lt;year&gt;/&lt;month&gt;/
</code></pre>

<p>dove year e month sono parametri. <br>
Ogni view è definita come funzione nel file <code>view.py</code>, e deve ritornare un oggetto di tipo HttpResponse</p>

<pre data-initialized="true" data-gclp-id="31"><code>from django.http import HttpResponse
def index(request):
    return HttpResponse("You're at the poll index.")
</code></pre>

<p><code>request</code> consente di accedere ai dettagli della richiesta.</p>

<p>una volta mappati gli URL ad esempio:</p>

<pre data-initialized="true" data-gclp-id="32"><code>from django.conf.urls import url
from . import views
urlpatterns = [
    url(r'^$', views.index, name='index'),
]
</code></pre>

<p>dobbiamo integrare lo spazion di URL dell’  applicazione con quelli del progetto.</p>

<pre data-initialized="true" data-gclp-id="33"><code>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)),
]
</code></pre>

<p>Ora andando alla pagina <code>localhost:8000/polls</code> otteniamo una risposta perchè:</p>

<p>Quando arriva la richiesta Django va a cercare il mapping di questo indirizzo nel file principale <code>urls.py</code> e capisce grazie a <code>r'^polls/'</code> che a tutte le pagine che iniziano con <code>polls</code> fanno match con con <code>polls.urls</code> quindi andrà a cercare il mapping del resto dell’ URL in questo file. la parte <code>polls</code> viene tolta perchè ha già fatto match in <code>mysite/urls.py</code> quindi ciò che rimane è una stringa vuota, che viene gestita nel file <code>polls/urls.py</code> grazie all’ espressione regolare <code>r'^$'</code> che fa match, appunto, con tutte le stringhe vuote.</p>



<h3 id="regular-expression-in-pythondjango"><em>* Regular expression in Python/Django*</em></h3>

<blockquote>
  <p>Written with <a href="https://stackedit.io/">StackEdit</a>.</p>
</blockquote></div></body>
</html>