Lag din egen URL-forkorter med Django: Steg-for-steg guide

Lær Django Gjennom Praktisk Prosjektutvikling

Den mest effektive måten å mestre Django, eller hvilken som helst ferdighet, er å anvende kunnskapen gjennom å skape virkelige, funksjonelle prosjekter.

Django er et ledende rammeverk for webutvikling i Python. Dens innebygde funksjoner og omfattende bibliotek av tredjepartsmoduler har gjort det til et av de mest foretrukne webrammeverkene globalt.

Det er raskt, robust og utstyrt med en rekke innebygde funksjoner. Et eksempel er et integrert autentiseringssystem som lar deg fokusere på kjernefunksjonene i din applikasjon. Du kan også installere eksterne moduler for å håndtere mer avanserte oppgaver, som for eksempel Django-allauth, som muliggjør brukeropprettelse gjennom sosiale mediekontoer.

Likevel er det viktig å nevne at Django er et omfattende rammeverk, noe som til tider kan gjøre det litt utfordrende å komme i gang med.

I dag skal vi derfor bygge en fullt funksjonell Django-applikasjon fra bunnen av.

Ved avslutningen av denne veiledningen vil du:

  • Ha utviklet en applikasjon for å forkorte URL-er.
  • Forstå Django MVT-arkitekturen.
  • Ha lært prosessen for å starte et nytt prosjekt.

Forutsetninger

Følgende forutsetninger er valgfrie og vil være til hjelp gjennom denne veiledningen. Men om du mangler erfaring med noen av disse, er det ikke noe problem. Det viktigste er å komme i gang.

  • Grunnleggende forståelse for UNIX-kommandoer (ls, cd, rm, touch)
  • Grunnleggende forståelse for Python-klasser og -funksjoner
  • Python installert på datamaskinen din (dette burde være en selvfølge, men måtte inkluderes).
  • Det vil være en fordel om du har litt tidligere erfaring med å bygge noe i Django.

All kode som brukes i denne veiledningen vil være tilgjengelig i dette Github-repoet.

Nå som du er klar over de nødvendige konseptene, la oss komme i gang.

Prosjektbeskrivelse

I denne veiledningen skal vi utvikle en applikasjon for å forkorte URL-er. En URL-forkorter er i utgangspunktet en tjeneste som transformerer en lang URL til en mer kompakt versjon.

For eksempel, om du ønsker å dele en tweet og inkludere en link til din nettside, men støter på en tegnbegrensning, kan du bruke en URL-forkorter.

La oss illustrere dette visuelt.

Som du ser, tar URL-forkorteren en lang URL og genererer en kort. Det er akkurat det vi skal bygge i dag.

Gjennom dette prosjektet vil du øve på bruken av MVT-arkitekturen, forstå de grunnleggende prinsippene for databasedesign med Django-modeller, og lære hvordan du presenterer informasjon til brukeren via visninger, URL-er og maler.

Strukturen i et Django-prosjekt

Et Django-nettsted er i bunn og grunn bygget på et enkelt prosjekt og flere separate applikasjoner. Hver app har en spesifikk funksjonalitet og kan fungere uavhengig.

La oss tenke oss en kompleks webapplikasjon som Stackoverflow. Funksjonaliteten baseres på to sentrale aspekter:

  • Brukeradministrasjon: Pålogging, Avlogging, Omdømme, Tillatelser
  • Forum: Spørsmål, Svar, Emneknagger, Filtre

I henhold til Django-nettstedets struktur vil prosjektet få navnet StackOverflow, og det vil inneholde to hovedapper: Bruker-appen og Forum-appen.

Hver app fungerer uavhengig. Det betyr at hver enkelt inneholder all den nødvendige koden for å fungere korrekt.

Dette inkluderer modeller (databasestruktur), visninger (forespørsler og svar), spesifikke URL-mønstre, og naturligvis maler og statiske filer (bilder, CSS, JavaScript). Dette innebærer at en Django-applikasjon kan gjenbrukes, da den kan fungere uavhengig.

Kort fortalt refererer et prosjekt til et sett med konfigurasjoner og applikasjoner som er ment å bygge en webapplikasjon. En Django-app derimot, er en del av et prosjekt som er uavhengig (har alt som trengs for å fungere), og formålet er å utføre en bestemt operasjon.

Oppsett av et Django-prosjekt

I denne delen skal vi sette opp et nytt Django-prosjekt. For dette skal vi bruke verktøy som et virtuelt miljø for å organisere Python-avhengigheter og de essensielle Django-skriptene: django-admin og manage.py.

Virtuelt miljø

Det anbefales sterkt å benytte virtuelle miljøer når du utvikler applikasjoner med Django. Det er den mest effektive måten å vedlikeholde et bestemt sett med avhengigheter. Hovedpoenget er imidlertid å isolere utviklingspakkene fra de globale.

La oss lage et virtuelt miljø med Pythons innebygde kommando.

Merk: Denne fremgangsmåten krever Python 3.6 eller nyere for å fungere.

python -m venv .venv

Denne kommandoen bruker «python -m» eller «python –mod» kommandoen. I bunn og grunn kjører den en modul eller et bibliotek, som et skript. I henhold til tolkningen av denne kommandoen, er «venv» biblioteket vi kjører, og «.venv» refererer til navnet på det virtuelle miljøet vi ønsker å lage.

Kommandoen betyr derfor:

Hei Python, kjør det innebygde «venv» biblioteket som et skript, og lag et virtuelt miljø med navnet «.venv»

Nå er tiden inne for å aktivere det virtuelle miljøet vi nettopp har opprettet, med følgende kommando:

source .venv/bin/activate

For å bekrefte at du ikke har noen pakker installert i det nye virtuelle miljøet, kan du kjøre:

pip freeze

Om du har aktivert det virtuelle miljøet korrekt, vil du ikke få noe output. Det er fordi vi ennå ikke har installert noe.

La oss introdusere Django

For å lage vår URL-forkorter applikasjon, starter vi med å installere Django-pakken. Django er en tredjepartspakke, og må derfor installeres med Pip (Pip Installs Packages).

$ pip install django
Collecting django
  Downloading Django-3.2.1-py3-none-any.whl (7.9 MB)
     |████████████████████████████████| 7.9 MB 344 kB/s 
Collecting asgiref<4,>=3.3.2
  Using cached asgiref-3.3.4-py3-none-any.whl (22 kB)
Collecting sqlparse>=0.2.2
  Using cached sqlparse-0.4.1-py3-none-any.whl (42 kB)
Collecting pytz
  Using cached pytz-2021.1-py2.py3-none-any.whl (510 kB)
Installing collected packages: asgiref, sqlparse, pytz, django
Successfully installed asgiref-3.3.4 django-3.2.1 pytz-2021.1 sqlparse-0.4.1

Merk: Husk at «$» kun er en indikasjon på ditt skall-miljø.

For å bekrefte at installasjonen gikk riktig, sjekker vi igjen de installerte pakkene i det virtuelle miljøet.

$ pip freeze
asgiref==3.3.4
Django==3.2.1
pytz==2021.1
sqlparse==0.4.1

Ikke bekymre deg om versjonene du får er ulike de som vises her. Så lenge Django er på versjon 3.x kan du fortsette uten problemer.

Start et Django-prosjekt

Etter at du har installert Django er tiden inne for å skape strukturen for URL-forkorter nettsiden. Husker du hva et Django-prosjekt er? La oss lage et ved å kjøre følgende kommando:

django-admin startproject config

For å forklare denne kommandoen: «django-admin» er et kommandolinjeverktøy som utfører de nødvendige oppgavene for å skape et Django-prosjekt. «startproject»-delen er kommandoen som blir kjørt av «django-admin» verktøyet, og «config» er navnet på prosjektet vi skal lage.

Det er viktig å understreke at «config» kan være et hvilket som helst navn du ønsker. Grunnen til at jeg bruker «config» som navn på dette prosjektet er kun for praktisk bruk. Det er hensiktsmessig å kunne bytte mellom prosjekter og fortsatt ha den samme navnekonvensjonen. Så ikke vær redd for å benytte andre prosjektnavn når det måtte passe deg.

Du vil nå se at du har en «config/» mappe med flere filer inni. Vi skal se på filstrukturen i prosjektet senere. La oss for nå gå inn i prosjektkatalogen og kjøre den lokale serveren.

cd config/

Den viktigste filen du kommer til å bruke er «manage.py»-skriptet. Det har samme funksjonalitet som «django-admin», men den store fordelen med å bruke det er at det lar deg håndtere innstillingene når du kjører prosjektet.

La oss se om alt fungerer som det skal.

python manage.py runserver

Opprette URL-forkorter App

Nå er det på tide å skape hovedapplikasjonen til prosjektet. Du skal bruke «manage.py»-filen for å utføre denne oppgaven.

python manage.py startapp urlshortener

Dette skaper en Django-applikasjon, med navnet «urlshortener». Om du kjører «tree» kommandoen, vil du få noe som dette:

.
├── config
│   ├── asgi.py
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── manage.py
└── urlshortener
    ├── admin.py
    ├── apps.py
    ├── __init__.py
    ├── migrations
    │   └── __init__.py
    ├── models.py
    ├── tests.py
    └── views.py

La oss klargjøre de forskjellige filene som er skapt så langt. «config» er navnet på prosjektet vårt og det heter dette kun etter konvensjon. Inne i config finner du «settings.py», som er filen der du definerer alle innstillingene for prosjektet ditt. «urls.py» er den overordnede konfigurasjonen for URL-ene i prosjektet. Den definerer URL-banene til alle applikasjonene i prosjektet.

Ikke bekymre deg for mye for filene «asgi.py» og «wsgi.py». Dette er filer som lar deg konfigurere applikasjonen din under distribusjon.

«manage.py» er Python-skriptet som lar deg kjøre alle de tilgjengelige kommandoene for Django-admin.

Når du tar en titt på «urlshortener», som er navnet på applikasjonen du nettopp opprettet, vil du se en merkelig mappe kalt «migrations/» og noen andre filer som er avgjørende for logikken i en hver applikasjon.

«apps.py» er stedet der applikasjonens konfigurasjon er lagret. Vanligvis er det ikke nødvendig å endre denne, med mindre du skal gjøre noe mer avansert.

«admin.py» er filen der du registrerer modellene dine for å gjøre dem synlige i Django sitt administrasjonspanel.

«models.py» er en av de viktigste filene. I denne modulen skal du definere modellene som (grovt sagt) er måten dataene blir lagret på. Du skal lære mer om modeller senere.

«migrations/» er mappen der Django-migreringer er lagret. Vi skal se nærmere på dette senere.

«tests.py» er filen der tester er lagret. Vi skal ikke dekke testing i denne veiledningen.

«views.py» er filen som inneholder visninger. I utgangspunktet definerer den hvordan brukeren interagerer med alle aspekter av applikasjonen din.

Installere en Django-applikasjon

Før du fortsetter, åpne «settings.py»-filen og modifiser «INSTALLED_APPS»-variabelen ved å legge til «urlshortener»-applikasjonen.

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # Custom apps
    'urlshortener',
]

Dette er en rutinemessig prosedyre når du lager en applikasjon. Så hver gang du gjør dette, må du huske å installere den i prosjektinnstillingene.

Forstå MVT-arkitekturen

Model, View, Template-arkitekturen er et programvaredesignmønster som Django-utviklere benytter for å lage webapplikasjoner.

Den er basert på 3 hovedkonsepter: Modell (data), Visning (brukerens interaksjon med data) og Mal (hvordan brukerne ser dataene).

Modeller er Python-klasser, som definerer alle feltene og oppførselen til dataene du ønsker å lagre. Vanligvis refererer hver modell til en unik tabell i databasen.

Visninger, i sin enkleste form, er kallbare elementer som mottar en forespørsel fra brukeren og genererer et svar. Mellom denne prosessen oppstår forretningslogikken. Jeg vet at «forretningslogikk» kan være litt vagt, så la meg forklare hva det betyr. Forretningslogikk er hvordan data opprettes, lagres og slettes – det er alt.

Til slutt, maler er tekstfiler (vanligvis HTML) som presenteres til brukerne. Formålet er å presentere data på en mest mulig enkel måte. Django inneholder et lite språk kalt Django Templating Language (DTL) som lar deg inkorporere noe av kraften i Python inn i tekstfiler.

Lag en Forkorter-Modell

Når du har en grunnleggende forståelse av MVT-arkitekturen, la oss starte med å lage Django URL-forkorteren fra bunnen av.

La oss først definere forkorter-modellen i «models.py»-filen.

'''
Url shortener model
'''

from django.db import models

# Create your models here.

class Shortener(models.Model):
    '''
    Creates a short url based on the long one
    
    created -> Hour and date a shortener was created 
    
    times_followed -> Times the shortened link has been followed

    long_url -> The original link

    short_url ->  shortened link https://domain/(short_url)
    ''' 
    created = models.DateTimeField(auto_now_add=True)

    times_followed = models.PositiveIntegerField(default=0)    

    long_url = models.URLField()

    short_url = models.CharField(max_length=15, unique=True, blank=True)

    class Meta:

        ordering = ["-created"]


    def __str__(self):

        return f'{self.long_url} to {self.short_url}'

Jeg vet at det er en ganske stor klasse med mye rart som skjer, men ikke fortvil. Jeg skal gå gjennom alt steg for steg.

Modell Forklaring

Først og fremst importerer vi modellmodulen. Denne modulen inneholder all funksjonaliteten vi trenger for å lage en Django-modell.

Ta en titt på «Shortener»-modellen. Det første som bør legges merke til er at den utvider modellene. Faktisk må enhver modell i en Django-applikasjon være en underklasse av models.Model klassen.

Deretter definerer vi alle feltene modellen skal ha i databasen. «created» feltet er datoen og tiden den forkortede lenken ble opprettet, derfor bruker vi DateTimeField for denne typen funksjonalitet. Vi bruker argumentet «auto_now_add=True» fordi vi ønsker at feltet kun skal endres når objektet blir opprettet.

Det andre feltet, «times_followed», refererer til antall ganger den forkortede URL-en har blitt brukt. Det er en «PositiveIntegerField», og vi spesifiserer en standardverdi på null. Dette betyr at hver gang et nytt objekt har opprettet feltet «times_followed», vil Django fylle ut dette feltet med 0.

På den annen side refererer «long_url» til URL-en som brukeren oppgir. Det er et URL-felt, fordi vi kun ønsker at brukeren skal skrive inn tegn som samsvarer med formatet: «http://dinside.com».

Det siste feltet er «short_url», og har interessante detaljer. Vi spesifiserer at den kun kan være 15 tegn lang, den må være unik, noe som betyr at det ikke kan være dupliserte elementer i dette feltet. Og til slutt indikerer vi at den kan være tom, noe som betyr at når du jobber med skjemaer trenger ikke brukeren å skrive inn sin egen forkortede kode.

Den interne «Meta» klassen forteller oss hvordan klassen skal oppføre seg. Vi definerer at rekkefølgen (ved å kalle «Shortener.objects.all()») av «shortener»-objektene skal diskrimineres ut fra de nyeste.

«__str__»-metoden forteller hvordan modellen må skrives ut. Så om vi har et objekt med «long_url» = «https://tipsbilk.net.com/» og den forkortede delen «123456» og vi printer det ut:

https://tipsbilk.net.com/ to 123456

Nå er det på tide å finne en måte å lagre den korte lenken på en tilfeldig måte.

Opprette Forkortingsfunksjonalitet

Vi skal lage 2 tilpassede funksjoner. Den første vil generere en tilfeldig kode, og den andre vil hindre at tilfeldige koder gjentas i «Shortener»-modellen. For å gjøre dette, opprett en fil «utils.py» i «urlshortener»-applikasjonen.

touch utils.py

Inne i denne filen skal vi bruke «choice»-funksjonen fra den tilfeldige innebygde modulen. Dette gjør det enklere å velge tilfeldige tegn for å skape koden.

'''
Utilities for Shortener
'''
from django.conf import settings

from random import choice

from string import ascii_letters, digits

# Try to get the value from the settings module
SIZE = getattr(settings, "MAXIMUM_URL_CHARS", 7)

AVAIABLE_CHARS = ascii_letters + digits


def create_random_code(chars=AVAIABLE_CHARS):
    """
    Creates a random string with the predetermined size
    """
    return "".join(
        [choice(chars) for _ in range(SIZE)]
    )

Som du ser, returnerer denne funksjonen en tilfeldig streng med en lengde spesifisert i innstillingsfilen, eller 7 som standard. Du bruker «getattr» funksjonen for å hente en variabel fra innstillingsmodulen, men uten å gi en feil om variabelen ikke er spesifisert.

La oss kalkulere litt. Om vi har 7 plasser som kan bestå av opptil 62 tilgjengelige tegn, er det mulighetskombinasjoner som følger:

Så basert på disse enkle utregningene, kan den forkortede delen fylles ut med opptil 2,5 billioner forskjellige koder. Dermed kan vi se bort i fra muligheten for å gå tom for tilfeldige forkortede nettadresser.

Selv om det eksisterer så mange kombinasjoner, er det en liten sannsynlighet for å få gjentatte forkortede deler. Dette er et problem ettersom vi satt feltet «shortened_url» til å være unikt. Derfor er den følgende funksjonen så nyttig.

def create_shortened_url(model_instance):
    random_code = create_random_code()
    # Gets the model class

    model_class = model_instance.__class__

    if model_class.objects.filter(short_url=random_code).exists():
        # Run the function again
        return create_shortened_url(model_instance)

    return random_code

La oss se hva som skjer her. Funksjonen mottar en «Shortener»-modellforekomst som argument. Først genererer funksjonen en tilfeldig kode ved hjelp av «create_random_code». Deretter henter den modellklassen og sjekker om det finnes andre objekter som har samme «short_url». Om den gjør det, kjører den seg selv på nytt, men om alt er i orden returnerer den «random_code».

Senere skal du interagere med skallet for å se nærmere på denne funksjonen.

Etter å ha opprettet verktøyfunksjonen, skal vi bruke den for å lage tilfeldige koder i «shortener»-modellen.

Endre Lagringsmetoden

Nederst i «Shortener»-klassen skal du endre modell-lagringsmetoden. Lagringsmetoden blir kalt hver gang et objekt blir lagret i databasen, så vi skal se hvordan man bruker den her.

# Import the function used to create random codes
from .utils import create_shortened_url

# At the end of the  Shortener model
    def save(self, *args, **kwargs):

        # If the short url wasn't specified
        if not self.short_url:
            # We pass the model instance that is being saved
            self.short_url = create_shortened_url(self)

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

Lagringsmetoden blir overskrevet, som betyr at du introduserer ny funksjonalitet i en eksisterende overordnet metode. I bunn og grunn sier vi til Django at hver gang et «Shortener»-objekt lagres og «short_url» ikke er spesifisert, må den fylles med en tilfeldig kode.

Kjøre Migreringer

Nå er det på tide å utføre og kjøre migreringene av «Shortener»-modellen. For å gjøre det, kjør de følgende kommandoene i rotprosjektmappen.

$ python manage.py makemigrations
Migrations for 'urlshortener':
  urlshortener/migrations/0001_initial.py
    - Create model Shortener

$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions, urlshortener
Running migrations:
  ......
  # Apply the URL shortener migrations
  Applying urlshortener.0001_initial... OK

For øyeblikket trenger du ikke å bekymre deg for hva migreringer er. Bare husk at når du kjører disse to kommandoene, oppretter Django en db.sqlite database fil, basert på modellene du har definert.

La oss skape noen objekter med Django-skallet.

$ python manage.py shell

>>> from urlshortener.models import Shortener
>>> s = Shortener(long_url="https://tipsbilk.net.com")
>>> s.short_url
''
>>> s.save()
>>> s.short_url
'kdWFVIc'
>>> s.long_url
'https://tipsbilk.net.com'
>>> print(s)
https://tipsbilk.net.com to kdWFVIc

Det er slik alle «shortener»-objektene kommer til å fungere.

Skrive Visninger

Som tidligere nevnt, er en visning en enkel funksjon som tar en forespørsel og returnerer et svar. La oss se hvordan man lager en «hello world» visning.

Grunnleggende Mal Svar

Lag en funksjon «home_view» inne i filen «urlshortener/views.py».

'''
Shortener views
'''
from django.shortcuts import render, get_object_or_404 # We will use it later

from django.http import HttpResponse 

# Create your views here.

def home_view(request):
    return HttpResponse("Hello world")

Den returnerer en enkel melding, «Hello world». Senere skal du se hvordan det ser ut i nettleseren. Opprett nå en «urls.py» fil, der alle URL-mønstrene til appen skal ligge.

touch urls.py

Legg til følgende kode.

'''
Urls for shortener app urlshortener/urls.py
'''

from django.urls import path

# Import the home view
from .views import home_view

appname = "shortener"

urlpatterns = [
    # Home view
    path("", home_view, name="home")
]

«Appname»-variabelen deklarerer (som navnet tilsier) navneområdet for «urlshortener»-appen.

For å forklare raskt, vi importerer path funksjonen, som returnerer et element som skal inkluderes i URL-mønstrene til appen. «Name»-attributtet er navneområdet til stien, som kan brukes i maler ved behov.

La oss nå endre de overordnede prosjektadressene.

# config/urls.py

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    
    # Shortener Urls
    path('', include('urlshortener.urls'))
]

La oss nå kjøre serveren igjen.

python manage.py runserver

Om du kjører serveren, skal du få en enkel «Hello world» melding. Dette er fordi du inkludere URL-mønstrene fra URL-forkorter applikasjonen i det totale prosjektet.

Dette er kun et utgangspunkt. Nå er det på tide å lage et skjema for å la brukerne lage forkortede URL-er selv.

Opprette Skjemaer

I Django er et skjema en enkel klasse som gjør det mulig å motta data fra brukeren.

Du skal lage en «forms.py» fil. Det er en konvensjon å lagre alle skjemaene til applikasjonen i denne filen.

cd urlshortener/
touch forms.py

Inne i denne filen skal du lage en klasse «ShortenerForm» som strekker seg fra «ModelForm».

'''
Shortener Forms urlshortener/forms.py
'''

from django import forms

from .models import Shortener

class ShortenerForm(forms.ModelForm):
    
    long_url = forms.URLField(widget=forms.URLInput(
        attrs={"class": "form-control form-control-lg", "placeholder": "Your URL to shorten"}))
    
    class Meta:
        model = Shortener

        fields = ('long_url',)

Dette er et modellskjema, siden formålet er å lage