- 1. Django Utilizzo avanzato e nuove funzionalit
2. Perch utilizzare django?
- Tempi di sviluppo ridotti
- Ottima documentazione, comunit attiva e partecipe
- Motore di templating semplice e adatto ai designer di pagine
HTML
- URL puliti e SEO-friendly
3. Perch utilizzare la versione trunk?
- 1 anno dall'ultima release stabile (0.9.6)
4. Utilizzo della versione trunk
- Installazione da sorgenti
- $ svn
cohttp://code.djangoproject.com/svn/django/trunkDjango
- $ python setup.py install
- Utilizzo senza installazione
- $ export PATH=$PATH:/path/to/Django/bin
- $ export PYTHONPATH=$PYTHONPATH:/path/to/packages/Django
5. Supporto unicode: gestione delle stringhe
- Django assume che tutte le bytestring siano inUTF-8 , in caso
contrario l'eccezioneUnicodeDecodeErrorverr sollevata
- La variabile di configurazioneDEFAULT_CHARSETviene utilizzata
solo per il rendering dei template e dei messaggi e-mail
- Le stringhe di traduzione lazy possono essere convertite
direttamente in stringhe unicode
-
-
-
http://www.djangoproject.com/documentation/i18n/#lazy-translation
6. Supporto unicode: funzioni di conversione
- django.utils.encoding.smart_unicode
-
- Converte una qualsiasi stringa in unicode
- django.utils.encoding.force_unicode
-
- Identica a smart_unicode, con la differenza che non preserva le
stringhe di traduzione lazy, forzandone la traduzione e la
conversione in unicode
7. Supporto unicode: URI e IRI
- Gli URL di tipo URI utilizzano solo caratteri ASCII.
- La funzioneiri_to_uripermette di costruire URL di tipo IRI (RFC
3987)
-
-
- http://www.ietf.org/rfc/rfc3987.txt
- >>> from django.utils.encoding import iri_to_uri
- >>> iri_to_uri(u'/locations/Rennes-le-Chteau')
- '/locations/Rennes-le-Ch%C3%A2teau'
8. Supporto unicode: database
- Assicurarsi che il proprio database sia configurato per
utilizzare l'encoding appropriato ( UTF-8, UTF-16 )
- Il database backend si occuper di convertire automaticamente le
stringhe unicode nell'encoding utilizzato dal database, e
viceversa
- possibile passare stringhe unicode e bytestringUTF-8ai metodi
utilizzati per filtrare gli oggettiQuerySet
- >>>
Place.objects.filter(name__contains=u'Chteau')
9. Supporto unicode: modelli
- Le stringhe ottenute dai campi testuali dei modelli sono sempre
di tipo unicode
- Nel caso il vostro modello contenga un metodo__str__()pu essere
necessario implementare anche il metodo __unicode__()
- Se necessario, utilizzare la funzioneiri_to_uri()nel
metodoget_absolute_url()
10. Supporto unicode: template
- I template possono essere salvati sul filesystem utilizzando un
charset diverso daUTF-8 , in tal caso necessario definire la
variabile di configurazioneFILE_CHARSET
- consigliato l'utilizzo delle funzioneforce_unicodenella
creazione di template tag
11. Escape automatico dei template
- Qualsiasi variabile inserita nel contesto di un template viene
convertita automaticamente utilizzandodjango.utils.html.escape
- stata introdotta con lo scopo di prevenire attacchi di
tipoXSS(Cross-site scripting)
- Non possibile disabilitare tale funzionalit globalmente
12. Escape automatico dei template
- possibile disabilitare l'escape automatico direttamente nei
template {% autoescape off %} ... {{ entry.body }} ... {%
endautoescape %} {{ entry.body|safe }}
13. Escape automatico dei template
- inoltre possibile disabilitare l'escape automatico nei template
filter @register.filter def safefilter(value): # do something with
value... return value safefilter.is_safe = True
- template.Contextaccetta
l'argomentoautoescapetemplate.Context({'foo': bar},
autoescape=False)
14. Modelli
- La classeLazyDate() stata rimossa. possibile utilizzare una
funzione per l'argomentodefault 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)
- L'utilizzo dell'attributomaxlength deprecato ed stato
sostituito damax_length
15. Modelli
- I campi di tipoFloatFieldutilizzavanofloatper rappresentare
numeri decimali a precisione fissa
- stato introdotto il campoDecimalField , che utilizza il tipo di
datodecimal.Decimalper mantenere la precisione latitude =
models.DecimalField(max_digits=8,decimal_places=6)
- FloatFieldnon accetta pi gli argomenti precedentemente
utilizzati
16. Modelli
- stato recentemente aggiunto il supporto all'ereditariet delle
classiModel 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()
-
http://www.djangoproject.com/documentation/model-api/#model-inheritance
http://code.djangoproject.com/wiki/QuerysetRefactorBranch
17. URL patterns
- ora possibile utilizzare la funzioneurl()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'^(?Pd+)/edit/$',
'place_edit', name='place_edit'),
url(r'^(?Pd+)/delete/$','place_delete', name='place_delete') )
18. URL patterns: permalink
- Utilizzo nel metodoget_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)
19. URL patterns: url template tag
- Add place Edit {{ place }} Delete {{ place }}
20. MEDIA_URL context processor
- La variabile di configurazioneMEDIA_URL ora disponibile per
poter essere utilizzata nei template
21. URL patterns: urlresolvers
- >>> 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/'
22. newforms
- Introdotta nella release 0.9.6 con lo scopo di sostituire la
vecchia libreria di gestione dei form
- Permette di semplificare la creazione dei form, la validazione
dei dati ricevuti, l'utilizzo e la creazione di widget HTML
personalizzati
- django.forms stata copiata indjango.oldforms
- Nella prossima release stabiledjango.newformsverr rinominata
indjango.forms
23. newforms
-
- Contiene i campi, riceve i dati, si occupa della loro
validazione e del rendering in HTML
-
- Rappresenta un campo e si occupa della sua validazione
-
- Rendering di un campo in HTML
24. newforms
-
- from django import newforms as forms
-
- class ContactForm(forms.Form):
-
- name = forms.CharField(required=False, max_length=50)email =
forms.EmailField()comment =
forms.CharField(widget=forms.Textarea)
-
- Gli argomentimax_lengtherequiredvengono utilizzati per la
validazione del campo name
-
- L'argomentowidgetviene utilizzato per definire il tipo di
widget utilizzato per l'output HTML
25. newforms
- I dati ricevuti vengono passati come primo argomento del
costruttore della classe
- possibile verificare la validit dei dati ricevutiutilizzando il
metodois_valid()
- L'attributoerrors un dizionario contenente gli errori di
validazione
- Nella release 0.9.6 i datidel form, normalizzati a seconda dei
tipi di campo, erano disponibili nell'attributoclean_data , che
stato rinominato incleaned_data
26. newforms
- >>> form = ContactForm() >>> form.is_bound
False >>> form = ContactForm({'email': '[email protected] '})
>>> form.is_bound True >>> form.is_valid() False
>>> form.errors {'comment': [u'This field is
required.']}
27. newforms
- Per gestire gli upload possibile passarerequest.FILEScome
secondo argomento nel costruttore della classe
- Il metodois_multipart()ritornaTruese la classe contiene campi
di tipoFileField
- possibile accedere al nome e al contenuto del file
attraversocleaned_data form.cleaned_data['fieldname'].content
form.cleaned_data['fieldname'].filename
28. newforms: esempio di utilizzo
-
- from django.template import RequestContext
-
- from django.template.loader import render_to_string
-
- from django.shortcuts import render_to_response
-
- from django.core.mail import mail_admins
-
- from pycon2.contacts.forms import ContactForm
-
- def contact(request, template='contacts/contact.html',
email_template='contacts/contact_email.txt'):
-
- if request.method == 'POST':
-
- form = ContactForm(request.POST)
-
- message = render_to_string(email_template,
-
- mail_admins('contact request', message)
-
- return render_to_response(template, {'form':
form},context_instance=RequestContext(request))
29. Field e Widget personalizzati: CaptchaField
-
- from django import newforms as forms
-
- from pycon2.utils.captcha.fields import CaptchaField
-
- class ContactForm(forms.Form):
-
- name = forms.CharField(required=False, max_length=50)
-
- email = forms.EmailField()
-
- comment = forms.CharField(widget=forms.Textarea)
30. CaptchaWidget
-
- # pycon2.utils.captcha.fields
-
- from django.newforms.util import flatatt
-
- from django.utils.safestring import mark_safe
-
- class CaptchaWidget(forms.TextInput):
-
- def render(self, name, value, attrs=None):
-
- captcha_url = reverse('captcha')
-
- image = CAPTCHA_IMAGE % captcha_url
-
- if value is None: value = ''
-
- final_attrs =
self.build_attrs(attrs,type=self.input_type,name=name)
-
- attrs = flatatt(final_attrs)
-
- final_attrs['value'] = force_unicode(value)
-
- return mark_safe(u'%s' % (image, attrs))
31. CaptchaWidget: funzioni utilizzate
- django.newforms.util.flatatt
-
- Converte un dizionario in una stringa contenente gli attributi
utilizzabili in un elemento HTML. I valori del dizionario vengono
convertiti utilizzando la funzionedjango.utils.html.escape
- django.utils.safestring.mark_safe
-
- Funzione utilizzata per definire che la stringa passata come
argomento sicura per poter essere utilizzata nell'output HTML
32. CaptchaField
-
- # pycon2.utils.captcha.fields
-
- from django.utils.translation import ugettext as _
-
- from pycon2.utils.captcha.middleware import
-
- class CaptchaField(forms.CharField):
-
- captcha = get_current_captcha()
-
- raise forms.ValidationError(_('You must enable cookies.'))
-
- raise forms.ValidationError(_('Incorrect! Try again.'))
33. Captcha middleware
-
- # pycon2.utils.captcha.middleware
-
- from threading import local
-
- from django.utils._threading_local import local
-
- def get_current_captcha():
-
- return getattr(_thread_locals, 'captcha', None)
-
- class CaptchaMiddleware(object):
-
- def process_request(self, request):
-
- captcha = None session = getattr(request, 'session', None) if
session: captcha = session.get('captcha')
-
- _thread_locals.captcha = captcha
34. Captcha view
-
- # pycon2.utils.captcha.view
-
- from Captcha.Visual.Tests import PseudoGimpy
-
- from django.http import HttpResponse
-
- def captcha(request):'''Visualizza un immagine captcha
utilizzando PyCaptcha
-
- request.session['captcha'] = g.solutions[0]
-
- return HttpResponse(s.getvalue(), 'image/jpeg')
35. Form preview
- Viene fornita un'applicazione per poter visualizzare
l'anteprima di una classe form
-
- Il form viene visualizzato in formato HTML su una pagina
web
-
- I dati del form vengono validati
-
-
- Se il form non valido, viene visualizzato con gli errori di
validazione
-
-
- Se il form valido, viene visualizzato per conferma
-
- I dati del form di conferma vengono ricevuti da un hook
definito dall'utente
36. Form preview # pycon2.contacts.preview import pprint from
django.http import HttpResponse from
django.contrib.formtools.preview importFormPreview 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
- Per visualizzare l'anteprima sufficiente aggiungere un pattern
nella propria configurazione degli URL ('^preview/contact/$',
'pycon2.contacts.preview.contact'),
38. Form wizard
- stata introdotta un applicazione che permette di creare form
suddivisi su pi pagine
- L'applicazione si occupa di mantenere lo stato dei dati
inseriti nei form fra una pagina e l'altra
- Le istanze delle classi form vengono passate al
metododone()
- possibile specificare i template da utilizzare definendo il
metodoget_template()
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.as_p }} {{
previous_fields|safe }}
{% endblock %} 42. ModelForm
- Permette di creare una classeFormda un modello
- Sostituisce le funzioni
deprecateform_for_model()eform_for_instance()
- Permette di modificare con facilit i campi generati
automaticamente
43. ModelForm
- from django import newforms as forms
- from pycon2.places.models import Place
- class PlaceForm(forms.ModelForm):
- exclude = ('created', 'author')
- La classe internaMetaviene utilizzata per definire
44. ModelForm
- Il costruttore della classe accetta l'argomentoinstanceper
definire l'istanza del modello da utilizzare
- Il metodosave()ritorna l'istanza del modello
-
- accetta il parametrocommit : se il suo valore Falseil metodo
restituisce un istanza non salvata
-
- in tal caso il metodosave_m2m()deve essere utilizzato per poter
salvare i dati delle relazioni many-to-many
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
- Utilizza la librerianewforms , eliminando le dipendenze
conoldforms
- Disaccoppia le funzionalit dell'interfaccia di amministrazione
dai modelli
- Permette di personalizzare alcuni aspetti dell'interfaccia di
amministrazione, fra cui:
-
- Definire widget personalizzati per i campi e modificarne gli
attributi
-
- Modificare i permessi sui singoli oggetti
48. newforms-admin: installazione
- Scaricare il branch e modificare la variabile
d'ambientePYTHONPATH
http://code.djangoproject.com/svn/django/branches/newforms-admin/
- Modificare la propria configurazione degli URL from
django.conf.urls.defaults import * from django.contrib import admin
urlpatterns = patterns('', (r'^admin/(.*)', admin.site.root),
)
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
- Applicazione basata sul modelloContentType , che contiene i
seguenti campi
-
- app_label(nome dell'applicazione)
-
- name( verbose_namedi un modello)
- Permette di creare delle relazioni generiche fral' istanza di
un modello e diverse altre istanze
- Viene utilizzata in diverse applicazioni fra cui
django.contrib.comments, django-tagging, django-voting etc.
52. Contenttypes
-
- >>> from django.contrib.contenttypes.models import
ContentType
-
- >>> place_type =
ContentType.objects.get(app_label='places',
-
- >>> place_type.model_class()
-
- >>> from pycon2.places.models import Location
-
- >>> ContentType.objects.get_for_model(Location)
53. Contenttypes: ObjectCounter
-
- from django.db import models
-
- from django.contrib.contenttypes.models import ContentType
-
- from django.contrib.contenttypes import generic
-
- from django.contrib.auth.models import User
-
- from pycon2.counter.managers import ObjectCounterManager
-
- class ObjectCounter(models.Model):
-
- content_type = models.ForeignKey(ContentType)
-
- object_id = models.PositiveIntegerField()
-
- content_object = generic.GenericForeignKey('content_type',
'object_id')
-
- visited = models.DateTimeField(auto_now_add=True)
-
- user = models.ForeignKey(User, blank=True, null=True)
-
- objects = ObjectCounterManager()
-
- return u'%s: %d' % (self.content_type.name,
self.object_id)
54. Contenttypes: ObjectCounterManager
-
- # pycon2.counter.managers
-
- from django.db import models, connection
-
- from django.contrib.contenttypes.models import ContentType
-
- class ObjectCounterManager(models.Manager):
-
- def count_object(self, obj, user=None):
-
- counter.content_object = obj
-
- if user: counter.user = user
-
- def most_visited_for_model(self, model, num=10):
-
- '''Inspired by
http://www.djangosnippets.org/snippets/108/'''
-
- content_type = ContentType.objects.get_for_model(model)
-
- primary_table = model._meta.db_table
-
- secondary_table = self.model()._meta.db_table
-
- query = """SELECT p.id AS obj_id, COUNT(*) AS score
-
- FROM %s p INNER JOIN %s s ON (p.id = s.object_id)
-
- WHERE s.content_type_id = %%s GROUP BY obj_id
-
- ORDER BY score DESC""" % (primary_table, secondary_table)
-
- cursor = connection.cursor()
-
- cursor.execute(query, [content_type.id])
-
- object_ids = [row[0] for row in cursor.fetchall()[:num]]
-
- object_dict = model._default_manager.in_bulk(object_ids)
-
- return [object_dict[object_id] for object_id in
object_ids]
55. Contenttypes: utilizzo di ObjectCounter
-
- >>> from django.db import models
-
- >>> from pycon2.counter.models import
ObjectCounter
-
- >>> from pycon2.members.models import Profile
-
- >>> profile1 = Profile.objects.get(pk=1)
-
- >>> profile2 = Profile.objects.get(pk=2)
-
- >>> profile3 = Profile.objects.get(pk=3)
-
- >>> ObjectCounter.objects.count_object(profile1)
-
- >>> ObjectCounter.objects.count_object(profile1)
-
- >>> ObjectCounter.objects.count_object(profile1)
-
- >>> ObjectCounter.objects.count_object(profile2)
-
- >>> ObjectCounter.objects.count_object(profile2)
-
- >>> ObjectCounter.objects.count_object(profile3)
-
- >>>
ObjectCounter.objects.most_visited_for_model(Profile)
56. Signals
- Django utilizza il dispatching di eventi per la gestione di
determinate funzionalit
- possibile collegare le proprie funzioni ai segnali utilizzati
internamente dal framework
- Tali funzionalit sono offerte da PyDispatcher, che stato
incluso a partiredalla versione 0.9.5
57. Signals
- I seguenti segnali sono utilizzati internamente nei modelli e
sono definiti indjango.db.models.signals
58. Signals: utilizzo di esempio
- possibile estendere il
modellodjango.contrib.auth.models.Userutilizzando un proprio
modello attraverso la variabile di
configurazioneAUTH_PROFILE_MODULE AUTH_PROFILE_MODULE =
'members.Profile'
- L'istanza del modello definito inAUTH_PROFILE_MODULEnon viene
creata automaticamente nel momento in cui un istanza diUserviene
salvata
59. Signals: utilizzo di esempio
- Possiamo creare l'istanza del modello nella nostra view che si
occupa della registrazione dei modelli
- E se l'utente viene creato da un amministratore attraverso
l'interfaccia di amministrazione?
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.
-
- Massimo Scamarcia [email_address]
-
- http://skam.webfactional.com/
Grazie! http://creativecommons.org/licenses/by-nd/2.5/it/