9. get_absolute_url - Programmare in Python

9. get_absolute_url

Fin'ora abbiamo ottenuto i link a ciascun post singolo tramite "hardcoding", ovvero specificandoli in maniera diretta, utilizzando la chiave primaria(chiamata anche id) e lo slug di ciascun post:

<!--DOCTYPE html -->
<html>
    <body>
        {% for object in object_list %}

             <h1><a href="/{{object.id}}/{{object.slug}}/">{{object.titolo}}</a></h1>

        {% endfor %}
    </body>
</html>

Ma il tutto è poco elegante e sopratutto rende il programma meno modulare; Noi vogliamo che la nostra app possa essere utilizzata anche in altri progetti: cosa succederebbe se il pattern url associato variasse anche solo di poco? Ad esempio:

# urls.py

urlpatterns = [
    (...)
    url(r'^asd/(?P<id>\d+)/(?P<slug>[\w-]+)/$', DetailView.as_view(
        model=Post,
        template_name="post_singolo.html"
        ),
        name="singolo"
    )
    (...)
]

N.B. L'utilizzo di una CBV richiamata direttamente nel file urls.py come mostrato in questa lezione, non è tipico, seppur comunque fattibile. Normalmente, le views, sia class based che function based, vengono definite comunque all'interno del file views.py, come abbiamo visto nella lezioneArchitettura MTV, Urls e Views. In questo breve corso introduttivo ho cercato di trovare un compromesso tra il mostrare la gran potenza di Django nel permettere di creare web app di una certa complessità scrivendo davvero poche righe di codice. Per un corso completo, dai uno sguardo aGuida Pratica e Completa a Django, Python e Bootstrap.

Otterremo sicuramente un errore.

Per ovviare a questo problema torniamo ora nel nostro models.py e creiamo una funzione che sia in grado di restituirci l'url del nostro post, qualunque esso sia! Per convenzione, chiameremo questa funzione "get_absolute_url", e sarà basata a sua volta su una funzione presente in django.core.urlresolvers, la funzione reverse.

from django.core.urlresolvers import reverse
from django.db import models

# Create your models here.

class Post(models.Model):
    titolo = models.CharField(max_length=120)
    contenuto = models.TextField()
    # auto_now_add setta quando il file viene creato, quindi solo una volta
    data = models.DateTimeField(auto_now=False, auto_now_add=True) 
    slug = models.SlugField()

    # python 3
    def __str__(self):
        return self.titolo

    def get_absolute_url(self):
        return reverse("singolo", kwargs={"id": self.id, "slug": self.slug})

A questo punto tornando nel template "lista_post.html", possiamo modificare i link in maniera appropriata, richiamando su ciascun oggetto del ciclo for la corrispondente funzione get_absolute_url:

<!--DOCTYPE html -->
<html>
    <body>
        {% for object in object_list %}
            <h1><a href="{{object.get_absolute_url}}">{{object.titolo}}</a></h1>
        {% endfor %}
    </body>
</html>