Slug ovvero come ricavare un link univoco dal titolo del post
Scrivendo il "motore" di questo blog mi sono trovato di fronte al problema di ricavare una URL, che per definizione è univoca, per ciascuno dei post. La definizione dei modelli in Django mette a disposizione un campo che sembra fatto apposta per questo scopo: lo SlugField.
Slug, acronimo di short label for something, è un campo che contiene solamente lettere, numeri, underscore "_" o trattini "-", tutti caratteri che possono essere utilizzati per comporre una URL. A questo punto mi occorre trovare un modo di valorizzare automaticamente questo campo con un valore univoco quando il post viene composto.
Django Snippets, un sito per gli utenti Django dove vengono raccolti e condivisi frammenti di codice riutilizzabili, contiene diversi modi per generare uno slug univoco a partire da un qualche valore dato. Nel mio caso ho utilizzato Automate unique slug (again) con una modifica per farlo funzionare con la versione 1.0 di Django che altrimenti mi restituiva un errore.
class Post(models.Model): blog = models.ForeignKey('weblog.Blog') user = models.ForeignKey('auth.User') title = models.CharField("titolo", max_length=128) publish = models.BooleanField("pubblicato") published_on = models.DateTimeField(auto_now_add=True) modified_on = models.DateTimeField(auto_now=True, auto_now_add=True) body = models.TextField() postid = models.SlugField("post ID", max_length=128, unique=True, null=True, blank=True) def __unicode__(self): return self.title # auto valorizzazione del campo slug, al momento del salvataggio dell'oggetto # da http://www.djangosnippets.org/snippets/761/ def save(self, force_insert=False, force_update=False): import re from django.template.defaultfilters import slugify if not self.postid: self.postid = slugify(self.title) while True: try: super(Post, self).save() # Assuming the IntegrityError is due to a slug fight except IntegrityError: match_obj = re.match(r'^(.*)-(\d+)$', self.postid) if match_obj: next_int = int(match_obj.group(2)) + 1 self.postid = match_obj.group(1) + '-' + str(next_int) else: self.postid += '-2' else: break