Your SlideShare is downloading. ×
0
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Django: utilizzo avanzato e nuove funzionalità
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Django: utilizzo avanzato e nuove funzionalità

4,914

Published on

Django è uno dei framework web più apprezzati e utilizzati dalla comunità Python (e non solo). …

Django è uno dei framework web più apprezzati e utilizzati dalla comunità Python (e non solo).

I suoi punti di forza sono rappresentati dal suo utilizzo rapido e intuitivo, l'ottima documentazione e una larga comunità di sviluppatori ed utilizzatori.

A più di un anno di distanza dal rilascio della versione 0.96 le feature e i miglioramenti introdotti sono stati molti.

La presentazione mostra alcune di queste novità e l'utilizzo avanzato di alcuni componenti del framework.

Published in: Technology
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
4,914
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
56
Comments
0
Likes
2
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide
  • Theme created by Sakari Koivunen and Henrik Omma Released under the LGPL license.
  • Transcript

    • 1. Django Utilizzo avanzato e nuove funzionalità
    • 2. Perchè utilizzare django? <ul><li>Tempi di sviluppo ridotti </li></ul><ul><li>Scalabilità e performance </li></ul><ul><li>Ottima documentazione, comunità attiva e partecipe </li></ul><ul><li>Motore di templating semplice e adatto ai designer di pagine HTML </li></ul><ul><li>URL puliti e SEO-friendly </li></ul><ul><li>Python powered! </li></ul>
    • 3. Perchè utilizzare la versione trunk? <ul><li>1 anno dall'ultima release stabile (0.9.6)‏ </li></ul><ul><li>Supporto unicode </li></ul><ul><li>Cambiamenti dell' API </li></ul><ul><li>Nuove funzionalità </li></ul>
    • 4. Utilizzo della versione trunk <ul><li>Installazione da sorgenti </li></ul><ul><li>$ cd /path/to/packages </li></ul><ul><li>$ svn co http://code.djangoproject.com/svn/django/trunk Django </li></ul><ul><li>$ python setup.py install </li></ul><ul><li>Utilizzo senza installazione </li></ul><ul><li>$ export PATH=$PATH:/path/to/Django/bin </li></ul><ul><li>$ export PYTHONPATH=$PYTHONPATH:/path/to/packages/Django </li></ul>
    • 5. Supporto unicode: gestione delle stringhe <ul><li>Django assume che tutte le bytestring siano in UTF-8 , in caso contrario l'eccezione UnicodeDecodeError verrà sollevata </li></ul><ul><li>La variabile di configurazione DEFAULT_CHARSET viene utilizzata solo per il rendering dei template e dei messaggi e-mail </li></ul><ul><li>Le stringhe di traduzione “lazy” possono essere convertite direttamente in stringhe unicode </li></ul><ul><ul><ul><li>http://www.djangoproject.com/documentation/i18n/#lazy-translation </li></ul></ul></ul>
    • 6. Supporto unicode: funzioni di conversione <ul><li>django.utils.encoding.smart_unicode </li></ul><ul><ul><li>Converte una qualsiasi stringa in unicode </li></ul></ul><ul><li>django.utils.encoding.force_unicode </li></ul><ul><ul><li>Identica a smart_unicode, con la differenza che non preserva le stringhe di traduzione “lazy”, forzandone la traduzione e la conversione in unicode </li></ul></ul>
    • 7. Supporto unicode: URI e IRI <ul><li>Gli URL di tipo URI utilizzano solo caratteri ASCII. </li></ul><ul><li>La funzione iri_to_uri permette di costruire URL di tipo IRI (RFC 3987)‏ </li></ul><ul><ul><ul><li>http://www.ietf.org/rfc/rfc3987.txt </li></ul></ul></ul><ul><li>>>> from django.utils.encoding import iri_to_uri </li></ul><ul><li>>>> iri_to_uri(u'/locations/Rennes-le-Château')‏ </li></ul><ul><li>'/locations/Rennes-le-Ch%C3%A2teau' </li></ul>
    • 8. Supporto unicode: database <ul><li>Assicurarsi che il proprio database sia configurato per utilizzare l'encoding appropriato ( UTF-8, UTF-16 ) ‏ </li></ul><ul><li>Il database backend si occuperà di convertire automaticamente le stringhe unicode nell'encoding utilizzato dal database, e viceversa </li></ul><ul><li>È possibile passare stringhe unicode e bytestring UTF-8 ai metodi utilizzati per filtrare gli oggetti QuerySet </li></ul><ul><li>>>> Place.objects.filter(name__contains=u'Château')‏ </li></ul>
    • 9. Supporto unicode: modelli <ul><li>Le stringhe ottenute dai campi testuali dei modelli sono sempre di tipo unicode </li></ul><ul><li>Nel caso il vostro modello contenga un metodo __str__() può essere necessario implementare anche il metodo __unicode__()‏ </li></ul><ul><li>Se necessario, utilizzare la funzione iri_to_uri() nel metodo get_absolute_url()‏ </li></ul>
    • 10. Supporto unicode: template <ul><li>I template possono essere salvati sul filesystem utilizzando un charset diverso da UTF-8 , in tal caso è necessario definire la variabile di configurazione FILE_CHARSET </li></ul><ul><li>È consigliato l'utilizzo delle funzione force_unicode nella creazione di template tag </li></ul>
    • 11. Escape automatico dei template <ul><li>Qualsiasi variabile inserita nel contesto di un template viene convertita automaticamente utilizzando django.utils.html.escape </li></ul><ul><li>È stata introdotta con lo scopo di prevenire attacchi di tipo XSS (Cross-site scripting)‏ </li></ul><ul><li>Non è possibile disabilitare tale funzionalità globalmente </li></ul>
    • 12. Escape automatico dei template <ul><li>È possibile disabilitare l'escape automatico direttamente nei template {% autoescape off %} ... {{ entry.body }} ... {% endautoescape %} {{ entry.body|safe }} </li></ul>
    • 13. Escape automatico dei template <ul><li>È inoltre possibile disabilitare l'escape automatico nei template filter @register.filter def safefilter(value): # do something with value... return value safefilter.is_safe = True </li></ul><ul><li>template.Context accetta l'argomento autoescape template.Context({'foo': bar}, autoescape=False)‏ </li></ul>
    • 14. Modelli <ul><li>La classe LazyDate() è stata rimossa. È possibile utilizzare una funzione per l'argomento default from datetime import datetime from django.db import models from django.contrib.auth.models import User class Place(models.Model): name = models.CharField(max_length=100) description = models.TextField(blank=True) created = models.DateField(default=datetime.now) location = models.ForeignKey(Location)‏ author = models.ForeignKey(User)‏ </li></ul><ul><li>L'utilizzo dell'attributo maxlength è deprecato ed è stato sostituito da max_length </li></ul>
    • 15. Modelli <ul><li>I campi di tipo FloatField utilizzavano float per rappresentare numeri decimali a precisione fissa </li></ul><ul><li>È stato introdotto il campo DecimalField , che utilizza il tipo di dato decimal.Decimal per mantenere la precisione latitude = models.DecimalField(max_digits=8, decimal_places=6)‏ </li></ul><ul><li>FloatField non accetta più gli argomenti precedentemente utilizzati </li></ul>
    • 16. Modelli <ul><li>È stato recentemente aggiunto il supporto all'ereditarietà delle classi Model class Place(models.Model): name = models.CharField(max_length=100) description = models.TextField(blank=True) created = models.DateField(default=datetime.now) location = models.ForeignKey(Location) author = models.ForeignKey(User) class Restaurant(Place): has_bistecca_fiorentina = models.BooleanField()‏ </li></ul><ul><li>http://www.djangoproject.com/documentation/model-api/#model-inheritance http://code.djangoproject.com/wiki/QuerysetRefactorBranch </li></ul>
    • 17. URL patterns <ul><li>È ora possibile utilizzare la funzione url() per assegnare un nome a un determinato URL pattern from django.conf.urls.defaults import * urlpatterns = patterns('pycon2.places.views', url(r'^add/$', 'place_add', name='place_add'), url(r'^(?P<place_id>d+)/edit/$', 'place_edit', name='place_edit'), url(r'^(?P<place_id>d+)/delete/$','place_delete', name='place_delete') )‏ </li></ul>
    • 18. URL patterns: permalink <ul><li>Utilizzo nel metodo get_absolute_url() di un modello: from django.db.models import permalink def get_absolute_url(self): return ('place_detail', [str(self.id)]) get_absolute_url = permalink(get_absolute_url)‏ </li></ul>
    • 19. URL patterns: url template tag <ul><li><a href=”{% url place_add %}”>Add place</a> <a href=”{% url place_edit place.id %}”>Edit {{ place }}</a> <a href=”{% url place_delete place.id %}”>Delete {{ place }}</a> </li></ul>
    • 20. MEDIA_URL context processor <ul><li>La variabile di configurazione MEDIA_URL è ora disponibile per poter essere utilizzata nei template <img src=”{{ MEDIA_URL }}img/logo.jpg” alt=”logo” title=”logo” /> </li></ul>
    • 21. URL patterns: urlresolvers <ul><li>>>> from django.core.urlresolvers import reverse >>> reverse('place_add') '/places/add/' >>> reverse('place_edit', args=[1]) '/places/1/edit/' >>> reverse('place_delete', args=[1]) '/places/1/delete/' </li></ul>
    • 22. newforms <ul><li>Introdotta nella release 0.9.6 con lo scopo di sostituire la vecchia libreria di gestione dei form </li></ul><ul><li>Permette di semplificare la creazione dei form, la validazione dei dati ricevuti, l'utilizzo e la creazione di widget HTML personalizzati </li></ul><ul><li>django.forms è stata copiata in django.oldforms </li></ul><ul><li>Nella prossima release stabile django.newforms verrà rinominata in django.forms </li></ul>
    • 23. newforms <ul><li>Form </li></ul><ul><ul><li>Contiene i campi, riceve i dati, si occupa della loro validazione e del rendering in HTML </li></ul></ul><ul><li>Field </li></ul><ul><ul><li>Rappresenta un campo e si occupa della sua validazione </li></ul></ul><ul><li>Widget </li></ul><ul><ul><li>Rendering di un campo in HTML </li></ul></ul>
    • 24. newforms <ul><ul><li># pycon2.contacts.forms </li></ul></ul><ul><ul><li>from django import newforms as forms </li></ul></ul><ul><ul><li>class ContactForm(forms.Form): </li></ul></ul><ul><ul><li>name = forms.CharField(required=False, max_length=50)‏ email = forms.EmailField()‏ comment = forms.CharField(widget=forms.Textarea)‏ </li></ul></ul><ul><ul><li>Gli argomenti max_length e required vengono utilizzati per la validazione del campo “name” </li></ul></ul><ul><ul><li>L'argomento widget viene utilizzato per definire il tipo di widget utilizzato per l'output HTML </li></ul></ul>
    • 25. newforms <ul><li>I dati ricevuti vengono passati come primo argomento del costruttore della classe </li></ul><ul><li>È possibile verificare la validità dei dati ricevuti utilizzando il metodo is_valid()‏ </li></ul><ul><li>L'attributo errors è un dizionario contenente gli errori di validazione </li></ul><ul><li>Nella release 0.9.6 i dati del form, normalizzati a seconda dei tipi di campo, erano disponibili nell'attributo clean_data , che è stato rinominato in cleaned_data </li></ul>
    • 26. newforms <ul><li>>>> form = ContactForm() >>> form.is_bound False >>> form = ContactForm({'email': 'foo@bar.com '}) >>> form.is_bound True >>> form.is_valid() False >>> form.errors {'comment': [u'This field is required.']} </li></ul>
    • 27. newforms <ul><li>Per gestire gli upload è possibile passare request.FILES come secondo argomento nel costruttore della classe </li></ul><ul><li>Il metodo is_multipart() ritorna True se la classe contiene campi di tipo FileField </li></ul><ul><li>È possibile accedere al nome e al contenuto del file attraverso cleaned_data form.cleaned_data['fieldname'].content form.cleaned_data['fieldname'].filename </li></ul>
    • 28. newforms: esempio di utilizzo <ul><ul><li>from django.template import RequestContext </li></ul></ul><ul><ul><li>from django.template.loader import render_to_string </li></ul></ul><ul><ul><li>from django.shortcuts import render_to_response </li></ul></ul><ul><ul><li>from django.core.mail import mail_admins </li></ul></ul><ul><ul><li>from pycon2.contacts.forms import ContactForm </li></ul></ul><ul><ul><li>def contact(request, template='contacts/contact.html', email_template='contacts/contact_email.txt'): </li></ul></ul><ul><ul><li>if request.method == 'POST': </li></ul></ul><ul><ul><li>form = ContactForm(request.POST)‏ </li></ul></ul><ul><ul><li>if form.is_valid(): </li></ul></ul><ul><ul><li>message = render_to_string(email_template, </li></ul></ul><ul><ul><li>form.cleaned_data)‏ </li></ul></ul><ul><ul><li>mail_admins('contact request', message)‏ </li></ul></ul><ul><ul><li>else: </li></ul></ul><ul><ul><li>form = ContactForm()‏ </li></ul></ul><ul><ul><li>return render_to_response(template, {'form': form}, context_instance=RequestContext(request))‏ </li></ul></ul>
    • 29. Field e Widget personalizzati: CaptchaField <ul><ul><li># pycon2.contacts.forms </li></ul></ul><ul><ul><li>from django import newforms as forms </li></ul></ul><ul><ul><li>from pycon2.utils.captcha.fields import CaptchaField </li></ul></ul><ul><ul><li>class ContactForm(forms.Form): </li></ul></ul><ul><ul><li>name = forms.CharField(required=False, max_length=50)‏ </li></ul></ul><ul><ul><li>email = forms.EmailField()‏ </li></ul></ul><ul><ul><li>comment = forms.CharField(widget=forms.Textarea)‏ </li></ul></ul><ul><ul><li>captcha = CaptchaField()‏ </li></ul></ul>
    • 30. CaptchaWidget <ul><ul><li># pycon2.utils.captcha.fields </li></ul></ul><ul><ul><li>from django.newforms.util import flatatt </li></ul></ul><ul><ul><li>from django.utils.safestring import mark_safe </li></ul></ul><ul><ul><li>CAPTCHA_IMAGE = '''<div class=”captcha”><img src=”%s” alt=”captcha” /></div>''' </li></ul></ul><ul><ul><li>class CaptchaWidget(forms.TextInput): </li></ul></ul><ul><ul><li>def render(self, name, value, attrs=None): </li></ul></ul><ul><ul><li>captcha_url = reverse('captcha')‏ </li></ul></ul><ul><ul><li>image = CAPTCHA_IMAGE % captcha_url </li></ul></ul><ul><ul><li>if value is None: value = '' </li></ul></ul><ul><ul><li>final_attrs = self.build_attrs(attrs, type=self.input_type, name=name)‏ </li></ul></ul><ul><ul><li>attrs = flatatt(final_attrs)‏ </li></ul></ul><ul><ul><li>if value != '': </li></ul></ul><ul><ul><li>final_attrs['value'] = force_unicode(value)‏ </li></ul></ul><ul><ul><li>return mark_safe(u'%s<input%s />' % (image, attrs))‏ </li></ul></ul>
    • 31. CaptchaWidget: funzioni utilizzate <ul><li>django.newforms.util.flatatt </li></ul><ul><ul><li>Converte un dizionario in una stringa contenente gli attributi utilizzabili in un elemento HTML. I valori del dizionario vengono convertiti utilizzando la funzione django.utils.html.escape </li></ul></ul><ul><li>django.utils.safestring.mark_safe </li></ul><ul><ul><li>Funzione utilizzata per definire che la stringa passata come argomento è sicura per poter essere utilizzata nell'output HTML </li></ul></ul>
    • 32. CaptchaField <ul><ul><li># pycon2.utils.captcha.fields </li></ul></ul><ul><ul><li>from django.utils.translation import ugettext as _ </li></ul></ul><ul><ul><li>from pycon2.utils.captcha.middleware import </li></ul></ul><ul><ul><li>get_current_captcha </li></ul></ul><ul><ul><li>class CaptchaField(forms.CharField): </li></ul></ul><ul><ul><li>widget = CaptchaWidget </li></ul></ul><ul><ul><li>def clean(self, value): </li></ul></ul><ul><ul><li>captcha = get_current_captcha()‏ </li></ul></ul><ul><ul><li>if not captcha: </li></ul></ul><ul><ul><li>raise forms.ValidationError(_('You must enable cookies.'))‏ </li></ul></ul><ul><ul><li>if value != captcha: </li></ul></ul><ul><ul><li>raise forms.ValidationError(_('Incorrect! Try again.'))‏ </li></ul></ul><ul><ul><li>return value </li></ul></ul>
    • 33. Captcha middleware <ul><ul><li># pycon2.utils.captcha.middleware </li></ul></ul><ul><ul><li>try: </li></ul></ul><ul><ul><li>from threading import local </li></ul></ul><ul><ul><li>except ImportError: </li></ul></ul><ul><ul><li>from django.utils._threading_local import local </li></ul></ul><ul><ul><li>_thread_locals = local()‏ </li></ul></ul><ul><ul><li>def get_current_captcha(): </li></ul></ul><ul><ul><li>return getattr(_thread_locals, 'captcha', None)‏ </li></ul></ul><ul><ul><li>class CaptchaMiddleware(object): </li></ul></ul><ul><ul><li>def process_request(self, request): </li></ul></ul><ul><ul><li>captcha = None session = getattr(request, 'session', None) if session: captcha = session.get('captcha')‏ </li></ul></ul><ul><ul><li>_thread_locals.captcha = captcha </li></ul></ul>
    • 34. Captcha view <ul><ul><li># pycon2.utils.captcha.view </li></ul></ul><ul><ul><li>import Captcha </li></ul></ul><ul><ul><li>import cStringIO </li></ul></ul><ul><ul><li>from Captcha.Visual.Tests import PseudoGimpy </li></ul></ul><ul><ul><li>from django.http import HttpResponse </li></ul></ul><ul><ul><li>def captcha(request): ''' Visualizza un immagine captcha utilizzando PyCaptcha </li></ul></ul><ul><ul><li>''' </li></ul></ul><ul><ul><li>g = PseudoGimpy()‏ </li></ul></ul><ul><ul><li>s = cStringIO.StringIO()‏ </li></ul></ul><ul><ul><li>i = g.render()‏ </li></ul></ul><ul><ul><li>i.save(s, 'JPEG')‏ </li></ul></ul><ul><ul><li>request.session['captcha'] = g.solutions[0] </li></ul></ul><ul><ul><li>return HttpResponse(s.getvalue(), 'image/jpeg')‏ </li></ul></ul>
    • 35. Form preview <ul><li>Viene fornita un'applicazione per poter visualizzare l'anteprima di una classe form </li></ul><ul><ul><li>Il form viene visualizzato in formato HTML su una pagina web </li></ul></ul><ul><ul><li>I dati del form vengono validati </li></ul></ul><ul><ul><ul><li>Se il form non è valido, viene visualizzato con gli errori di validazione </li></ul></ul></ul><ul><ul><ul><li>Se il form è valido, viene visualizzato per conferma </li></ul></ul></ul><ul><ul><li>I dati del form di conferma vengono ricevuti da un hook definito dall'utente </li></ul></ul>
    • 36. Form preview # pycon2.contacts.preview import pprint from django.http import HttpResponse from django.contrib.formtools.preview import FormPreview from pycon2.contacts.forms import ContactForm class ContactFormPreview(FormPreview): def done(self, request, cleaned_data): # do something with cleaned_data... output = pprint.pformat(cleaned_data)‏ return HttpResponse(output, mimetype='text/plain')‏ contact = ContactFormPreview(ContactForm)‏
    • 37. Form preview <ul><li>Per visualizzare l'anteprima è sufficiente aggiungere un pattern nella propria configurazione degli URL ('^preview/contact/$', 'pycon2.contacts.preview.contact'), </li></ul>
    • 38. Form wizard <ul><li>È stata introdotta un applicazione che permette di creare form suddivisi su più pagine </li></ul><ul><li>L'applicazione si occupa di mantenere lo stato dei dati inseriti nei form fra una pagina e l'altra </li></ul><ul><li>Le istanze delle classi form vengono passate al metodo done()‏ </li></ul><ul><li>È possibile specificare i template da utilizzare definendo il metodo get_template()‏ </li></ul>
    • 39. Form wizard # pycon2.contacts.forms from django import newforms as forms from django.http import HttpResponseRedirect from django.contrib.formtools.wizard import FormWizard from django.core.urlresolvers import reverse class PollOne(forms.Form): name = forms.CharField()‏ email = forms.EmailField() job_position = forms.CharField()‏ LANGUAGE_CHOICES = ( ('python', 'Python'), ('ruby', 'Ruby'), ('perl', 'Perl'), ('php', 'PHP'), ) class PollTwo(forms.Form): languages = forms.MultipleChoiceField(choices=LANGUAGE_CHOICES)‏ preferred_language = forms.ChoiceField(choices=LANGUAGE_CHOICES)‏
    • 40. Form wizard # pycon2.contacts.forms class PollWizard(FormWizard): def done(self, request, form_list): form_data = [form.cleaned_data for form in form_list] # do something with form_data return HttpResponseRedirect(reverse('poll_done')) def get_template(self, step): '''Override default template “forms/wizard.html”''' return ['contacts/poll_%s.html' % step, 'contacts/poll.html'] # pycon2.contacts.urls from django.conf.urls.defaults import * from pycon2.contacts.forms import PollOne, PollTwo, PollWizard urlpatterns = patterns('', url(r'^poll/$', PollWizard([PollOne, PollTwo]), name='poll'), url(r'^poll/done/$', 'django.views.generic.simple.direct_to_template', {'template': 'contacts/poll_done.html'}, name='poll_done') )‏
    • 41. Form wizard {# templates/contacts/poll.html #} {% extends 'base_site.html' %} {% block title %} Poll - step {{ step }} of {{ step_count }} {% endblock %} {% block content %} <form action='.' method='POST'> <input type=&quot;hidden&quot; name=&quot;{{ step_field }}&quot; value=&quot;{{ step0 }}&quot; /> {{ form.as_p }} {{ previous_fields|safe }} <p> <input type=&quot;submit&quot; value=&quot;Submit&quot; /> </p> </form> {% endblock %}
    • 42. ModelForm <ul><li>Permette di creare una classe Form da un modello </li></ul><ul><li>Sostituisce le funzioni deprecate form_for_model() e form_for_instance() </li></ul><ul><li>Permette di modificare con facilità i campi generati automaticamente </li></ul>
    • 43. ModelForm <ul><li># pycon2.places.forms </li></ul><ul><li>from django import newforms as forms </li></ul><ul><li>from pycon2.places.models import Place </li></ul><ul><li>class PlaceForm(forms.ModelForm): </li></ul><ul><li>class Meta: </li></ul><ul><li>model = Place </li></ul><ul><li>exclude = ('created', 'author') </li></ul><ul><li>La classe interna Meta viene utilizzata per definire </li></ul><ul><ul><li>il modello da utilizzare </li></ul></ul><ul><ul><li>i campi da escludere </li></ul></ul>
    • 44. ModelForm <ul><li>Il costruttore della classe accetta l'argomento instance per definire l'istanza del modello da utilizzare </li></ul><ul><li>Il metodo save() ritorna l'istanza del modello </li></ul><ul><ul><li>accetta il parametro commit : se il suo valore è False il metodo restituisce un istanza non salvata </li></ul></ul><ul><ul><li>in tal caso il metodo save_m2m() deve essere utilizzato per poter salvare i dati delle relazioni many-to-many </li></ul></ul>
    • 45. ModelForm: esempio di utilizzo # pycon2.places.views @login_required def place_add(request, template='places/place_add.html'): if request.method == 'POST': form = PlaceForm(request.POST)‏ if form.is_valid(): place = form.save(commit=False)‏ place.author = request.user place.save()‏ return HttpResponseRedirect(place.get_absolute_url())‏ else: form = PlaceForm()‏ return render_to_response(template, {'form': form}, context_instance=RequestContext(request))‏
    • 46. ModelForm: esempio di utilizzo # pycon2.places.views @login_required def place_edit(request, place_id, template='places/place_edit.html'): place = get_object_or_404(Place, pk=place_id)‏ if request.method == 'POST': form = PlaceForm(request.POST, instance=place)‏ if form.is_valid(): form.save()‏ return HttpResponseRedirect(place.get_absolute_url())‏ else: form = PlaceForm(instance=place)‏ return render_to_response(template, {'form': form, 'place': place}, context_instance=RequestContext(request))‏
    • 47. newforms-admin <ul><li>Utilizza la libreria newforms , eliminando le dipendenze con oldforms </li></ul><ul><li>Disaccoppia le funzionalità dell'interfaccia di amministrazione dai modelli </li></ul><ul><li>Permette di personalizzare alcuni aspetti dell'interfaccia di amministrazione, fra cui: </li></ul><ul><ul><li>Definire widget personalizzati per i campi e modificarne gli attributi </li></ul></ul><ul><ul><li>Modificare i permessi sui singoli oggetti </li></ul></ul>
    • 48. newforms-admin: installazione <ul><li>Scaricare il branch e modificare la variabile d'ambiente PYTHONPATH http://code.djangoproject.com/svn/django/branches/newforms-admin/ </li></ul><ul><li>Modificare la propria configurazione degli URL from django.conf.urls.defaults import * from django.contrib import admin urlpatterns = patterns('', (r'^admin/(.*)', admin.site.root), )‏ </li></ul>
    • 49. newforms-admin: esempio di utilizzo # pycon2.places.models from django.contrib import admin class Place(models.Model): name = models.CharField(max_length=100) description = models.TextField(blank=True) created = models.DateField(default=datetime.now) location = models.ForeignKey(Location)‏ author = models.ForeignKey(User)‏ class Location(models.Model): name = models.CharField(max_length=100)‏ latitude = models.DecimalField(max_digits=8, decimal_places=6)‏ longitude = models.DecimalField(max_digits=8, decimal_places=6) # register models into admin site admin.site.register(Place) admin.site.register(Location)‏
    • 50. newforms-admin: esempio di utilizzo class PlaceOptions(admin.ModelAdmin): list_display = ('name', 'location', 'author') search_fields = ('name', 'description') def has_change_permission(self, request, obj=None): if obj: if request.user != obj.author: return False return super(PlaceOptions, self).has_change_permission(request, obj) class PlaceInline(admin.TabularInline)‏ model = Place extra = 5 class LocationOptions(admin.ModelAdmin): inlines = [PlaceInline] # register models into admin site admin.site.register(Place, PlaceOptions) admin.site.register(Location, LocationOptions)‏
    • 51. Contenttypes <ul><li>Applicazione basata sul modello ContentType , che contiene i seguenti campi </li></ul><ul><ul><li>app_label (nome dell'applicazione)‏ </li></ul></ul><ul><ul><li>model (nome del modello)‏ </li></ul></ul><ul><ul><li>name ( verbose_name di un modello)‏ </li></ul></ul><ul><li>Permette di creare delle relazioni generiche fra l' istanza di un modello e diverse altre istanze </li></ul><ul><li>Viene utilizzata in diverse applicazioni fra cui django.contrib.comments, django-tagging, django-voting etc. </li></ul>
    • 52. Contenttypes <ul><ul><li>>>> from django.contrib.contenttypes.models import ContentType </li></ul></ul><ul><ul><li>>>> place_type = ContentType.objects.get(app_label='places', </li></ul></ul><ul><ul><li>model='place')‏ </li></ul></ul><ul><ul><li>>>> place_type </li></ul></ul><ul><ul><li><ContentType: place> </li></ul></ul><ul><ul><li>>>> place_type.model_class()‏ </li></ul></ul><ul><ul><li><class 'pycon2.places.models.Place'> </li></ul></ul><ul><ul><li>>>> from pycon2.places.models import Location </li></ul></ul><ul><ul><li>>>> ContentType.objects.get_for_model(Location)‏ </li></ul></ul><ul><ul><li><ContentType: location> </li></ul></ul>
    • 53. Contenttypes: ObjectCounter <ul><ul><li># pycon2.counter.models </li></ul></ul><ul><ul><li>from django.db import models </li></ul></ul><ul><ul><li>from django.contrib.contenttypes.models import ContentType </li></ul></ul><ul><ul><li>from django.contrib.contenttypes import generic </li></ul></ul><ul><ul><li>from django.contrib.auth.models import User </li></ul></ul><ul><ul><li>from pycon2.counter.managers import ObjectCounterManager </li></ul></ul><ul><ul><li>class ObjectCounter(models.Model): </li></ul></ul><ul><ul><li>content_type = models.ForeignKey(ContentType)‏ </li></ul></ul><ul><ul><li>object_id = models.PositiveIntegerField()‏ </li></ul></ul><ul><ul><li>content_object = generic.GenericForeignKey('content_type', 'object_id')‏ </li></ul></ul><ul><ul><li>visited = models.DateTimeField(auto_now_add=True)‏ </li></ul></ul><ul><ul><li>user = models.ForeignKey(User, blank=True, null=True)‏ </li></ul></ul><ul><ul><li>objects = ObjectCounterManager() </li></ul></ul><ul><ul><li>def __unicode__(self): </li></ul></ul><ul><ul><li>return u'%s: %d' % (self.content_type.name, self.object_id)‏ </li></ul></ul>
    • 54. Contenttypes: ObjectCounterManager <ul><ul><li># pycon2.counter.managers </li></ul></ul><ul><ul><li>from django.db import models, connection </li></ul></ul><ul><ul><li>from django.contrib.contenttypes.models import ContentType </li></ul></ul><ul><ul><li>class ObjectCounterManager(models.Manager): </li></ul></ul><ul><ul><li>def count_object(self, obj, user=None): </li></ul></ul><ul><ul><li>counter = self.model()‏ </li></ul></ul><ul><ul><li>counter.content_object = obj </li></ul></ul><ul><ul><li>if user: counter.user = user </li></ul></ul><ul><ul><li>counter.save()‏ </li></ul></ul><ul><ul><li>def most_visited_for_model(self, model, num=10): </li></ul></ul><ul><ul><li>'''Inspired by http://www.djangosnippets.org/snippets/108/''' </li></ul></ul><ul><ul><li>content_type = ContentType.objects.get_for_model(model)‏ </li></ul></ul><ul><ul><li>primary_table = model._meta.db_table </li></ul></ul><ul><ul><li>secondary_table = self.model()._meta.db_table </li></ul></ul><ul><ul><li>query = &quot;&quot;&quot;SELECT p.id AS obj_id, COUNT(*) AS score </li></ul></ul><ul><ul><li>FROM %s p INNER JOIN %s s ON (p.id = s.object_id)‏ </li></ul></ul><ul><ul><li>WHERE s.content_type_id = %%s GROUP BY obj_id </li></ul></ul><ul><ul><li>ORDER BY score DESC&quot;&quot;&quot; % (primary_table, secondary_table)‏ </li></ul></ul><ul><ul><li>cursor = connection.cursor()‏ </li></ul></ul><ul><ul><li>cursor.execute(query, [content_type.id])‏ </li></ul></ul><ul><ul><li>object_ids = [row[0] for row in cursor.fetchall()[:num]] </li></ul></ul><ul><ul><li>object_dict = model._default_manager.in_bulk(object_ids)‏ </li></ul></ul><ul><ul><li>return [object_dict[object_id] for object_id in object_ids] </li></ul></ul>
    • 55. Contenttypes: utilizzo di ObjectCounter <ul><ul><li>>>> from django.db import models </li></ul></ul><ul><ul><li>>>> from pycon2.counter.models import ObjectCounter </li></ul></ul><ul><ul><li>>>> from pycon2.members.models import Profile </li></ul></ul><ul><ul><li>>>> profile1 = Profile.objects.get(pk=1)‏ </li></ul></ul><ul><ul><li>>>> profile2 = Profile.objects.get(pk=2)‏ </li></ul></ul><ul><ul><li>>>> profile3 = Profile.objects.get(pk=3)‏ </li></ul></ul><ul><ul><li>>>> ObjectCounter.objects.count_object(profile1)‏ </li></ul></ul><ul><ul><li>>>> ObjectCounter.objects.count_object(profile1)‏ </li></ul></ul><ul><ul><li>>>> ObjectCounter.objects.count_object(profile1)‏ </li></ul></ul><ul><ul><li>>>> ObjectCounter.objects.count_object(profile2)‏ </li></ul></ul><ul><ul><li>>>> ObjectCounter.objects.count_object(profile2)‏ </li></ul></ul><ul><ul><li>>>> ObjectCounter.objects.count_object(profile3)‏ </li></ul></ul><ul><ul><li>>>> ObjectCounter.objects.most_visited_for_model(Profile)‏ </li></ul></ul><ul><ul><li>[<Profile: foo>, <Profile: bar>, <Profile: baz>] </li></ul></ul>
    • 56. Signals <ul><li>Django utilizza il dispatching di eventi per la gestione di determinate funzionalità </li></ul><ul><li>È possibile collegare le proprie funzioni ai segnali utilizzati internamente dal framework </li></ul><ul><li>Tali funzionalità sono offerte da PyDispatcher, che è stato incluso a partire dalla versione 0.9.5 </li></ul>
    • 57. Signals <ul><li>I seguenti segnali sono utilizzati internamente nei modelli e sono definiti in django.db.models.signals </li></ul><ul><ul><li>pre_init </li></ul></ul><ul><ul><li>post_init </li></ul></ul><ul><ul><li>pre_save </li></ul></ul><ul><ul><li>pre_delete </li></ul></ul><ul><ul><li>post_delete </li></ul></ul><ul><ul><li>post_syncdb </li></ul></ul>
    • 58. Signals: utilizzo di esempio <ul><li>È possibile estendere il modello django.contrib.auth.models.User utilizzando un proprio modello attraverso la variabile di configurazione AUTH_PROFILE_MODULE AUTH_PROFILE_MODULE = 'members.Profile' </li></ul><ul><li>L'istanza del modello definito in AUTH_PROFILE_MODULE non viene creata automaticamente nel momento in cui un istanza di User viene salvata </li></ul>
    • 59. Signals: utilizzo di esempio <ul><li>Possiamo creare l'istanza del modello nella nostra view che si occupa della registrazione dei modelli </li></ul><ul><li>E se l'utente viene creato da un amministratore attraverso l'interfaccia di amministrazione? </li></ul>
    • 60. Signals: utilizzo d'esempio # pycon2.members.models from django.db import models from django.contrib.auth.models import User from django.dispatch import dispatcher from django.db.models import signals class Profile(models.Model): user = models.ForeignKey(User)‏ photo = models.ImageField(upload_to='pics', blank=True)‏ bio = models.TextField(blank=True)‏ def create_profile(sender, instance, signal, *args, **kwargs): if kwargs.get('created'): try: instance.get_profile()‏ except Profile.DoesNotExist: profile = Profile(user=instance)‏ profile.save()‏ dispatcher.connect(create_profile, signal=signals.post_save, sender=User)‏
    • 61. <ul><ul><li>Massimo Scamarcia [email_address] </li></ul></ul><ul><ul><li>http://skam.webfactional.com/ </li></ul></ul>Grazie! http://creativecommons.org/licenses/by-nd/2.5/it/

    ×