Django (sissejuhatus)

Lühiülevaate Pythoni veebiraamistikust Django.

Ehitame koos ühe väikse demoprojekti, kus saab lugeda uudiseid. Näide annab vaid minimaalse ülevaate Djangost, seetõttu soovitan kindlasti huvi korral läbi töötada Django ametliku õpetuse.

Django on väga hästi dokumenteeritud, küsimuste tekkides soovitan lugeda Django dokumentatsiooni.

Demoprojekti koodi saab näha Gitlabist.

Uue Django projekti loomine

Uut projekti saab luua nii käsurealt, kui ka PyCharmi kasutades. Siin on välja toodud uue Django projekti tegemiseks vajalikud sammud PyCharmis.

  1. Ava File menüüst New Project ... dialoog.
_images/django-new-project.png
  1. Avanenud aknas vali vasakult Django.
_images/django-new-project2.png
  1. Loo uus projekt vajutades nuppu Create.

Kui ei ole võimalik PyCharmi kasutada, võib jälgida seda juhendit Django installiks ja kirjutada käsureale django-admin startproject mysite. Tekib kaust nimega mysite, mis on meie demoprojekti aluseks.

Esimesed sammud

Tekkinud projektis on algselt selline struktuur:

mysite/
    manage.py
    mysite/
        __init__.py
        settings.py
        urls.py
        wsgi.py
  • Väline kaust mysite/ on kaust, kuhu salvestatakse kogu projekti kood.
  • manage.py on konsooli programm, millega saab projektis erinevaid käske täita. Sellega tutvume hiljem.
  • Sisemine kaust mysite/, on lehekülje pakk. Selles pakis peavad olema defineeritud seadistused ning veebiaadressite URL’id.
  • mysite/__init__.py on tühi fail, mis ütleb Pythonile, et see kaust mysite on pakk.
  • mysite/settings.py Django seadistus
  • mysite/urls.py määrab, millise programmi pannakse käima, kui kasutaja mingile kindlale leheküljele läheb.
  • mysite/wsgi.py serveri jaoks vajalikud seadistused.

Arendusserver

Proovime, kas projekti loomine läks edukalt. Kirjuta konsooli python manage.py runserver või vajuta pycharmis run.

Konsoolli peaks ilmuma midagi sellist:

Performing system checks...

System check identified no issues (0 silenced).

You have 15 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.
October 15, 2018 - 15:10:47
Django version 2.1.2, using settings 'mysite.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

Ning lehel http://127.0.0.1:8000/ peaks olema näha raketti, mis kihutab taeva poole.

Esimene äpp

Django Projekt koosneb mitmetest äppidest. Lihtsa kodulehe puhul võib olla äppideks blogi, galerii, kontakt jne.

Äpp on oma olemuselt Pythoni pakk, me võiksime pakke ise teha, aga Django pakub meile võimalust teha äpp läbi konsooli.

Kirjuta konsooli:

python manage.py startapp news

Tekib uus kaust nimega news.

Lisaks tuleb uus äpp registreerida settings.py failis INSTALLED_APPS nimekirjas.

mysite/settings.py

...
# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'news',  # add this line
]
...

Esimene mudel

Andmeid hoitakse andmebaasis. Andmebaase kirjeldatakse SQL keeles. Djangot kasutades ei pea me uut keelt õppima vaid saame kirjelda objekte Pythoni klassidena. Selliseid objekte kutsutakse andmemudeliteks. Django loob tehtud andmemudelite järgi sobiva andmebaasi.

Muudame faili mysite/news/models.py.

from django.db import models


class Reporter(models.Model):
    full_name = models.CharField(max_length=70)

    def __str__(self):
        return self.full_name


class Article(models.Model):
    pub_date = models.DateField()
    headline = models.CharField(max_length=200)
    content = models.TextField()
    reporter = models.ForeignKey(Reporter, on_delete=models.CASCADE)

    def __str__(self):
        return self.headline

Mudel Reporter on väga lihtne mudel, omades vaid nime.

Mudel Article sisaldab loomiskuupäeva, pealkirja, sisu ning viidet artikli autorile.

Mudelite põhjal andmebaasi muutmiseks vajaliku koodi genereerimiseks jooksutame käsku.

python manage.py makemigrations polls

Kausta news/migrations/ tekkis uus fail 0001_initial.py, selles failis on kirjas, milliseid muudatusi tuleb andmebaasis teha, et meie mudeleid andmebaasi lisada.

Et tehtud muudatused ka andmebaasi jõuaksid tuleb konsoolis jooksutada järgnevat käsku. python manage.py migrate

Selle sammuga otsitakse üles kõik failid */migrations/ kaustas ning tehakse andmebaasi vastavad muudatused.

Katsetused Pythoni interpretaatoriga

Interaktiivse kasutajaliideset (IDLE) kasutades on lihtne katsetada Django API’t andmebaasiga suhtluseks.

IDLE TL;DR: ava PyCharmis aken View -> Tool Windows -> Python Console ja kirjuta koodi.

Näited:

# Import the models we created from our "news" app
>>> from news.models import Article, Reporter

# No reporters are in the system yet.
>>> Reporter.objects.all()
<QuerySet []>

# Create a new Reporter.
>>> r = Reporter(full_name='John Smith')

# Save the object into the database. You have to call save() explicitly.
>>> r.save()

# Now it has an ID.
>>> r.id
1

# Now the new reporter is in the database.
>>> Reporter.objects.all()
<QuerySet [<Reporter: John Smith>]>

# Fields are represented as attributes on the Python object.
>>> r.full_name
'John Smith'

# Django provides a rich database lookup API.
>>> Reporter.objects.get(id=1)
<Reporter: John Smith>
>>> Reporter.objects.get(full_name__startswith='John')
<Reporter: John Smith>
>>> Reporter.objects.get(full_name__contains='mith')
<Reporter: John Smith>
>>> Reporter.objects.get(id=2)
Traceback (most recent call last):
    ...
DoesNotExist: Reporter matching query does not exist.

# Create an article.
>>> from datetime import date
>>> a = Article(pub_date=date.today(), headline='Django is cool',
...     content='Yeah.', reporter=r)
>>> a.save()

# Now the article is in the database.
>>> Article.objects.all()
<QuerySet [<Article: Django is cool>]>

# Article objects get API access to related Reporter objects.
>>> r = a.reporter
>>> r.full_name
'John Smith'

# And vice versa: Reporter objects get API access to Article objects.
>>> r.article_set.all()
<QuerySet [<Article: Django is cool>]>

# The API follows relationships as far as you need, performing efficient
# JOINs for you behind the scenes.
# This finds all articles by a reporter whose name starts with "John".
>>> Article.objects.filter(reporter__full_name__startswith='John')
<QuerySet [<Article: Django is cool>]>

# Change an object by altering its attributes and calling save().
>>> r.full_name = 'Billy Goat'
>>> r.save()

# Delete an object with delete().
>>> r.delete()

Admin paneel

Kui mudelid on tehtud saame me luua rakenduse jaoks admin lehekülje. Djangos on väga lihtne teha administraatorile paneeli - lehte, kus volitatud kasutajad saavad luua, muuta ja kustutada objekte.

Kirjutame news/admin.py faili sellise koodi:

from django.contrib import admin

from . import models

admin.site.register(models.Reporter)
admin.site.register(models.Article)

Et admin leheküljele ligi pääseda peame me looma admin õigustes kasutaja.

Selleks vali PyCharmis Tools -> Run manage.py Task..., avanud konsooli kirjuta:

   createsuperuser

Jälgi juhendeid ekraanil.

Kui Run manage.py Task... menüüd ei saa avada tuleb käsureale kirjutada

python manage.py createsuperuser

Peale kasutaja loomist saad admin paneelile ligi. http://127.0.0.1:8000/admin/

Selle lehe kaudu võib endale luua esialgset sisu.

Esimene lehekülg

URL seadistamine.

Et teha lehekülgi tuleb kõigepealt ära seadistada lehekülje URL’id.

Teeme faili mysite/news/urls.py ning lisame sinna mõned URL’i mustrid.

from django.urls import path

from . import views

urlpatterns = [
    path('articles/<int:year>/', views.year_archive, name="year"),
    path('articles/<int:year>/<int:question_id>/', views.article_detail, name="detail"),
]

See kood ühendab ära URL’id vastavate funktsioonidega views.py failis.

Django otsib kasutaja leheküljele vastavat funktsiooni views.py failist. Kui funktsioon leitakse, siis edastab Django päringu info ning URL’is leiduva info funktsioonile.

Muudame koodi failis mysite/mysite/urls.py, et peamine äpp (mysite) oskaks aadresse, mis algavad kujul news/ edasi suunata mysite/news/urls.py faili.

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

urlpatterns = [
    path('news/', include('news.urls')),
    path('admin/', admin.site.urls),
]

Näide: aadressi news/articles/2005/39323/ põhjal kutsutakse välja funktsioon news.views.article_detail(request, year=2005, question_id=39323).

Vaated

Lisaks aadressi seadistusele tuleb kirjutada ka vaated. Kirjutame kaks lihtsalt vaadet faili news/views.py.

from django.shortcuts import render, get_object_or_404

from .models import Article


def year_archive(request, year):
    articles = Article.objects.filter(pub_date__year=year)
    context = {'year': year, 'article_list': articles}
    return render(request, 'news/year_archive.html', context)


def article_detail(request, year, question_id):
    article = get_object_or_404(Article, pk=question_id) # if article is not found display 404 error.
    context = {'year': year, 'article': article}
    return render(request, 'news/article_detail.html', context)

Meetod render() tagastab HTML lehekülje, võttes argumentideks:

  • päringu objekt;
  • mall, mille põhjal HTML sisu genereerida;
  • kontekst, mida mallis kasutada.

Päring ning kontekst on meil olemas, puudu on vaid mallid ehk templates.

Mallid

Mall on segu html ja pythoni koodist, mille järgi genereeritakse html lehekülgi.

Kuna igal veebileheküljel on kattuvaid osasi, siis loome alustuseks põhja, mida teised mallid saavad laiendada.

Teeme faili news/templates/base.html

<html>
<head>
    <title>{% block title %}{% endblock %}</title>
</head>
<body>
{% block content %}
    <h1>My first site.</h1>
{% endblock content %}
</body>
</html>

Seda malli saavad teised mallid kasutada, kui alammallis on öeldud, et ta laiendab mingit kindlat malli{% extends "base.html" %}. Sellisel juhul saab üle kirjutada ülemmallist osi, mis on {% block block_name %} {% endblock%} vahele kirjutatud.

Nüüd teeme mallid funktsioonidele year_archive ja article_detail, need mallid laiendavad malli base.html.

news/templates/news/year_archive.html

{% extends "base.html" %}

{% block title %}Articles for {{ year }}{% endblock %}

{% block content %}
    <h1>Articles for {{ year }}</h1>

    {% for article in article_list %}
        <div style="border: solid 2px">
            <a href="{% url 'detail' year article.id %}">{{ article.headline }}</a>
            <p>By {{ article.reporter.full_name }}</p>
            <p>Published at {{ article.pub_date|date:"F j, Y" }}</p>
        </div>
    {% endfor %}
{% endblock %}

news/templates/news/article_detail.html

{% extends "base.html" %}

{% block title %}{{ article.headline }}{% endblock %}

{% block content %}
    <h1>{{ article.headline }}</h1>

    <p>By {{ article.reporter.full_name }}</p>
    <p>Published at {{ article.pub_date|date:"F j, Y" }}</p>
    <br>
    <p>{{ article.content|linebreaks }}<p>
    <br>
    <p>Go back to <a href="{% url "year" year %}">{{ year }}</a> articles list.</p>
{% endblock %}

Nüüd peaksid nägema 2018. a artikleid aadressil http://127.0.0.1:8000/news/articles/2018/.

Esimene rakendus ongi valmis.

Kuhu edasi?

Et paremini mõista, kuidas Django kood töötab, soovitan läbida Django ametlikud koolitused.

Seejärel võiks teha läbi paar väiksemat projekti, näiteks proovida teha enda blogi.

Kui koolitused läbitud ja paar väiksemat projekti on tehtud soovitan lugeda raamatut Two Scoops of Django.