Personal tools

November

Nov 29, 2011

Stati Generali dell'Innovazione: perché abbiamo voluto esserci

Filed Under:

L'evento di Roma conferma nel modo migliore le grandi speranze con cui RedTurtle ha aderito a SGI: siamo parte attiva del "blocco socio-culturale dell'innovazione", che si pone a disposizione del Governo Monti e di quelli che lo seguiranno

Banner SGI

Innovazione: come?

Senza un approccio organico e inclusivo, innovazione diventa una parola vuota

L'innovazione a macchia di leopardo, l'innovazione che riparte sempre da zero, l'innovazione "a modo mio", l'innovazione non innovativa. E ancora: l'innovazione "ingessata", l'innovazione fuori contesto, l'innovazione a parole, l'innovazione chiusa, l'innovazione irripetibile, l'innovazione (solo) dei soliti noti, l'innovazione pre-elettorale, l'innovazione con barriera di ingresso. C'è altro? L'innovazione a fuga in avanti, l'innovazione senza Legge, la Legge senza innovazione, l'innovazione inapplicabile, l'innovazione sovranormata e quella sottonormata, l'innovazione settoriale o di casta, e potrei continuare.

Fin qui la rassegna delle storture osservabili non solo qui in Italia, ma in particolare nel nostro Paese. Un'innovazione spesso solo parlata, spesso polverizzata in iniziative magari eccellenti, ma tuttora alla ricerca di una visione di assieme, di un sistema, di una strategia, di una cabina di regia.

Ecco come!

Per correggere questo stato di cose, per valorizzare un talento che il mondo ci riconosce proprio nel creare e innovare sul piano tecnico, organizzativo e culturale, nasce l'associazione Stati Generali Innovazione, cui RedTurtle ha aderito dal primo istante, portando un importante contributo al gruppo di lavoro che si occupa in particolare di Pubblica Amministrazione. I nostri valori sono la natura di PMI, il sapere sul software libero, il patrimonio di esperienze e best practices dei nostri Clienti, ben rappresentato da PloneGov Italia.

SGI Cloud Tag

Dal documento del Gruppo di Lavoro Open Government:

"...consapevole del valore delle esperienze di innovazione già in essere, l’Associazione intende censire ed aggregare tali esperienze, riconducendole a un unica visione multipolare, condivisa, armonica, coordinata, saldamente radicata nel contesto normativo esistente."

Gli Stati Generali (SGI) nascono per iniziativa dei più importanti poli di innovazione reale nel Paese (la lista dei promotori  è realmente impressionante), di rappresentanze di tutte le categorie di stakeholder (Pubblica Amministrazione, Industria, Accademia, Ricerca, Terzo Settore) e sono aperti all'adesione di singoli, aziende e associazioni.

Paradosso: i governi che si sono succeduti nel tempo, hanno intrapreso le loro politiche di innovazione senza coinvolgere tutte le realtà innovative per missione, competenze e filosofia, senza censirle, aggregarle e valorizzarle: spesso si sono limitati a nomine con criteri di contiguità partitica, spesso hanno affossato anziché valorizzare quanto fatto in precedenza, sempre è mancato il momento "sistemico" di aggregazione degli stakeholder.

Modus operandi

"...Tale struttura di liberi saperi sarà gestita strutturando (con criteri trasparenti) una Consulta Permanente super partes e qualificata, partecipata dagli stakeholder dell’innovazione, che divenga il naturale referente delle istituzioni innovative della PA, e che sappia fornire linee guida, per evitare gli errori del passato ed orientare le future scelte in un approccio multidisciplinare al tema dell’innovazione."

In SGI si è partiti da subito con il piede giusto, a cominciare dalla connotazione "a-partisan" fortemente voluta dal Presidente Flavia Marzano e dagli altri fondatori. L'evento costitutivo dello scorso fine settimana, oltre a confermare le migliori impressioni maturate nelle settimane di lavoro che lo hanno preceduto, ha offerto al mondo un'immagine confortante della combinazione di voglia e capacità di cambiare, e un senso di fiducia per la coincidenza nel tempo tra la disponibilità di queste forze coese, una crisi da risolvere, e un nuovo governo tecnico, interlocutore predestinato per SGI.

Ponendosi a disposizione del Paese sia per definire una serie di interventi immediati a costo basso o nullo, sia per portare avanti nel tempo la propria piattaforma programmatica distillato delle migliori competenze del mondo reale, SGI si candida a rivestire un ruolo chiave.

Impressioni

Personalmente, ho atteso l'evento con le aspettative accumulate in alcune settimane di collaborazione (un po' in remoto, un po' in presenza) al Gruppo di Lavoro per l'innovazione nella PA. Tutto è fluito ragionevolmente  liscio, con l'aula magna di Università Roma 3 a fare da cornice.

Università Roma Tre

Critiche soprattutto costruttive, proposte e una confortante rispondenza tra le linee di azione di SGI e le esigenze e opportunità evidenziate dai relatori. Gli SGI *sono* la soluzione che serve

Più che fare una telecronaca (il programma è stato rispettato con modeste sbavature, tipiche di una "prima" molto affollata), mi importa confermarvi che il clima costruttivo e partecipato che si è respirato in Aula Magna è proprio quello che Flavia descrive sul suo blog.

Il Venerdì, più istituzionale e strutturato, integralmente trasmesso in webcast su www.statigeneralinnovazione.it, ha visto succedersi relatori di alto profilo, e a fine mattinata anche parlamentari, ognuno a portare il proprio contributo sul tema sotto una pioggia incessante di tweet che scorrevano sullo schermo alle spalle del palco, alcuni ripresi in tempo reale dai moderatori per stimolare i relatori.

Al pomeriggio, le sessioni parallele hanno consentito di riaprire il dialogo tra i gruppi di lavoro e la base dell'Associazione per discutere gli specifici position paper.

Pubblico di venerdì

Il Sabato mattina, arricchito dal contributo di ascolto e proposta di Mario Campolargo (Responsabile EC "Emerging Technologies and Infrastructures") e Franco Accordino (EC, Task Force Digital Futures), in teleconferenza da Bruxelles per parlare di Agenda Digitale Europea, ha culminato nel dibattito necessario per confezionare in modo sintetico la piattaforma da offrire all'interlocuzione con il Governo, che (senza negare l'obiettivo chiave di SGI, collaborare a tempo pieno con il sistema-Paese) si è deciso, tanto per iniziare, di basare su una proposta di otto azioni immediate e a costo tendente allo zero.

Noi e gli Stati Generali

RedTurtle, sponsor dell'iniziativa,  si è accreditata come portatrice di forti competenze e di utili esperienze sul software libero: la nostra posizione aziendale si è manifestata nei contributi che ho offerto alla discussione, alcuni dei quali integrati nel Position paper del gruppo Open eGovernment e nel documento finale, e certamente intendiamo anche in futuro porre a disposizione di SGI la nostra competenza e la nostra visione.

Ci si è lasciati con una collaborazione ancor meglio avviata e numerosi compiti a casa, sul cui svolgimento gli Stati Generali intendono usare la stessa congenita trasparenza e apertura mostrata fin dall'inizio.

Seguiteci e coinvolgetevi!

Nov 23, 2011

Agile day - Roma, 19 novembre 2011

Filed Under:

Diario agile di una giornata agile. Riflessioni a fine giornata dell'evento Agileday di Roma che ci ha visto piacevolmente coinvolti in compagnia di colleghi e amici

Ore 19:30 di sabato. In treno, di ritorno dalla giornata agile di Roma...

"dai Nicola, scrivi il post!"
"(...)"

spritzGià, lo capisco. Ci sono cosi tante cose da raccontare  e uno spritz di happy ending da smaltire :-)

Una signora seduta di fronte a noi ha appena esclamato "siete mitici!" dopo aver condiviso la nostra euforia e le nostre gag da agilisti dell'ultima ora.

Nel mentre passa accanto al nostro sedile il Taz che intima a Max di smettere di twittare ogni tre secondi la cronaca in tempo reale dei nostri spostamenti... è la sindrome dell'agilista sociale (una mutazione del morbo agilista difficilmente curabile con le terapie convenzionali).

Raccontare i singoli talk a cui abbiamo assistito sarebbe riduttivo. Basta una facile ricerca su twitter di #iad11 per rendersene conto (il topic è stato tra le hit di twitter della mattina). 

Twitter... Una vera magia: in presenza di quattro track parallele ti consente di seguirne fisicamente una e partecipare alle altre tre

Benissimo, i miei compagni di viaggio mi stanno offrendo un altro modo per raccogliere gli appunti sparsi di oggi... Provo a catturare alcuni frammenti di conversazione.

Max chiede a Ste di spiegare il business model di RT in 30 secondi (Un po' alla "Startup senza falldown" del mattino). 30 secondi ?! Ardua impresa. 

Ecco che viene riproposto anche qualche accenno del talk di @ziobrando (Volevo solo scrivere codice), nostalgico e velatamente malinconico. Una sua citazione che merita di essere tramandata ai posteri è:

Dopo un metodo di 1500 righe non devi mettere la parentesi graffa ma "e vissero tutti felici e contenti" @paolopolce #iad11

Io potrei parlare di "varchi attivi", "panini freschi" e "tomtom diabolici" per ricordare il talk di @yvonnebindi (L’usabilità delle parole).

spritzStefano ricorda Spaghetti DevOps, Overcoming self-organization blocks e Kanban = Pillola Viola.
Nicola invece non manca di segnalarci Capire e gestire il debito tecnico e La professione dello sviluppatore.
Max chiude il cerchio con il talk su eXtreme Programming, Timeboxing and Kanban e quello del "commerciale agile".

Ok, Nicola ha iniziato a parlare di python, javisti e ide... La signora del sedile di fronte credo abbia dato forfait. L'indole dei satanici programmatori sta prendendo il sopravvento.

Il tempo di un pomodoro e dal sedile accanto non proviene più alcun segno di vita... Ops! Morfeo (o lo spritz della foto) ha avuto il sopravvento! La signora è salva.

cenaDel resto la sveglia alle 3:30 di stamattina è stata tutt'altro che agile. Son serviti 4 caffè per arrivare fin qui e almeno un altro si renderà necessario dopo la cena (agile anch'essa) che ci aspetta a Bologna con gli amici che non hanno potuto partecipare.

Torniamo stanchi ma decisamente arricchiti di esperienze, condivisioni e tanta energia. Maaaaa... mi chiedo: gli agilisti sono esseri umani comuni che hanno visto la luce (come il nostro Nicola stamattina alle 5:30 al bar quando un semplice faretto acceso ha avuto ai suoi occhietti stretti dal sonno l'effetto di un'apparizione mistica) o sono una nuova razza di New Type di Gundamiana memoria? 

Un giorno, forse, troverò anch'io La Risposta.

See you all'Agile Day 2012!

  • attori protagonisti: @massimoazzolini, @nicolasenno, @stemrc, @nekorina
  • attrice non protagonista: la signora del sedile di fronte
  • attori non protagonisti: @bettazzoni, @ziobrando, @ilbonzo, @gaunilone, @guandalf, @yoghi
  • guest star: la bimba di 10 anni (a occhio) che ha seguito tutti i talk della giornata
  • premio della critica: all'ottima organizzazione romana (e non) dell'intero Agile Day, ai relatori, ai reporter (twitters... si dice cosi?) e alla torta alle spezie del buffet di rinfresco!

Se vuoi vedere foto dell'evento, vai al nostro album su Facebook.

Nov 18, 2011

Modulistica PDF online: popolamento automatico via Python

Filed Under:

Un suggerimento per aggiungere testo a un file pdf comune, come ad esempio un banale modulo del censimento, utilizzando alcune delle librerie Python in circolazione

La creazione di pdf è spesso richiesta quando si sviluppa un'applicazione. Ma ci dobbiamo destreggiare in un mare di librerie Python

Per lo sviluppo di un'applicazione mi sono trovata a dover generare un pdf il cui contenuto consiste in un modulo, ad esempio il modulo del censimento, compilato con i dati degli utenti dell'applicazione presi run-time dal sistema.

Avrei impiegato troppo tempo a disegnare il modulo insieme ai dati dell'utente, in più, per certi moduli (come il modulo censimento) sono già forniti i pdf.

Pensare di caricare il modulo come immagine di sfondo non è fattibile. Prima di tutto per la qualità scarsa del pdf finale e poi perché le dimensioni del file di output aumentano molto a causa dell'immagine usata come sfondo.

Il file da ottenere è un modulo già fornito in versione pdf, ma a cui ho bisogno di aggiungere testo.

La soluzione, a mio avviso migliore, è stata quella di usare ReportLab per disegnare un pdf fatto unicamente dei dati dell'utente per poi fare un merge del primo con il pdf contente il modulo, usando PyPDF.

L'unica difficoltà in questo approccio è creare il pdf contenente i dati di riempimento. Infatti questi dati devono essere nella posizione giusta, prioprio come se stessimo compilando il modulo.

La soluzione è: merge e righello alla mano

Per superare questo ostacolo agilmente ho usato uno screen ruler. Io ho preferito "Free Ruler" per Mac OS X tra i vari righelli che ho trovato in rete, soprattutto per il suo tick mark interattivo che permette di fare una misura abbastanza accurata.

Ho aperto il pdf con il modulo da compilare, e poi ho misurato con il righello i punti in cui inserire i dati. Per creare il pdf con i dati di riempimento ho usato ReportLab che consente di scrivere stringhe di testo in un punto esatto, utilizzando le coordinate x e y.

Ecco la MIA ricetta

Passo 1

Aprire il pdf che rappresenta la base del nostro impasto, ovvero  il modulo da compilare, usando la classe PdfFileReader di pyPdf.

import codecs
from pyPdf import PdfFileWriter, PdfFileReader

input1 = PdfFileReader(codecs.open(path_modello_censimento, "rb"))

 

Passo 2

Preparare il pdf con i nostri canditi: i dati di riempimento. Qui entra in gioco ReportLab.

import StringIO
from reportlab.pdfgen import canvas
from reportlab.lib.units import cm

packet = StringIO.StringIO()
can = canvas.Canvas(packet)
...
textobject = can.beginText()
textobject.setTextOrigin( 11.94*cm, 20.12*cm)
textobject.textLine('hello world')
...
can.drawText(textobject)
can.showPage()
can.save()
packet.seek(0)

Come unità ho usato i centrimenti, sia nel fissare l'origine di ogni striga di testo inserita, sia quando ho misurato con il righello. 11.94 e 20.12 sono due esempi di coordinate.

Tenere presente che l'orgine si trova in basso a sinistra. Ma con l'istruzione seguente possiamo spostare l'orgine in alto.

can.translate(cm, cm)

 

Passo 3

Aprire il pdf creato sopra con PdfFileReader.

input2 = PdfFileReader(packet)

 

Passo 4

Aprire il pdf finale, che conterrà il merge dei due pdf precedenti con la classe PdfFileWriter di pyPdf.

output = PdfFileWriter()

 

Passo 5

Adesso la parte più divertente: "Impastare".

page0 = input1.getPage(0)
page0.mergePage(input2.getPage(0))
output.addPage(page0)

Dopo aver unito i due pdf pagina per pagina si arriva finalment al punto 6..

Passo 6

Adesso abbiamo il nostra risultato finale "output" che può essere memorizzato ovunque si voglia, io lo scrivo in un file temporaneo per completare l'esempio:

import tempfile
temp_file_name = tempfile.mktemp()
outputStream = codecs.open(temp_file_name, mode="wb")
output.write(outputStream)
outputStream.close()
os.unlink(temp_file_name)

 

L'elaborazione richiede un po' di tempo, ma il risultato finale è buono. Buon appetito!

Nov 10, 2011

PloneConference 2011: novità e conferme

Di ritorno da San Francisco, ecco le anticipazioni e le conferme di cui abbiamo discusso durante una delle ultime best conference ever

Ancora una volta: "the best conference... ever" (cit.)
Tre track parallele, numerosi openspace, meeting in e out la conference, social party(!) ogni sera e per finire l'usuale sprint

Le 3D, ma molto altro

Il leitmotif di quest'anno è stato senz'altro il tris di Diazo, Deco e Dexterity. E' già un po' di tempo che se ne parla e non vi nascondo un po' di delusione nel vedere che sono ancora temi importanti.

Il punto cruciale sta nel fatto che negli anni passati è stata tentata una rivoluzione, che avrebbe però avuto un impatto troppo importante su tutto l'ecosistema Plone. Questo ha portato a una serie di complicazioni e di refactoring.

Ora si sta ragionando in termini di add-on per Plone che ne migliorino l'esperienza, senza introdurre stravolgimenti.

Diazo & CMSUI

E' ormai un sistema maturo utilizzato in produzione da molto tempo.

L'idea è di:

  1. semplificare la fase di skinning di Plone limitandola al frontend, più facilmente gestibile da Diazo,
  2. demandare a CMSUI tutta la fase di gestione del backend mantenendo il tutto contestuale, ma indipendente dal layout.

Direi che questi due video da soli sono sufficientemente esplicativi.

Diazo Theme Manager:

CMSUI:

Deco

Sta raggiungendo anche lui la maturazione e si sta lavorando sulla user experience. L'idea in questo caso è quella di sostituire prodotti come PortletPage

o Collage. Questa una preview realizzata dai colleghi di FourDigits.

Dexterity

Sugli scudi infine anche Dexterity, di cui parlammo ancora due anni fa come promessa e che ora sta raggiungendo il suo compimento. Sull'interfaccia c'è ancora da lavorare e non è uno strumento per tutte le stagioni, ma è sicuramente estremamente interessante.

Gli altri temi caldi

I miei talk preferiti sono stati:

  • Clone to Plone
  • Multiplayer Plone
  • Make plone search work like Google

Il primo racconta l'utilizzo di FunnelWeb per migrare portali da un altro sistema a Plone.

Nota mentale: ogni migrazione è un'isola, ogni migrazione è "painful"

Il secondo è stato tenuto da Geir Baekholt su istigazione di Yiorgis Gozadinos e permette di utilizzare Plone un po' alla GoogleDocs con tanto di chat e status:

 

Infine l'uso di Solr al fine di ottimizzare gli indici permette anche di aumentare le funzionalità "googlesche" di Plone:

 

Pyramid

La track "Related Tech" è stata fortemente monopolizzata da Pyramid. E' la tecnologia "sorella" di Plone che abbiamo sposato da tempo. Ne abbiamo parlato qui, qui e anche qui. Senza contare il talk di Andrew che ormai è un bestseller alle varie conferenze.

Pyramid è in diretta concorrenza con Django (framework di cui viceversa non si è parlato). E' da sottolineare il fatto che praticamente tutti i Plonisti a S. Francisco avessero fatto la stessa scelta e questo ci conforta sapendo di aver scelto a suo tempo nel modo corretto, ma soprattutto di essere in buona compagnia.

Il Keynote

Quest'anno l'usuale keynote è stato tenuto da P.J. Onori. Personalmente l'ho trovato di particolare ispirazione: è un inno alla crescita professionale, al capire l'usabilità delle cose, alla condivisione di esperienze tra developer e designer.

Più volte mi sono ritrovato a dire "si! si! si!".

 

I nostri talk

Avrete modo di leggere di più nei prossimi giorni sui talk (e lighting talk) di Andrew e Stefano. Mi limito a segnalarvi le presentazioni:
  • Bootstrap your app in 45 seconds (slideshare)
  • Plone in the Public Sector: Business and Sustainability Models (slideshare)

Nov 04, 2011

Image handling personalizzato negli AT

Un'applicazione mobile e la necessità di usare un certo formato immagine mi hanno spinto a capire come Plone gestisca la creazione delle immagini scalate e come ci si può inserire nel processo per fare delle personalizzazioni

Il caso d'uso

Lo sviluppo di una applicazione mobile che deve mostrare una lista di eventi ha fatto sorgere la necessità di avere un formato di immagine piccolo (facile con Plone), quadrato (mmhm...) e senza distorsioni dell'immagine (ok, non ci siamo): qualora l'immagine non fosse quadrata, la si dovrà "croppare".

Il comportamento standard IN plone

Plone base non fornisce la possibilità di prendere una immagine qualsiasi e restituirla in un formato miniaturizzato e sicuramente quadrato.

Prendiamo, ad esempio, questa immagine:

python_img

Immagine originale di dimensione 200x150

Agendo sulle funzionalità standard di plone, andiamo in ZMI nelle 'portal_properties/image_properties' del nostro sito, e aggiungiamo fra le 'allowed_size' una 'custom_size 100:100'; poi possiamo verificare caricando l'immagine (ha dimensione 200x150) che se chiamiamo sull'oggetto 'image_custom_size', ci viene tornata un'immagine 100x75:

python_img

Immagine ridimensionata con il comportamento standard di Plone

L'immagine è stata scalata in proporzione, non è questo che vogliamo! E quindi?

Studiamo la situazione

La prima domanda che è lecito e doveroso farsi è: 

Cosa succede quando facciamo traversing su un oggetto usando come attributo da "attraversare" uno degli scaling disponibili per le immagini?

Stiamo lavorando su Plone 4 e indagando un poco si scopre che è stato registrato un adattatore per gestire il traversing in caso di immagini dentro a plone.app.imaging:

class ImageTraverser(DefaultPublishTraverse):
    """ traversal adapter for scaled down versions of image content """
    adapts(IBaseObject, IRequest)

    def fallback(self, request, name):
        return super(ImageTraverser, self).publishTraverse(request, name)

    def publishTraverse(self, request, name):
        schema = self.context.Schema()
        if '_' in name:
            fieldname, scale = name.split('_', 1)
        else:
            fieldname, scale = name, None
        field = schema.get(fieldname)
        handler = IImageScaleHandler(field, None)
        if handler is not None:
            image = handler.getScale(self.context, scale)
            if image is not None:
                return image
        return self.fallback(request, name)
   

 

All'interno di questo adapter abbiamo il metodo publishTraverse da cui partire e un metodo che si occupa del fallback al traverser di default nel caso non si stia lavorando allo scaling delle immagini.

Inoltre, se si lavora allo scaling delle immagini, si chiama un altro adapter (IImageScaleHandler) che fornirà i metodi per creare l'oggetto con l'immagine ridimensionata:

handler = IImageScaleHandler(field, None)
if handler is not None:
   image = handler.getScale(self.context, scale)
   if image is not None:
      return image

La soluzione

Ok, è sufficiente. Abbiamo tutto quello che ci serve sapere! Come nella maggior parte dello sviluppo che si fa per Plone/Zope, la Zope Component Architecture permetterà di fare tutto in modo relativamente veloce.

Io sto lavorando con delle immagini in un archetype customizzato, per cui la cosa più semplice da fare per me sarà registrare un adapter più specifico per l'interfaccia del mio tipo, ma possiamo banalmente proseguire l'esempio registrandone uno per IATImage:

class MyImageTraverser(DefaultPublishTraverse):
    """ traversal adapter for scaled down versions of image content """
    adapts(IATImage, IRequest)
    
    def fallback(self, request, name):
        ...
    def publishTraverse(self, request, name):
        ...

 

Ora abbiamo il traverser per gli oggetti che implementano IATImage, e siamo già a metà del lavoro. Il successivo e ultimo passo sarà applicare la trasformazione vera e propria. 

Come abbiamo già avuto modo di vedere, si richiama un handler nel traverser che si occupa di ottenere l'immagine scalata. Quello che possiamo fare è registrare un nostro handler personalizzato per il field che contiene l'immagine; magari chiamare un handler personalizzato in modo condizionato, per gestire soltanto i casi che ci interessano; qualcosa come:

if scale in crop_and_scale:
    handler = ICustomImageScaleHandler(field, None)
else:
    handler = IImageScaleHandler(field, None)

 

L'handler originale si trova in plone.app.image, nello stesso modulo del traverser; analizzando il codice ci si rende conto che se nel sistema è presente plone.app.blob, di default, si userà il BlobImageScaleHandler presente in quest'ultimo pacchetto. 

Noi potremo creare un handler personalizzato come adapter sul field che si usa per contenere l'immagine, e essendo presente plone.app.blob, lo creeremo ereditando dalla classe BlobImageScaleHandler.

All'interno dell'handler, ci sono tutti i metodi per ottenere l'immagine scalata.

Per raggiungre il nostro obiettivo, ereditando dal BlobImageScaleHandler, possiamo scrivere un handler personalizzato che conterrà un unico metodo, createScale: l'unico che ci serve personalizzare. Qui potremo applicare le trasformazioni necessarie. Il metodo originale esegue i seguenti passi:

def createScale(self, instance, scale, width, height, data=None):
    """ create & return a scaled version of the image as retrieved
        from the field or optionally given data """
    field = self.context
    if HAS_PIL and width and height:
        if data is None:
            image = field.getRaw(instance)
            if not image:
                return None
            data = str(image.data)
        if data:
            id = field.getName() + '_' + scale
            try:
                imgdata, format = field.scale(data, width, height)
            except (ConflictError, KeyboardInterrupt):
                raise
            except Exception:
                if not field.swallowResizeExceptions:
                    raise
                else:
                    exception('could not scale ImageField "%s" of %s',
                        field.getName(), instance.absolute_url())
                    return None
            content_type = 'image/%s' % format.lower()
            filename = field.getFilename(instance)
            return dict(id=id, data=imgdata.getvalue(),
                content_type=content_type, filename=filename)
    return None

 

Per fare la modifica, nell'handler personalizzato potremo cambiare questa riga

imgdata, format = field.scale(data, width, height)

 

con quello che fa più comodo, e usando il crop delle PIL potremo trasformare l'immagine come necessario, arrivando a un risultato come questo.

python_quad

Immagine ridimensionata e croppata fino alla dimensione 100x100