django | collegarsi al server web di lavoro (python) da client remoto

Quando si sviluppano applicazioni con django si ha a disposizione un server web “temporaneo” che si avvia con il comando:

$ python manage.py runserver

ed e’ raggiungibile all’indirizzo:

http://lcoalshot:8000

Se vogliamo accedervi da remoto bisogna lanciare prima il comando (sulla macchina client):

$ ssh -L 8888:127.0.0.1:8000 nome_utente@indirizzo_ip_server

per esempio:

$ ssh -L 8888:127.0.0.1:8000 sit@192.168.168.1

A questo punto possiamo collegarci mediante il browser puntando a:

http://localhost:8888

PS: E’ necessario avere avviato in precedenza il servizio con:

$ python manage.py runserver

sulla macchina host

qualche tips su django

Rimozione django

Per rimuovere django installato da sorgenti (nel caso si voglia installare una versione piu’ recente, per esempio) basta trovare la directory “django” e cancellarla. Per trovarla impartire il comando:

sit@debian:~$ python -c “import sys; sys.path = sys.path[1:]; import django; print(django.__path__)”

che nel mio caso restituisce:

[‘/usr/lib/pymodules/python2.6/django’]

MD_PYTHON ERROR in django

Dopo un blocco inaspettato del server (durante un processo di rsync) il gestionale django installato riportava il seguente errore:

MOD_PYTHON ERROR

…………..

…………..

Import Error: Could not import settings ‘my_app.settings’ (Is it on sys.psth? Does it have syntax error?): No module named myapp.settings

Dopo avere cercato in rete ho trovato che la causa di questo messaggio potrebbe essere:

– file di configurazione di apache errato;

– sys.path sbagliato;

– permessi non corretti su cartelle e files del progetto (permessi che inibiscono all’utente www-data di leggere i file di settings);

– bug nel codice django.

Prima di procedere ho provato a replicare l’aplicativo sul portatile (compreso db postgresql colllegato) e tutto funzionava a modino (NB: stesso SO Debian stable).

Quindi ho confrotato il file di configurazione di apache (/etc/apache2/apache2.conf”) e sono identici; quindi il problema non sta li;

ho confrontato il sys.path delle due macchine: per farlo ho lanciato una shell python, poi:

>>> import os, sys

>>> print sys.path

ed i risultati sono identici: quindi anche la seconda ipotesi e’ scartata.

Anticipo che il bug nel codice django e’ da escludere a priori visto che sul portatile gira senza problemi. Rimangono da verificare i permessi sulle cartelle del progetto.

Infatti confrontando i listati di “ls -l” sulle due macchine si nota che la directory “/home/user/” ha dei permessi differenti (nel server e’ inibita la lettura a tutti. Molto probabilmente durnate l’operazione di rsync lanciato da root ha modificato i diritti di accesso durante; il blocco del server causato da un down temporaneo della rete ha messo in lock anche le directory interessate). Cambiando questa impostazione con:

$ chmod 751 -R /home/user/

tutto e’ andato a posto

django | somma di campi

Supponiamo di avere una tabella contente i valori dei consumi energetici di un particolare dispositivo.

In particolare abbiamo inserito un campo (somma) che sarà popolato con il risultato ottenuto dalla somma di altri 4 campi. In questo modo ad ogni inserimento (Admin) di dati relativi ai primi 4 campi (rientranti nella somma) e dopo avere cliccato il punsante “Salva” o “Salva e continua le modifiche” il campo “somma” apparirà popolato con il valore somma.

Ecco un esempio di strutturazione della class nel file models.py.

class ConsumiIlluminazione(models.Model):
 """Tabella consumi illuminazione"""

 utente = models.ForeignKey(UtenteIlluminazione)
 campo1 = models.IntegerField(null=True, blank=True)
 campo2 = models.IntegerField(null=True, blank=True)
 campo3 = models.IntegerField(null=True, blank=True)
 campo4 = models.IntegerField(null=True, blank=True)
 somma = models.IntegerField(null=True, blank=True)
 def calcoloTotale(self):
  self.somma = self.campo1 + self.campo2 + self.campo3 + self.campo4
 def save(self):
  self.calcoloTotale()
  super(ConsumiIlluminazione, self).save()
 def __unicode__(self):
  return "%s" % (self.utente)
 class Meta:
  ordering = ["utente"]
  verbose_name_plural = "Consumi illuminazione"

geodjango | primo approccio

GeoDjango è un add-on per Django che consente di gestire e manipolare dati geografici all’interno di un progetto django.

Questo post riassume i passi iniziali per implementare una class geografica in una applicazione….spero di espandere il post non appena avro’ fatto qualche test ed esperienza ulteriore. Andiamo per step:

1. Creazione del db geografico (nel mio caso si tratta di un db Postgis).

Se ancora non esiste creiamo un template per i db gis (sarà molto comodo anche in futuro):

– autenticarsi come utente postgres ed entrae in un template (esempio il “template1”):

postgres@debian:/home/sit$ psql template1;

–  creare un nuovo db che chiameremo template_gis sul modello del template0;

postgres=# CREATE DATABASE template_gis template=template0;

– uscire da psql e creare il linguaggio per il db appena creato:

postgres@debian:/home/sit$ createlang plpgsql template_gis

– poi:

postgres@debian:/home/sit$ psql -f /usr/share/postgresql/8.4/contrib/postgis-1.5/postgis.sql -d template_gis

– popoliamo la tabella spatial_ref_sys:

postgres@debian:/home/sit$ psql -d template_gis -f /usr/share/postgresql/8.4/contrib/postgis-1.5/spatial_ref_sys.sql

– entrare nuovamente in un template e indicare che template_gis è un template:

postgres=# UPDATE pg_database set datistemplate=’t’ WHERE datname=’template_gis’;

– a questo punto possiamo creare il nostro db per django usando il template_gis appena creato:

postgres=# CREATE DATABASE energia_django template=template_gis OWNER sit;

– ci spostiamo all’interno del database appena creato:

postgres=# \connect energia_django

– poi è necessario dare i GRANT di SELECT sulla spatial_erf_sys e ALL sulla geometry_columns:

postgres=# GRANT SELECT on spatial_ref_sys to sit;

postgres=# grant ALL on geometry_columns to sit;

2. Configurazione del progetto django (geodjango)

Andiamo all’interno del nostro progetto django (il progetto sia chiama “energia” e una prima applicazione si chiama “manager”)

– Configurare il file settings.py modificando le impostazioni del database come segue:

DATABASES = {
    'default': {
         'ENGINE': 'django.contrib.gis.db.backends.postgis',
         'NAME': 'energia_django',
         'USER': 'sit',
     }
}

Aggiungere:

django.contrib.gis tra le INSTALLED_APPS

3. Preparazione dei dati geografici

Partiamo da dati in formato SHP (nel nostro caso si tratta di uno SHP di punti chiamato “quadri.shp”.

– creare una directory chiamata “data” all’interno della nostra applicazione:

$ mkdir manager/data

e salviamo al suo interno gli SHP relativi:

– con ogrinfo ispezioniamo lo SHP:

$ ogrinfo -so quadro.shp quadro

ottenendo una lista di dati relativi allo SHP (tra cui il numero di feature, SRS, nomi dei campi). Questo è molto importante per creare la class (nel file models.py) che andrà ad “accogliere” i dati. Definiamo quindi la class nel nostro models.py dell’applicazione.

class QuadroIlluminazione(models.Model):
 kp = models.IntegerField()
 numnuovo = models.CharField(max_length=5)
 via = models.CharField(max_length=30)
 codanagr = models.IntegerField()
 norma = models.CharField(max_length=2)
 regolato = models.CharField(max_length=2)
 contenel = models.CharField(max_length=15)
 contpote = models.CharField(max_length=20)
 elettronic = models.CharField(max_length=2)
 ncliente = models.CharField(max_length=10)
 gmrotation = models.FloatField()
 geom = models.MultiPointField(srid=3003)
 objects = models.GeoManager()
 class Meta:
 verbose_name_plural = "Quadri illuminazione pubblica"

 # Returns the string representation of the model.
 def __unicode__(self):
 return self.numnuovo

NB: attenzione all’indentazione; in questo post puo’ non essere corretta; vedere la guida di python per una corretta scrittura del codice)

Abbiamo definito la nuova tabella che conterrà i dati geografici con gli stessi attributi trovati nello SHP. Gli unici due campi che vengono aggiunti sono “geom” e “objects“.

– Controlliamo che tutto sia a posto prima di generare il DB con:

$ python manage.py sqlall manager

l’output è simile a questo (la parte finale):

……………..

CREATE INDEX “manager_contrattoaperturagasnaturale_utente_id” ON “manager_contrattoaperturagasnaturale” (“utente_id”);
CREATE INDEX “manager_contrattofornituragasnaturale_utente_id” ON “manager_contrattofornituragasnaturale” (“utente_id”);
SELECT AddGeometryColumn(‘manager_quadroilluminazione’, ‘geom’, 3003, ‘MULTIPOINT’, 2);
ALTER TABLE “manager_quadroilluminazione” ALTER “geom” SET NOT NULL;
CREATE INDEX “manager_quadroilluminazione_geom_id” ON “manager_quadroilluminazione” USING GIST ( “geom” GIST_GEOMETRY_OPS );COMMIT;

– a questo punto sincronizziamo il DB con:

$ python manage.py syncdb

compariranno una serie di messaggi (con la richiesta di creazione del superutente). alla fine avremo il nostro db pronto.

4. Ridefinizione del models.py

Il models.py deve essere modificato inserendo classe e dizionario. Una funzione ci viene in aiuto per automatizzare il processo:

$ python manage.py ogrinspect manager/data/quadro.shp QuadroIlluminazione –srid=3003 –mapping –multi

Questo comando produce in output la definizione della class e del dizionario necessario per il nostro layer geografico. Tale output puo’ essere copiato/incollato nel nostro models.py

5. Caricamento dei dati del database

Per il caricamento dei dati è necessario creare un modulino python per l’import. Per farlo creare un file chiamato “load.py” e salvarlo all’interno della nostra applicazione. Copiare al suo interno il seguente codice:

import os
from django.contrib.gis.utils import LayerMapping
from models import QuadroIlluminazione

quadroilluminazione_mapping = {
 'kp' : 'KP',
 'numnuovo' : 'NumNuovo',
 'via' : 'Via',
 'codanagr' : 'CodAnagr',
 'norma' : 'Norma',
 'regolato' : 'Regolato',
 'contenel' : 'ContEnel',
 'contpote' : 'ContPote',
 'elettronic' : 'Elettronic',
 'ncliente' : 'Ncliente',
 'gmrotation' : 'GMRotation',
 'geom' : 'MULTIPOINT',

}

quadroilluminazione_shp = os.path.abspath(os.path.join(os.path.dirname(__file__), 'data/quadro.shp'))

def run(verbose=True):
 lm = LayerMapping(QuadroIlluminazione, quadroilluminazione_shp, quadroilluminazione_mapping, transform=True, encoding='iso-8859-1')
 lm.save(strict=True, verbose=verbose)

– Ora invochiamo la shell python per importare i dati mediante il modulo appena creato

$ python manage.py shell

Al prompt di python impartiamo i seguenti comandi (prima richiamiamo il modulo e poi la funzione di “load”):

>>> from manager import load
>>> load.run()

Seguirà una serie di messaggi di import (uno per ogni feature).

6. Caricamento del layer geografico

All’interno del file “admin.py” inserire le seguenti stringhe di codice:

from django.contrib.gis import admin
from manager.models import *
........
admin.site.register(QuadroIlluminazione, admin.GeoModelAdmin)

…to be continued as soon as possible

django | modificare le tabelle

Una volta creato il progetto e l’applicazione con django succede di dover apportare delle modifiche alla struttura del database (per esempio aggiunta di campi alle tabelle,..).

Per farlo sono necessari 4 passi:

– eseguire un backup del db con:

$ python manage.py dumpdata manager > db.json

dove manager è il nome dell’applicazione (db) e db.json è un backup di tutto il db (JSON sta per JavaScript Object Annotation: si tratta di un formato di interscambio per dati)

– si apportano le modifiche alla tabella (model); ad esempio inserendo un nuovo campo agendo sul file models.py

– si resetta il database: in questo modo vengono ricreate le tabelle con il nuovo modello (rispondere “yes” alla domanda di conferma di reset):

$ python manage.py reset manager

– ri ricaricano i dati prelevandoli dal backup fatto in precedenza:

$ python manage.py loaddata db.json

Fatto!

django! si, django!

In questo post tento di riassumere (nella maniera piu’ semplice possibile) i passi che ho seguito per creare il primo progetto con django. Da non sviluppatore e abbastanza ignorante nel campo dei linguaggi di programmazione se dovessi definire django con un aggettivo direi: disarmante!

Si ispira al principio DRY (Don’t Repeat Yourself) e la migliore definizione di django che ho trovato è quella fornita da Marco Beri nel suo ottimo libro “Sviluppare applicazioni web con django”: “Django è un ottimo tavolo da lavoro, con tanto di strumenti, per costruire siti dinamici e applicazioni web“. E io aggiungo: le “gambe” del tavolo sono costituite da Python!

Utilizzando Debian troviamo django già pacchettizzato. Purtroppo la versione disponibile non è la piu’ recente; ma basta scaricare i sorgenti dal sito http://www.djangoproject.com/download/ e seguire i 3 (anzi 4) semplici passi indicati:

– si scarica;

– si decomprime il tar.gz;

– ci si sposta nella directory ottenuta dalla decompressione;

– si “suda” per installare il pacchetto: fatto!

E qui comincia il bello. Andiamo per fasi (step):

– si crea una directory di lavoro (la possiamo creare nella nostra home; poi vedremo come fare per renderla visibile al server web).

$ mkdir django_work

– ci spostiamo nella directory creata:

$ cd django_work

– richiamiamo il modulo per la creazione del “progetto” (con django si crea prima un “progetto” e poi “n” applicazioni. C’è molta documentazione in rete che riguarda la strutturazione del framewok):

$ django-admin startproject energia

Questo comando genera nella directory corrente una sottodirectory che ha il nome del progetto indicato (nel nostro caso “energia”) che contiene alcuni file: __init__.py, manage.py, settings.py, e urls.py

NB: con l’installazione di django è stato installato anche un server web (diciamo “provvisorio”) utilissimo per fare i test durante la creazione e implementazione del progetto. Questo server si avvia mediante il comando:

$ python manage.py runserver

Se tutto è ok compare un messaggio simile a questo:

Validating models…

0 errors found….. ecc

Quit the server with CTRL-C.

– Modificare il file settings.py e indicare i parametri alla voce “DATABASES“:

‘ENGINE’:  ‘postgresql_psycopg2″ (se si usa database Posgresql)

‘NAME’:  ‘energia’ (il db si puo’ creare dopo; l’importante è dare questo nome :-))

‘USER’:  ‘sit’ (il proprietario del db creato)

‘HOST’: ‘localhost’

‘PORT’: ” (lasciare in bianco per assumere la porta configurata di default)

– Creare il nuovo database (con lo stesso nome indicato del file “settings.py“). PS: in questo post si assume di lavorare con DB Postgresql; per altre configurazioni (sqlite, mysql,…) vedere la ricca documentazione che si puo’ trovare in rete.

$ su

# su postgres

# psql

# CREATE DATABASE energia OWNER sit;

– lanciare il webserver (quello ausiliario fornito da django con il solo scopo di testare lo sviluppo dell’applicazione) posizionandosi all’interno della directory di lavoro.

$ ./manage.py runserver oppure

$ python manage.py runserver

Deve comparire un messaggio di “0 errors“.

– Puntare il browser alla pagina http://localhost:8000/

dovremmo ottenere una pagina con scritto “IT WORKED…..”

– Creare l’applicazione che chiameremo “manager“:

$ ./manager.py startapp manager

In questo modo viene creata la directory “manager”.

– Definire le tabelle del DB mediante il file “models.py“: le tabelle sono definite come classi python (vedi il tutorial on line)

– L’applicazione nuova chiamata “manager” deve essere attivata modificando il file “…../django_work/energia/settings.py” ed inserendo la voce ‘energia.manager’ nella sezione “INSTALLED_APPS

– Per applicare il modello appena definito cioé costruire la struttura del database lanciare il comando:

$ ./manage.py syncdb

Compare una sequenza di messaggi che indicano l’avvenuta creazione di alcune tabelle (comprese quelle di autenticazione) in quanto previste tra le “INSTALLED_APPS” del file “settings.py” (‘django.contrib.auth‘). Installando l’auth system viene chiesto se si vuole creare un superuser. Rispondere “yes“: viene proposto l’utente attivo. Dare” yes” e immettere un indirizzo e-mail e una password (l’email non è indispensabile).

– A questo punto si puo’ procedere al popolamento della/e tabella/e del db. Il tutorial propone di usare la shell di django ma si puo’ fare benissimo con vari client (io ho usato phppgadmin per Postgresql).

– Creazione delle “view“: si tratta delle viste ossia come devono essere presentati i dati. Prima di farlo definiamo gli URl delle varie pagine editando il file “…/django_work/energia/urls.py“.

Questi pattern associano le espressioni regolari ad un modulo python.

Le view vengono definite nel file “…/django_work/energia/manager/views.py” (sono tipiche dell'”applicazione”). Nelle view definite si fa riferimento a determinati template (file HTML).

– Definire la variabile ‘TEMPLATES_DIRS‘ all’interno del file “settings.py

Esempio: ABSOLUTE_PATH + ‘/home/sit/django_work/energia/manager/templates’

– Creare una directory “templates” all’interno di “manager” e procedere alla creazione dei template (base.html, index.html,…). Per una descrizione più dettagliata sui template si rimanda al tutorial on-line.

Supposto che tutto sia ok si puo’ passare alla pubblicazione vera e propria del nostro lavoro. Ricordiamoci che fino ad ora abbiamo lavorato “in casa” usando il server web ausiliario gentilmente offerto da django. Ma se dobbiamo “uscire” nel mondo dobbiamo usare un “vero” server web. Qui facciamo riferimento ad Apache.

– Nel file “settings.py” nella sezione “DATABASES” verificare che la voce ‘HOST‘ sia impostata a ‘localhost’.

– Modificare il file di configurazione di Apache che si trova in (debian :-)) “/etc/apache2/apache2.conf” aggiungendo:

<Location “/energia/”>

SetHandler python-program

PythonHandler django.core.handlers.modpython

SetEnv DJANGO_SETTINGS_MODULE energia.settings

PythonPath “[‘/home/sit/django_wotk/’,’/home/sit/django_work/energia/’] + sys.path”

PythonOption django.root /energia

PythonDebug On

</Location>

<Location “/media”>

SetHandler None

</Location>

Alias /media /home/sit/src/Django-1.2.1/django/contrib/main/admin/media

Quest’ultimo alias è necessario per caricare i file CSS, JS (modificare i template HTML inserendo “/energia/” a monte di ogni HREF).

NB: ricordarsi di riavviare il server web dopo ogni modifica:

# /etc/init.d/apache2 restart

Spero sia tutto corretto. Commenti benvenuti.