Водич за прављење апликације за скраћивање УРЛ-ова помоћу Дјанга

Najbolji pristup za učenje Django-a, ili bilo koje veštine, jeste primena stečenog znanja kroz razvoj funkcionalnih projekata.

Django je veoma popularan Python framework za razvoj veb aplikacija. Zahvaljujući svojim ugrađenim funkcionalnostima i velikom broju eksternih paketa, postao je jedan od najomiljenijih veb framework-a širom sveta.

On je brz, pouzdan i nudi mnoge ugrađene mogućnosti. Na primer, ima sistem za autentifikaciju korisnika, što vam omogućava da se koncentrišete na ključne karakteristike vaše aplikacije. Pored toga, možete instalirati spoljne pakete za složenije zadatke, kao što je Django-allauth, koji vam omogućava da registrujete korisnike putem njihovih naloga na društvenim mrežama.

Međutim, da budemo realni, Django je toliko veliki framework da ponekad može biti teško započeti rad sa njim.

Zato ćemo danas napraviti potpuno funkcionalnu Django aplikaciju od nule.

Nakon ovog uputstva, vi ćete:

  • Izraditi aplikaciju za skraćivanje URL-ova
  • Razumeti Django MVT (Model-View-Template) arhitekturu
  • Naučiti proces kreiranja Django projekta

Preduslovi

Sledeći zahtevi su opcioni i mogu vam pomoći da lakše pratite uputstva. Ipak, ne brinite ako nemate iskustva ni sa jednim od njih. Najvažniji je prvi korak.

  • Osnovno razumevanje UNIX komandi (ls, cd, rm, touch)
  • Osnovno razumevanje Python klasa i funkcija
  • Python instaliran na vašem računaru (možda je očigledno, ali moralo je biti pomenuto)
  • Bilo bi dobro ako ste već ranije radili sa Djangom

Sav kod koji se koristi u ovom uputstvu biće dostupan na GitHub repozitorijumu.

Sada, kada su prethodni koncepti jasni, možemo preći na stvar.

Opis projekta

U ovom uputstvu, izgradićete skraćivač URL-ova. Skraćivač URL-ova je usluga koja preuzima dugačak URL i pretvara ga u kraći.

Na primer, ako želite da podelite tvit i uključite link do vašeg sajta, ali ste ograničeni brojem karaktera, možete koristiti skraćivač URL-ova.

Hajde da to ilustrujemo grafikom.

Kao što vidite, skraćivač URL-ova uzima dugačak URL i vraća kraći. To je upravo ono što ćete danas napraviti.

Kroz ovaj projekat, praktično ćete primeniti MVT obrazac, naučiti osnove dizajniranja baze podataka pomoću Django modela, kao i kako da prikažete informacije korisniku kroz prikaze, URL-ove i templejte.

Struktura Django projekta

U osnovi, Django veb sajt se sastoji od jednog projekta i više odvojenih aplikacija. Svaka od tih aplikacija ima svoju specifičnu funkcionalnost i može funkcionisati samostalno.

Zamislite kompleksnu veb aplikaciju poput Stack Overflow. Njena funkcionalnost se zasniva na dva glavna aspekta:

  • Upravljanje korisnicima: prijava, odjava, reputacija, dozvole
  • Forum: pitanja, odgovori, tagovi, filteri

U skladu sa strukturom Django veb sajta, projekat bi se zvao StackOverflow i imao bi dve glavne aplikacije: korisničku aplikaciju i forum aplikaciju.

Svaka od tih aplikacija ima nezavisnu funkcionalnost. To znači da svaka sadrži sav potreban kod za ispravan rad.

To uključuje modele (strukturu baze podataka), prikaze (zahtev i odgovor), specifične URL obrasce, i naravno, šablone i statičke fajlove (slike, CSS, JavaScript). Zbog toga se svaka Django aplikacija može ponovo koristiti, jer može funkcionisati samostalno.

Ukratko, projekat se odnosi na skup konfiguracija i aplikacija koje su namenjene za kreiranje veb aplikacije. S druge strane, Django aplikacija je deo projekta, koja je samostalna (ima sve što je potrebno za rad), a njen cilj je izvršavanje određene operacije.

Podešavanje Django projekta

U ovom odeljku ćete podesiti Django projekat. Za to ćete koristiti različite alate kao što su virtuelno okruženje za organizovanje Python zavisnosti, i najvažnije Django skripte: django-admin i manage.py

Virtuelno okruženje

Uvek preporučujem rad sa virtuelnim okruženjima kada pravite aplikacije koristeći Django. To je najefikasniji način za upravljanje zavisnostima. Ali, glavna svrha je da se izoluju paketi za razvoj od globalnih.

Dakle, kreiraćemo virtuelno okruženje koristeći ugrađenu Python komandu:

Napomena: Za ovaj metod je potreban Python 3.6 ili noviji.

python -m venv .venv

Ova komanda koristi python -m ili python –mod. U suštini, pokreće modul ili biblioteku kao skriptu. Prema ovoj komandi, venv je biblioteka koju pokrećemo, a .venv je ime virtuelnog okruženja koje želimo da kreiramo.

Pojednostavljeno rečeno, ova komanda znači:

Hej, Python, pokreni kao skriptu ugrađenu biblioteku venv i kreiraj virtualno okruženje pod imenom .venv

Sada je vreme da aktiviramo virtuelno okruženje koje smo upravo kreirali, pomoću sledeće komande:

source .venv/bin/activate

Da biste proverili da li imate nula paketa instaliranih u novom venv-u, pokrenite:

pip freeze

Ako ste ispravno aktivirali virtuelno okruženje, nećete dobiti nikakav rezultat. To je zato što još uvek ništa nismo instalirali.

Instaliranje Django-a

Da bismo kreirali našu aplikaciju za skraćivanje URL-ova, počećemo sa instalacijom Django paketa. Django je eksterni paket i zato ga moramo instalirati pomoću Pip-a (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

Napomena: Imajte na umu da znak $ nije ništa drugo do oznaka vašeg shell-a.

Da bismo potvrdili da je instalacija uspešna, proverićemo ponovo instalirane pakete našeg venv-a.

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

Ne brinite ako se verzije koje dobijete razlikuju od mojih. Ako je Django verzije 3.x, možete nastaviti bez problema.

Pokretanje Django projekta

Nakon instalacije Django-a, vreme je da kreiramo strukturu veb stranice za skraćivanje URL adresa. Sećate li se šta je Django projekat? Kreirajmo ga pokretanjem sledeće komande:

django-admin startproject config

Objašnjavajući sve o ovoj komandi, django-admin je alatka komandne linije koja obavlja sve potrebne zadatke za kreiranje Django projekta. „startproject“ je komanda koju pokreće alatka django-admin, a config je naziv projekta koji kreiramo.

Važno je istaći da config može biti bilo koje ime koje želite. Razlog zašto koristim config kao naziv ovog projekta je samo zbog praktičnosti. Lepo je prelaziti sa jednog projekta na drugi i imati istu konvenciju imenovanja. Dakle, ne plašite se korišćenja drugih naziva projekata kada god želite.

Kao što možete primetiti, sada imate folder config/, i u njemu se nalazi mnogo fajlova. Kasnije ćemo razmotriti strukturu fajlova projekta. Za sada, uđimo u direktorijum projekta i pokrenimo lokalni server.

cd config/

Najvažniji fajl koji ćete koristiti je skripta manage.py. Ona ima istu funkcionalnost kao django-admin, ali glavna prednost je što vam omogućava upravljanje podešavanjima prilikom pokretanja projekta.

Sada da vidimo da li sve funkcioniše kako treba:

python manage.py runserver

Kreiranje aplikacije za skraćivanje URL-ova

Vreme je da kreirate glavnu aplikaciju projekta. Za ovaj zadatak koristite fajl manage.py.

python manage.py startapp urlshortener

Ovo kreira Django aplikaciju, sa nazivom urlshortener. Ako pokrenete komandu tree, dobićete nešto poput ovoga:

.
├── 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

Hajde da razjasnimo različite fajlove koji su kreirani do sada. config je naziv našeg projekta i tako je nazvan samo zbog konvencije. U okviru foldera config, imate settings.py, to je fajl u kom se podešavaju sva podešavanja vašeg projekta. urls.py je generalna konfiguracija URL-ova unutar projekta. Definiše putanje URL-ova svih aplikacija unutar projekta.

Ne brinite previše o fajlovima asgi.py i wsgi.py. To su fajlovi koji vam omogućavaju da konfigurišete svoju aplikaciju za implementaciju.

manage.py je Python skripta koja vam omogućava pokretanje svih dostupnih komandi django-admin.

Ako pogledate folder urlshortener, što je naziv aplikacije koju ste upravo kreirali, možete primetiti da postoji neobičan folder koji se zove migrations/ i nekoliko drugih fajlova koji su ključni za logiku svake aplikacije.

apps.py je mesto gde se nalazi konfiguracija aplikacije. Obično ne vršite izmene u njemu, osim ako ne radite prilično napredne stvari.

admin.py je mesto gde registrujete svoje modele kako bi bili vidljivi u Django admin panelu.

models.py je najvažniji. U ovom modulu morate da definišete modele, koji su (u najširem smislu) način na koji se podaci čuvaju. Kasnije ćete čuti više o modelima.

migrations/ je folder u kom se čuvaju Django migracije. Kasnije ćemo detaljnije pogledati.

tests.py je fajl u kom se čuvaju testovi. U ovom uputstvu se nećemo baviti testiranjem.

views.py je fajl u kom se čuvaju prikazi (views). U suštini, definiše kako će korisnik komunicirati sa svim aspektima vaše aplikacije.

Instalacija Django aplikacije

Pre nego što nastavite, otvorite fajl settings.py i izmenite promenljivu INSTALLED_APPS dodavanjem aplikacije urlshortener.

# 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',
]

Ovo je rutinski proces kada kreirate aplikaciju. Dakle, svaki put kada to uradite, ne zaboravite da je instalirate u podešavanjima projekta.

Razumevanje MVT obrasca

Obrazac Model, View, Template je obrazac dizajna softvera koji Django programeri koriste za kreiranje veb aplikacija.

Zasnovan je na 3 glavna koncepta: Model (podaci), View (interakcija korisnika sa podacima), Template (način na koji korisnici vide podatke).

Modeli su Python klase koje definišu sva polja i ponašanje podataka koje želite da čuvate. Obično se svaki model odnosi na jedinstvenu tabelu u bazi podataka.

Prikazi, u svom najjednostavnijem obliku, su funkcije koje primaju zahtev od korisnika i generišu odgovor. Između tog procesa se dešava poslovna logika. Znam da je „poslovna logika“ prilično nejasan koncept, zato da objasnim šta tačno jeste. Poslovna logika je način na koji se podaci kreiraju, čuvaju i brišu, to je sve.

Konačno, template-i su tekstualni dokumenti (obično HTML) koji se prikazuju korisnicima. Njihova svrha je da prikažu podatke na što jasniji način. Django uključuje mini jezik koji se zove Django Template Language (DTL) koji vam omogućava da ugradite neke od moći Pythona u tekstualne dokumente.

Kreiranje modela Shortener

Nakon što ste na brzinu razumeli MVT obrazac, kreiraćemo Django URL skraćivač od nule.

Pre svega, definišimo model skraćivača u fajlu models.py.

'''
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}'

Znam, to je prilično obimna klasa, sa mnogo neobičnih stvari, ali ne brinite. Objasniću svaki važan aspekt korak po korak.

Objašnjenje modela

Pre svega, uvozimo module modela. Ovaj modul sadrži svu funkcionalnost koja nam je potrebna za kreiranje Django modela.

Kada pogledamo model Shortener, prva stvar koju treba primetiti je da on proširuje models.Model. Zapravo, svaki model u bilo kojoj Django aplikaciji mora biti podklasa models.Model klase.

Zatim, definišemo sva polja koja će model imati u bazi podataka. Polje created je datum i vreme kreiranja skraćenog linka, pa koristimo DateTimeField za kreiranje ove vrste funkcionalnosti. Koristimo argument auto_now_add=True jer želimo da se polje menja samo kada se instanca kreira.

Drugo polje, times_followed, se odnosi na broj korišćenja skraćenog URL-a. To je PositiveIntegerField i postavljamo podrazumevanu vrednost na nulu. To znači da svaki put kada instanca kreira polje times_followed, Django će popuniti to polje sa 0.

S druge strane, long_url se odnosi na URL koji korisnik unosi. To je URLField, jer želimo samo da korisnik unosi karaktere u formatu: http://vas-sajt.com.

Poslednje polje je short_url i ima zanimljive detalje. Navodimo da može imati samo 15 karaktera, mora biti jedinstveno, što znači da se elementi u tom polju ne mogu ponavljati. Na kraju, naglašavamo da može biti prazno, što znači da korisnici neće morati da pišu sopstveni skraćeni kod kada rade sa obrascima.

Unutrašnja klasa Meta nam govori kako klasa mora da se ponaša, i postavljamo da će redosled (pozivanjem Shortener.objects.all()) objekata skraćivača biti diskriminisan najnovijim.

Metoda __str__ govori kako model treba da bude prikazan. Dakle, ako imamo objekat sa long_url = „https://wds.com/“ i skraćenim delom „123456“, i mi ga štampamo:

https://techblog.co.rs.com/ to 123456

Sada je vreme da potražimo način da sačuvamo kratak link na slučajan način.

Kreiranje funkcionalnosti za skraćivanje

Kreiraćemo 2 prilagođene funkcije. Prva će generisati slučajan kod, a druga će sprečiti dobijanje ponovljenih slučajnih kodova iz Shortener modela. Za to, kreirajte fajl utils.py u okviru aplikacije „urlshortener“.

touch utils.py

Unutar ovog fajla, koristimo funkciju choice iz ugrađenog modula random. Ovo olakšava zadatak odabira slučajnih karaktera za kreiranje koda.

'''
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)]
    )

Kao što vidite, ova funkcija vraća nasumičan string dužine navedene u fajlu za podešavanja ili, po default-u, 7. Koristite funkciju getattr da biste dobili promenljivu iz modula podešavanja, bez greške ako promenljiva nije navedena.

Hajde da malo izračunamo. Ako imamo 7 mesta gde može biti do 62 dostupna karaktera za svako mesto, moguće permutacije su:

Dakle, na osnovu ovih brzih proračuna, skraćeni deo može biti popunjen sa do 2,5 triliona različitih kodova. Zbog toga možemo zaboraviti na isticanje nasumičnih skraćenih URL-ova.

Iako može postojati toliko permutacija, mala je verovatnoća da će se skraćeni delovi ponoviti. Ovo je problem zato što smo postavili da polje shortened_url bude jedinstveno. Zbog toga je sledeća funkcija tako korisna.

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

Hajde da vidimo šta se ovde dešava. Funkcija uzima kao argument instancu modela Shortener. Prvo, funkcija generiše slučajan kod koristeći create_random_code. Zatim, dobija klasu modela i proverava da li postoji još neki objekat koji ima isti short_url. Ako postoji, funkcija se ponovo pokreće, ali ako je sve u redu, vraća random_code.

Kasnije ćete imati priliku da se detaljnije upoznate sa ovom funkcijom kroz shell.

Nakon kreiranja pomoćne funkcije, iskoristimo je za kreiranje nasumičnih kodova u modelu skraćivača.

Promena načina čuvanja

Na kraju klase Shortener, izmenićete metodu čuvanja modela. Metoda save se poziva svaki put kada se objekat sačuva u bazi podataka, tako da ćemo ovde videti kako da je koristimo.

# 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)

Metoda save se zamenjuje, što znači da uvodite novu funkcionalnost postojećoj roditeljskoj metodi. U osnovi, govorite Django-u da svaki put kada se sačuva Shortener objekat, a short_url nije naveden, on mora biti popunjen nasumičnim kodom.

Pokretanje migracija

Sada je vreme da kreirate i pokrenete migracije Shortener modela. Za to, pokrenite sledeće komande u osnovnom folderu projekta.

$ 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

Za sada ne morate da brinete o tome šta su migracije. Samo imajte na umu da Django prilikom pokretanja ove dve komande, kreira db.sqlite fajl baze podataka, na osnovu modela koje ste definisali.

Napravimo neke objekte koristeći Django shell:

$ python manage.py shell

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

Tako će otprilike funkcionisati svi objekti za skraćivanje.

Pisanje prikaza (Views)

Kao što sam već rekao, pogled (view) je jednostavna funkcija koja prima zahtev i vraća odgovor. Dakle, da vidimo kako da kreiramo osnovni pogled.

Osnovni template odgovora

U fajlu „urlshortener/views.py“ kreirajte funkciju home_view.

'''
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")

Ona vraća jednostavnu poruku „Hello world“. Kasnije ćete videti kako to izgleda u pregledaču. Sada kreirajte fajl „urls.py“, tamo će biti smešteni svi URL obrasci aplikacije.

touch urls.py

Dodajte sledeći kod:

'''
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")
]

Promenljiva appname deklariše (kao što i ime sugeriše) namespace aplikacije urlshortener.

Ukratko, uvozimo funkciju path koja vraća element koji treba da bude uključen u URL obrasce aplikacije. Atribut name je namespace putanje, koji se može pozvati unutar šablona, ako je to potrebno.

Sada izmenimo sve URL adrese projekta.

# 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'))
]

Sada ponovo pokrenite server.

python manage.py runserver

Ako pokrenete server, dobićete jednostavnu poruku „Hello world“. To je zato što uključujete obrasce URL-ova iz aplikacije za skraćivanje URL-ova u ceo projekat.

Ovo je samo početna tačka. Sada je vreme da napravite obrazac koji će omogućiti korisniku da sam kreira skraćene URL adrese.

Kreiranje obrazaca

U Django-u, obrazac je jednostavna klasa koja omogućava dobijanje unosa od korisnika.

Kreiraćete fajl forms.py. Konvencija je da se svi obrasci aplikacije čuvaju u tom fajlu.

cd urlshortener/
touch forms.py

Unutar tog fajla ćete kreirati klasu „ShortenerForm“, koja nasleđuje „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',)

To je model obrazac, zato što je njegova svrha da kreira objekat modela na osnovu korisničkog unosa. Takođe, koristimo argument widget, koji nam omogućava da navedemo atribut class (klasa u CSS-u, ne u Python-u). To je zato što ćemo kasnije stilizovati aplikaciju koristeći Bootstrap.

Finalizacija prikaza

Nakon kreiranja obrazaca, vreme je da kreirate konačnu poslovnu logiku aplikacije.

Idite do fajla views.py u okviru aplikacije za skraćivanje i izmenite prikaz home_view. Možete pogledati GitHub repozitorijum u ovom trenutku da biste stekli predstavu o tome kako izgleda struktura projekta.

Postoje dva prikaza za aplikaciju za skraćivanje URL-ova:

  • Početni prikaz: ovo prikazuje obrazac za skraćivanje i novi URL ako je obrazac već poslat.
  • Prikaz za preusmeravanje: ovo preusmerava na dugačku URL adresu i dodaje 1 na broj praćenja.

Počnimo sa početnim prikazom koji je najsloženiji. Moraćete da uvezete model i obrazac Shortener. Još uvek koristite funkciju jer želim da razumete ceo tok podataka u pogledu. Takođe, koristićete putanju do šablona (koji još nije kreiran).

Home view

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

from django.http import HttpResponse, Http404, HttpResponseRedirect


# Model
from .models import Shortener

# Custom form

from .forms import ShortenerForm

# Create your views here.

def home_view(request):
    
    template="urlshortener/home.html"

    
    context = {}

    # Empty form
    context['form'] = ShortenerForm()

    if