• 40 hours
  • Medium

Free online content available in this course.

Paperback available in this course

course.header.alt.is_certifying

You can get support and mentoring from a private teacher via videoconference on this course.

Got it!

Last updated on 10/11/19

TP : un raccourcisseur d'URL

Log in or subscribe for free to enjoy all this course has to offer!

Dans ce chapitre, nous allons mettre en pratique tout ce que vous avez appris jusqu'ici. Il s'agit d'un excellent exercice qui permet d'apprendre à lier les différents éléments du framework que nous avons étudiés (URL, modèles, vues, formulaires, administration et templates).

Cahier des charges

Pour ce travail pratique, nous allons réaliser un raccourcisseur d'URL. Ce type de service est notamment utilisé sur les sites de microblogging (comme Twitter) ou les messageries instantanées, où utiliser une très longue URL est difficile, car le nombre de caractères est limité.

Typiquement, si vous avez une longue URL, un raccourcisseur créera une autre URL, beaucoup plus courte, que vous pourrez distribuer. Lorsque quelqu'un cliquera sur le lien raccourci, il sera directement redirigé vers l'URL plus longue.
Par exemple, tib.ly/abcde  redirigerait verswww.mon-site.com/avec-une/URL-tres-longue. Le raccourcisseur va générer un code (iciabcde) qui sera propre à l'URL plus longue. Un autre code redirigera le visiteur vers une autre URL.

Vous allez devoir créer une nouvelle application que nous nommeronsmini_url. Cette application ne contiendra qu'un modèle appeléMiniURL, c'est lui qui enregistrera les raccourcis. Il comportera les champs suivants :

  • L'URL longue :URLField;

  • Le code qui permet d'identifier le raccourci ;

  • La date de création du raccourci ;

  • Le pseudo du créateur du raccourci (optionnel) ;

  • Le nombre d'accès au raccourci (une redirection = un accès).

Nous avons indiqué le type du champ pour l'URL, car vous ne l'avez pas vu dans le cours auparavant. Les autres sont classiques et ont été vus, nous supposons donc que vous choisirez le bon type.
Les deux premiers champs (URL et code) devront avoir le paramètreunique=True. Ce paramètre garantit que deux entrées ne partageront jamais le même code ou la même URL, ce qui est primordial ici, surtout pour le champcode .
Finalement, le nombre d'accès sera par défaut mis à 0 grâce au paramètredefault=0.

Vous devrez également créer un formulaire, plus spécialement unModelFormbasé sur le modèleMiniURL. Il ne contiendra que les champs URL et pseudo, le reste sera soit initialisé selon les valeurs par défaut, soit généré par la suite (le code notamment).

Nous vous fournissons la fonction qui permet de générer le code :

import random
import string

def generer(nb_caracteres):
    caracteres = string.ascii_letters + string.digits
    aleatoire = [random.choice(caracteres) for _ in range(nb_caracteres)]
    
    return ''.join(aleatoire)

Vous aurez ensuite trois vues :

  • Une vue affichant toutes les redirections créées et leurs informations, triées par ordre descendant, de la redirection avec le plus d'accès vers celle en ayant le moins ;

  • Une vue avec le formulaire pour créer une redirection ;

  • Une vue qui prend comme paramètre dans l'URL le code et redirige l'utilisateur vers l'URL longue.

Partant de ces trois fonctions, il ne faudra que 2 templates (la redirection n'en ayant pas besoin), et 3 routages d'URL bien entendu.

L'administration devra être activée, et le modèle accessible depuis celle-ci. Il devra être possible de rechercher des redirections depuis la longue URL via une barre de recherche, tous les champs devront être affichés dans une catégorie et le tri par défaut sera fait selon la date de création du raccourci.

Voici aux figures suivantes ce que vous devriez obtenir.

Image utilisateur
Image utilisateur
Image utilisateur

Si vous coincez sur quelque chose, n'hésitez pas à aller relire les explications dans le chapitre concerné, tout y a été expliqué.

Correction

Normalement, cela ne devrait pas avoir posé de problèmes !

Il fallait donc créer une nouvelle application et l'inclure dans votresettings.py:

python manage.py startapp mini_url

Votremodels.pydevrait ressembler à ceci :

from django.db import models
import random
import string


class MiniURL(models.Model):
    url = models.URLField(verbose_name="URL à réduire", unique=True)
    code = models.CharField(max_length=6, unique=True)
    date = models.DateTimeField(auto_now_add=True, 
                                verbose_name="Date d'enregistrement")
    pseudo = models.CharField(max_length=255, blank=True, null=True)
    nb_acces = models.IntegerField(default=0, 
                                   verbose_name="Nombre d'accès à l'URL")

    def __str__(self):
        return "[{0}] {1}".format(self.code, self.url)

    def save(self, *args, **kwargs):
        if self.pk is None:
            self.generer(6)

        super(MiniURL, self).save(*args, **kwargs)

    def generer(self, nb_caracteres):
        caracteres = string.ascii_letters + string.digits
        aleatoire = [random.choice(caracteres) for _ in range(nb_caracteres)]

        self.code = ''.join(aleatoire)

    class Meta:
        verbose_name = "Mini URL"
        verbose_name_plural = "Minis URL"

Il y a plusieurs commentaires à faire dessus. Tout d'abord, nous avons surchargé la méthodesave(), afin de générer automatiquement le code de notre URL. Nous avons pris le soin d'intégrer la méthodegenerer()au sein du modèle, mais il est aussi possible de la déclarer à l'extérieur et de faireself.code = generer(6). Il ne faut surtout pas oublier la ligne qui appelle lesave()parent, sinon lorsque vous validerez votre formulaire il ne se passera tout simplement rien !

La classeMetaici est similaire à la classeMetad'unModelForm, elle permet d'indiquer des métadonnées concernant le modèle. Ici nous avons modifié le nom qui sera utilisé dans lesModelForm, l'administration (verbose_name) et sa forme plurielle (verbose_name_plural).

Après la création de nouveaux modèles, il fallait les ajouter dans la base de données via la commande python manage.py makemigrations puispython manage.py migrate (n'oubliez pas d'ajouter l'application dans votresettings.py!) :

$ python manage.py makemigrations
Migrations for 'mini_url':
  0001_initial.py:
    - Create model MiniURL
    
$ python manage.py migrate
Operations to perform:
  Synchronize unmigrated apps: admin, contenttypes, auth, sessions
  Apply all migrations: blog, mini_url
Synchronizing apps without migrations:
  Creating tables...
  Installing custom SQL...
  Installing indexes...
Running migrations:
  Applying mini_url.0001_initial... OK

Leforms.pyest tout à fait classique :

from django import forms
from .models import MiniURL

class MiniURLForm(forms.ModelForm):
    class Meta:
        model = MiniURL
        fields = ('url', 'pseudo')

De même pouradmin.py:

from django.contrib import admin
from .models import MiniURL

class MiniURLAdmin(admin.ModelAdmin):
    list_display = ('url', 'code', 'date', 'pseudo', 'nb_acces')
    list_filter = ('pseudo', )
    date_hierarchy = 'date'
    ordering = ('date', )
    search_fields = ('url', )

admin.site.register(MiniURL, MiniURLAdmin)

Voicimini_url/urls.py. N'oubliez pas de l'importer dans votreurls.pyprincipal. Rien de spécial non plus :

from django.conf.urls import url
from . import views

urlpatterns = [
    # Une string vide indique la racine
    url(r'^$', views.liste, name='url_liste'),
    url(r'^nouveau$', views.nouveau, name='url_nouveau'),
    # (?P<code>\w{6}) capturera 6 caractères alphanumériques. 
    url(r'^(?P<code>\w{6})/$', views.redirection, name='url_redirection'),
]

La directive permettant d'importer lemini_url/urls.pydans votreurls.pyprincipal :

url(r'^m/', include('mini_url.urls')),

Et pour finir, le fichierviews.py:

from django.shortcuts import redirect, get_object_or_404, render
from mini_url.models import MiniURL
from mini_url.forms import MiniURLForm


def liste(request):
    """ Affichage des redirections """
    minis = MiniURL.objects.order_by('-nb_acces')

    return render(request, 'mini_url/liste.html', locals())


def nouveau(request):
    """ Ajout d'une redirection """
    if request.method == "POST":
        form = MiniURLForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect(liste)
    else:
        form = MiniURLForm()

    return render(request, 'mini_url/nouveau.html', {'form': form})


def redirection(request, code):
    """ Redirection vers l'URL enregistrée """
    mini = get_object_or_404(MiniURL, code=code)
    mini.nb_acces += 1
    mini.save()

    return redirect(mini.url, permanent=True)

Notez qu'à cause de l'argumentpermanent=True, le serveur renvoie le code HTTP 301 (redirection permanente).

Pour terminer, les deux templates,liste.htmletnouveau.html. Remarquez{{ request.get_host }}qui donne le nom de domaine et le port utilisé. En production, par défaut il s'agit delocalhost:8000. Néanmoins, si nous avions un autre domaine commebit.ly, c'est ce domaine qui serait utilisé (il serait d'ailleurs beaucoup plus court et pratique comme raccourcisseur d'URL).

<h1>Le raccourcisseur d'URL spécial crêpes bretonnes !</h1>

<p><a href="{% url 'url_nouveau' %}">Raccourcir une URL.</a></p>

<p>Liste des URL raccourcies :</p>
<ul>
    {% for mini in minis %}
    <li> {{ mini.url }} via <a href="http://{{ request.get_host }}{% url 'url_redirection' mini.code %}">{{ request.get_host }}{% url 'url_redirection' mini.code %}</a>
    {% if mini.pseudo %}par {{ mini.pseudo }}{% endif %} ({{ mini.nb_acces }} accès)</li>
    {% empty %}
    <li>Il n'y en a pas actuellement.</li>
    {% endfor %}
</ul>
<h1>Raccourcir une URL</h1>

<form method="post" action="{% url 'url_nouveau' %}">
    {% csrf_token %}
    {{ form.as_p }}
    <input type="submit"/>
</form>

À part la sous-classeMetadu modèle etrequest.get_host, tout le reste a été couvert dans les chapitres précédents. Si quelque chose vous semble étrange, n'hésitez pas à aller relire le chapitre concerné.

Ce TP conclut la partie 2 du tutoriel. Nous avons couvert les bases du framework. Vous devez normalement être capables de réaliser des applications basiques. Dans les prochaines parties, nous allons approfondir ces bases et étudier les autres bibliothèques que Django propose.

En attendant, voici quelques idées d'améliorations pour ce TP :

  • Intégrer un style CSS et des images depuis des fichiers statiques via le tag{% static %};

  • Donner davantage de statistiques sur les redirections ;

  • Proposer la possibilité de rendre anonyme une redirection ;

  • Etc.

Example of certificate of achievement
Example of certificate of achievement