Id alfanumerici per le chiavi primarie in django

 

Django web framework

Oggi torno sul blog per scrivere un breve tutorial riguardante il “mondo” Django.

Da buon appassionato di questo framework continuo nei miei esperimenti e in questo articolo spiegherò come modificare le chiavi primarie delle tabelle django da numero intero a stringa alfanumeriche sulla falsa riga degli uuid di PostgreSQL.

Il framework usa come default chiavi primarie di tipo integer che per ovvi limiti di architettura del tipo int possono essere grandi al massimo 32 bit. Con poche righe di codice vedremo come sostituire la chiave primaria con un valore generato tramite il modulo python uuid.

Per prima cosa in genere mi creo un file utils.py nell’app principale, un modulo in cui inserire tutte le funzioni di utilità per l’app. All’interno di questo file andremo a creare la nostra funzione che genererà gli uuid in questo modo:


import uuid

def make_uuid():
   return str(uuid.uuid1())

In questo modo genereremo un id alfanumerico basato sul mac address dell’host da cui viene generato, un numero di sequenza (in questo caso random) e il timestamp corrente. In questo modo non solo avremo id univoci all’interno della tabella, ma addirittura all’interno dell’intero database azzerando di fatto la possibilità di collisioni (l’unica possibilità sarebbe se venissero generati nello stesso istante due id con lo stesso numero di sequenza, non impossibile ma altamente improbabile).

Una volta scritta questa funzione non ci resta che usarla per generare gli id all’interno dei nostri model come nell’esempio sottostante:

from APP_NAME.utils import make_uuid
from django.db import models

class MyModel(models.Model):
   id = models.CharField(max_length = 36, primary_key = True, default = make_uuid, editable = False)
   ... altri campi ...

Come potete vedere si dovrà importare la funzione appena scritta all’interno del file models.py e utilizzarla per specificare il valore di default del campo id (omesso di default in caso di id standard).

Se si volesse evitare di usare il mac address della macchina per generare l’uuid si potrebbe utilizzare una funzione differente. Ad esempio la uuid.uuid4() genera uuid random, ovviamente a discapito di una, seppure remota, possibilità di collisioni.

Riempire dinamicamente una jTable in Java

Ultimamente sto utilizzando intensamente Java per lavoro. Sto realizzando un gestionale abbastanza corposo, dove ho potuto sperimentare diverse cose interessanti.

Nel disegnare le interfacce, uno degli oggetti che sto trovando sempre più utile, è la jTable, nient’altro che una semplice tabella (la vecchia DataGrid di visual basic). Inizialmente avevo trovato un po’ ostico capire come funzionasse, nonostante ci fossero parecchi esempi che danno molti consigli su come usarle. Una delle pagine di esempi più complete è questa sul sito oracle.

Voglio però spendere qualche riga per spiegare come poter facilmente caricare una jTable leggendo i dati da un resultset o da un elenco qualsiasi.

Penso che il concetto più semplice per utilizzare al meglio le jTable sia implementare una List<T> (dove T può essere un array di Object o di String o una vostra classe personale, fate voi) con una ArrayList o una LinkedList. Questa lista terrà aggiornata la jTable.

Personalmente creo sempre un metodo che chiamo “refreshTable” che legge i dati dalla lista e li inserisce nella tabella. Il metodo non farà altro che usare un iteratore per scorrere la lista e creare una matrice di Object da passare alla nostra jTable per riempirla.

        //Creo array di intestazioni
        String [] headers=this.getTableHeaders();
        //Creo matrice di dati
        Object[][] data=new Object[this.lista.size()][headers.length];
        int i=0;
        for(Iterator<String[]> it=lista.iterator();it.hasNext();){
            String[] tmp=it.next();
            for(int j=0;j<tmp.length;j++){
                data[i][j]=tmp[j];
            }
            i++;
        }
        //Setto dati e intestazioni della tabella
        this.myJTable.setModel(new javax.swing.table.DefaultTableModel(data, headers){@Override public boolean isCellEditable(int rowIndex, int mColIndex) { return false; }});
        //Setto larghezza colonne
        this.setTableCellsSize(this.myJTable);
        //Imposto allinamento delle celle al centro
        DefaultTableCellRenderer renderer=new DefaultTableCellRenderer();
        renderer.setHorizontalAlignment(DefaultTableCellRenderer.CENTER);
        this.myJTable.setDefaultRenderer(this.myJTable.getColumnClass(0), renderer);
        this.myJTable.updateUI();

Così facendo abbia riempito la nostra jTable. Il metodo che fa ciò è il setModel(), al quale io passo sempre una matrice di Object che contiene i dati veri e propri e un array di String che contiene le intestazioni della tabella (che leggo dal mio metodo this.getTableHeaders() ). Oltre a questo ho creato un metodo (this.setTableCellsSize() ) che imposta la larghezza delle varie colonne della tabella:

        int prefWidth=(this.getWidth()/2)/(this.getHeadersTable()).length;
        tbl.setAutoResizeMode(jTable.AUTO_RESIZE_OFF);

        tbl.getColumnModel().getColumn(0).setPreferredWidth(prefWidth+20);
        tbl.getColumnModel().getColumn(1).setPreferredWidth(prefWidth+100);
        tbl.getColumnModel().getColumn(2).setPreferredWidth(prefWidth+20);
        tbl.getColumnModel().getColumn(3).setPreferredWidth(prefWidth-30);
        tbl.getColumnModel().getColumn(4).setPreferredWidth(prefWidth+20);
        tbl.getColumnModel().getColumn(5).setPreferredWidth(prefWidth+20);
        tbl.getColumnModel().getColumn(6).setPreferredWidth(prefWidth-20);
        tbl.getColumnModel().getColumn(7).setPreferredWidth(prefWidth+20);

Nelle ultime righe ho invece dichiarato un Renderer per settare l’allineamento al centro delle celle della jTable.

Prestate attenzione alla linea dove viene eseguita la setModel(): qui ho riscritto il metodo isCellEditable, in modo che restituisca sempre false. Così facendo qualsiasi cella della nostra jTable non potrà essere editata.

Se vi servissero esempi più dettagliati (ad esempio per inserire delle checkbox in una delle colonne o per aprire menu al pressione del tasto destro del mouse sulla tabella) fate un fischio! ;-)

Nato di domenica…

Ho scoperto oggi un trick davvero interessante, che permette in php di creare delle variabili con nomi dinamici… :-O Cosa vorra mai dire tutto ciò? Semplice:
Se io voglio che una variabile prenda il nome del contenuto di un’altra variabile, posso farlo così:

$a="pippo";
${$a}="pluto";
echo $pippo;//a video verrà visualizzato: pluto

Mi sono trovato di fronte a questo problema, quando stamattina dovevo leggere dei records da un db, e creare delle variabili che si chiamassero come i campi del db.

Siccome sono pigro (e da qui il titolo di questo post, infatti mio papà dice che sono nato di domenica :-P), per semplificarmi la vita i campi letti dal db sono all’interno di un array associativo del tipo $array[0][‘campodb’] e scorro i risultati con un:

foreach(array_keys($array[0]) as $k){ ... }

Quindi sfruttando questa piccola scoperta in poche righe mi sono letto i valori dal db e creato le variabili contenenti i valori letti dal db.

Il codice finito risulta una cosa del tipo:

$q="SELECT campo1,campo2,...,campo20 FROM tabella WHERE condizioni";
$db->query($q); /**/
if($db->numRows>0){
   foreach(array_keys($db->rows[$i]) as $k){
      ${$k}=$db->rows[$i];
   }
}

Alla fine della fiera avrò una variabile per ogni campo presente nella SELECT con all’interno il valore letto dal db ($campo1, $campo2, … , $campo20).
In alternativa qui sotto ci sono alcuni esempi dell’utilizzo di questa features in php (direttamente da php.net)

define('ONE', 1);
function one() {
    return 1;
}
$one = 1;

${"foo$one"} = 'foo';
echo $foo1; // foo
${'foo' . ONE} = 'bar';
echo $foo1; // bar
${'foo' . one()} = 'baz';
echo $foo1; // baz

Sapevate già tutto? D’oh! Sono sempre l’ultimo a scoprire le cose interessanti! ;-(
[ad]

Indici Full Text in MySQL

Post da nerd, astenersi perditempo… :-P

[NERD MODE ON]

Alcuni giorni fa sul lavoro mi sono cimentato in un nuovo esperimento.

Tutto è partito dal problema di dover indicizzare dei contenuti, sui quali poi eseguira una ricerca “generica” in stile google (ovvero un unico campo che riceve un insieme di parole, che possono corrispondere a diversi campi del db).

Bene non voglio stare qui a spiegare nei dettagli la soluzione che abbiamo deciso di adottare, ma in sostanza mi sono ritrovato con un campo testuale con dentro tutte le parole che corrispondono ad una chiave.

Ok, e ora? L’idea iniziale è stata quella di eseguire una query con ” LIKE ‘%parola%’ ” in OR con altre LIKE simili, per ogni parola inserita dall’utente. Una volta implementata, tutto funzionava (avevo 3 record in quella tabella). Siccome per scrupolo avevo anche implementato un timer che misurasse il tempo di esecuzione, ho provato a fare un test pesante… Con python mi sono creato un programma per scrivere su file qualche centinaia di query di inserimento su quella tabella, lo eseguo e popolo il db. Ora ci sono 1000 record (non sono ancora abbastanza ma rende già l’idea), rilancio la ricerca e il timer segna 0,3 secondi. Buono no? sì ma sono 1000 record, se mai i record dovessero essere 100K o ancora di più? Mmm non mi soddisfa questa cosa. *Googleing*….*Googleing*….*Googleing* FULL TEXT INDEX

Cos’è? In MySQL è possibile definire su un campo di una tabella, un indice FULL TEXT, ovvero una struttura che indicizza in maniera ottimale tutte le parole presenti in uno o più campi. Ci sono alcune restrizioni però. Quella più importante è che la tabella non può essere creata con il motore InnoDB (il più comune perchè supporta query multiple in una singola transazione). Inoltre le stringhe da cercare con le query dovranno avere più di 3 caratteri (altrimenti bisogna andare a modificare le impostazioni di MySQL, cosa impossibile se non si ha accesso al server, e comunque relativamente complicata da fare).

Detto ciò i passi da fare sono i seguenti:
Definiamo la tabella e l’indice:

CREATE TABLE test (
id INT UNSIGNED   AUTO_INCREMENT NOT NULL PRIMARY KEY,
keywords TEXT,
[keywords2] VARCHAR(255),
FULLTEXT (keywords[,keywords2])
);

[Tra le parentesi quadre ho messo il secondo campo, spero si capisca che è opzionale…]

Fatto questo e dopo aver popolato la tabella, possiamo provare la nostra ricerca con la seguente query:

SELECT * FROM test WHERE MATCH(keywords) AGAINST('pippo')

In questo modo andremo a dire a MySQL di cercarci l’esatta parola ‘pippo’ all’interno del campo keywords.

Una cosa che non si trova facilmente nelle guide che ho seguito (ho fatto perciò riferimento alla documentazione ufficiale di MySQL) è che così facendo si effettua una ricerca in linguaggio naturale, che è ottimale per indicizzare frasi di senso (più o meno) compiuto. Il “difetto” se può definirsi così, è che con questo tipo di ricerca alcune parole non verranno trovate, infatti MySQL utilizza un array di stopwords che verranno saltate a piè pari dalla ricerca. Per effettuare una ricerca su tutte le parole e utilizzando operatori logici (ad esempio “+” significa OR mentre “-” esclude la parole che segue questo simbolo) bisogna effettuare una ricerca IN BOOLEAN MODE, più lenta, ma più efficace. La nostra query dovrà quindi essere modificata in:

SELECT * FROM test WHERE MATCH(keywords) AGAINST('*pippo*,*pluto*' IN BOOLEAN MODE)

In questo modo si effettua una ricerca all’interno del campo keywords, delle parole che contengono al loro interno “pippo” o “pluto”. Il carattere “*” funziona un po’ come il “%” nelle LIKE.

A questo punto manca un ultima chicca. La funzione MATCH (..) AGAINST(..) ritorna un valore che rappresenta la pertinenza delle parole cercate nel campo. Nel BOOLEAN MODE sarà il numero di parole trovate nel campo, mentre con la ricerca in linguaggio naturale ci sarà un algoritmo che calcola la pertinenza con delle regole strane ma che funzionano ;)

Quindi per sfruttare al massimo questo algoritmo bisognerà scrivere la query con:

SELECT *, MATCH(keywords) AGAINST('*pippo*,*pluto*' IN BOOLEAN MODE) as pertinenza FROM test WHERE MATCH(keywords) AGAINST('*pippo*,*pluto*' IN BOOLEAN MODE) ORDER BY pertinenza DESC

Così facendo ordiniamo i risultati dal più pertinente, a quello meno.

Risultato? sui miei 1000 records il tempo si è dimezzato, nel caso peggiore… Risultato accettabile no? :-)

Non vi resta che provare per credere, buon divertimento!

[NERD MODE OFF]
[ad#ad-1]

jQuery User Interface: interfacce utente in javascript!

Intanto benvenuti a tutti nel mio nuovo-vecchio blog. Ho solamente cambiato indirizzo, mantenendo tutto il vecchio blog e cambiando la veste grafica… Un piccolo aggiornamento contro la noia, insomma! ;-)

Detto ciò in per inaugurare davideferrero.com, voglio portarvi a conoscenza di un tool molto utile, se non lo conoscete ancora.

Come tutti ormai sapete (non lo sapete? sapevatelo :-P ) sono fan e infognato (leggi “addicted” che fa più figo) di jQuery, un javascript framework molto intuitivo, semplice e abbastanza leggero per animare e migliorare le proprio pagine web.

Bene, usando un po’ jQuery noterete subito di aver bisogno di interfacce grafiche per l’utente, ad esempio per una scelta di date (ne avevo già parlato qui) o per creare dei blocchi trascinabili (drag&drop), barre di caricamento, pulsanti “slider” o dei tabs… Ok, con jQuery UI tutto ciò è possibile, potete crearvi il vostro tema personalizzato scegliendo i colori e le caratteristiche dei vari oggetti e scaricarvi i file (javascript, css e immagini), personalizzandovi il pacchetto di download con solo gli oggetti di cui avete bisogno. Per tutte le personalizzazioni dei vari gadget, troverete un’ampia documentazione che vi aiuterà nel caso aveste problemi a farli funzionare.

Appena pubblicheremo il progetto a cui sto ancora lavorando in ufficio, potrete vedere all’opera alcune di queste UI… a presto per i prossimi aggiornamenti su questo argomento!

PS: aggiornate il feed rss facendolo puntare al nuovo indirizzo se non lo avete ancora fatto, ma soprattutto se vi eravate abbonati a quello vecchio… Se invece non lo avevate aggiunto tra i vostri preferiti, avete un motivo in più per farlo ora! ;-)
[ad#ad-1]

Web & Flash: risolvere tutti i problemi di compatibilità

Come spiega il titolo, in questi giorni, ho avuto qualche piccolo problema nell’embedding di oggetti flash in alcune pagine web a cui stavo lavorando.

Chiunque si sia cimentato, anche solo per poco, nel mestiere del web developer, avrà certamente incontrato problemi nel rendere uguale per tutti i browser le pagine web. Con quasi tutti i browser, le pagine vengono renderizzate in un certo modo, mentre con altri browser no (notare, non c’è la “s” del plurale :-P ). E così è anche per gli oggetti flash. Il browser appena linkato pensa bene di riconoscere l’embedd come controllo Active X, e non lo visualizza (a meno che… ma la storia si fa lunga e tortuosa). Googleggiando, ci si imbatte quasi subito in swfobject, un oggetto javascript che ci toglie le castagne dal fuoco e mette in pista in un attimo il nostro lavoro. Il codice da scrivere è veramente ridotto all’osso, vi riporto l’esempio che faceva al caso mio con l’embedd del player flash di livestream.com (una piattaforma di streaming video):

  1. Includere la libreria nel tag <head>:
    <script type="text/javascript" src="swfobject.js"></script>
  2. Creare il div che ospiterà l’oggetto flash:
    <div id="livestreamPlayer"></div>
  3. Creare l’oggetto con il codice javascript:
    <script type="text/javascript">
    	flashvars = { channel: 'livestreamearth' };
    	params = { AllowScriptAccess: 'always' };
    	swfobject.embedSWF("http://cdn.livestream.com/chromelessPlayer/wrappers/
    SPlayer.swf","livestreamPlayer", "400", "300", "9.0.0", "expressInstall.swf",
    flashvars, params);
    </script>

Come si può intuire la variabile flashvars conterrà le variabili di cui l’oggetto flash necessita per funzionare mentre params conterrà i settaggi flash per l’oggetto. Il primo parametro è invece il path dell’oggetto flash da embeddare, il secondo è l’id del div che lo conterrà nella nostra pagina, seguito da width e height, versione di flash richiesta e oggetto flash(fornito insieme ad swfobject) che consente di aggiornare la propria versione di flash installata sul pc.

Con questi semplici passi si otterrà il caricamente dell’oggetto flash tramite javascript, che consentirà di bypassare il blocco di alcuni browser e di eseguirlo senza problemi in tutti gli altri ;-).

Eccovi il link per scaricare lo zip contenente swfobject: http://bit.ly/3GWdi6

<script type="text/javascript" src="swfobject.js"></script>

[ad]

WordPress come CMS!

Come alcuni di voi già sanno, ultimamente, a lavoro, mi sono dovuto immergere all’interno del codice di wordpress. Bene, devo dire che ero un po’ perplesso, ma ho voluto sperimentare e provare lo stesso…

Al contrario di quanto pensassi, il codice di un tema è molto intuitivo e comprensibile. Basta masticare un po’ di CSS e un po’ di PHP. Se volete provare, potete scaricare questo tema. Io sono partito da qui e ho seguito la guida di worldpress.it.

La cosa più interessante è che wordpress può essere utilizzato anche come Content Mangement System (CMS). Alcuni ne sconsigliano questo tipo di utilizzo, mentre altri lo promuovono… Da parte mia devo dire che ci sono i pro e i contro, e ovviamente vi sconsiglio di utilizzarlo se dovete realizzare un sito complesso, che deve gestire parecchi utenti o situazioni complesse(e-commerce, per fare un esempio). Però wordpress permette di gestire pagine, e con semplici funzioni (le trovate tutte in questa guida ufficiale) potete accedere e personalizzare tutti i vostri contenuti. E allora qual’è il vantaggio nell’usare wordpress? Ovviamente tutta la gestione dei contenuti già fatta(memorizzati su database mysql) e la rapidità di “costruzione” del sito web. Devo ammettere che in 2 giorni si possono realizzare siti web decenti (se non ci si fossilizza troppo sul layout grafico).

Quasi sicuramente lo utilizzerò altre volte, e soprattutto quando si devono realizzare siti standard e pronti “in pochi minuti”, allora potrebbe essere la soluzione giusta, a differenza di Joomla, Drupal o quant’altro che potrebbero risultare un po’ complicati (in fase di personalizzazione del codice). Che dire, se lo provate, buon divertimento!
[ad]

Un calendario con jquery!

Sono ormai diventato un jquery addicted e per ogni problema trovo una soluzione in questo fantastico framework javascript…

L’altro giorno sul lavoro dovevo realizzare una maschera di input con alcuni filtri su una ricerca… Uno di questi filtri era proprio una data di inizio e data di fine… Siccome la pagina (jsp) era rivolta ad impiegati di un ufficio(che non sempre sono good user) mi è stato chiesto di realizzare un calendario per permettere una scelta di date…

Ovviamente la prima cosa che ho fatto è stato googleggiare cercando “calendar jquery”… il primo risultato mi ha rimandato a questa pagina dove ho trovato in pochi e semplici passi alcuni file (un js e un css) da scaricare e da includere nel mio progetto(che comprendeva già jquery). E così che con 1 istruzione

$("#idtextbox").datepicker({"dd/mm/yy"});

ho risolto il mio problema..
Ecco a voi un semplice esempio (del tutto identico a quello che ho utilizzato io ;-):


[ad]

Java Sharp!

Da venerdì scorso mi sono buttato sul C#, un nuovo linguaggio (per me), che poi ho scoperto che tanto nuovo non è…

Dovevo iniziare un’applicazione che facesse una scansione di una cartella su un server alla ricerca di file .zip. Trovati questi file, bisogna leggere dei file .dat che contengono delle chiavi con cui recuperare dati da un database. Fatto ciò  si devono inviare gli zip ad un server ftp remoto e backuppare i file sul server. Interessante no? Il tutto era da fare in .net, per cui mi sono subito messo a googleggiare e ho trovato del codice abbastanza completo sul trasferimento ftp. Guardo bene… Ehi ma questo è Java… No C#…Ok proviamolo! Programma che ti programmi (?? :O) sono sempre più convinto che Microsoft non si smentisca, e abbia copiato un’altra volta… Qualcuno mi fa capire che differenze ci sono tra Java e C#? Altrimenti per me quello diventa Java Sharp![ad]