Python & Django

Prezentácia

Pylint chyby>

Virtuálne prostredie

Virtualenv oddelí nastavenia Python/Django pre každý projekt zvlášť. To znamená, že zmeny, ktoré sa spravia v jednom projektne, neovplyvnia iné projekty na danom PC. Je potrebné si vytvoriť adresár, kde budeme projekt vyvíjať.

  mkdir myfirstdjango 
cd myfirstdjango
Vytvoríme virtualenv
 conda create -n env python=3.6 anaconda 
conda activate env

Inštalácia Djanga do virtuálneho prostredia

 conda install -n env django

Vytvorenie projektu

 django-admin.exe startproject mysite .

Nastavenia settings.py

Keď DEBUG je True a ALLOWED_HOSTS je prázdne, host je overovaný vôči ['localhost', '127.0.0.1', '[::1]'].

 ALLOWED_HOSTS = []

Existuje veľa rôznych databázových softvérov, ktoré umožňujú ukladať údaje pre web aplikácie. My budeme používať predvolenú databázu - sqlite3.

 DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

Vytvorenie databázy:

 python manage.py migrate

Spustenie webového servera

 python manage.py runserver 
python manage.py runserver 0:8000 #ak sa vyskytne chybová hláška UnicodeDecodeError

Kontrola, či web stránka funguje - otvoríme si http://127.0.0.1:8000/ v browseri

Vytvorenie aplikácie

Django prichádza s nástrojom, ktorý automaticky generuje základnú adresárovú štruktúru aplikácie, takže sa môžeme zamerať skôr na písanie kódu než na vytváranie adresárov.

 python manage.py startapp blog 

To vytvorí adresár blog, ktorý má vyzerať takto:

 blog/
    __init__.py
    admin.py
    apps.py
    migrations/
        __init__.py
    models.py
    tests.py
    views.py 

Po vytvorení aplikácie je potrebné Djangu povedať, že ju má použiť. To urobíme v súbore mysite/settings.py. Pridáme riadok obsahujúci 'blog' tesne pred uzatváraciu zátvorku:

 INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'blog',
] 

Vytvorenie modelu blog postu

Otvoríme si blog/models.py a vložíme tam tento kód

from django.db import models
from django.utils import timezone


class Post(models.Model):
    author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
    title = models.CharField(max_length=200)
    text = models.TextField()
    created_date = models.DateTimeField(
            default=timezone.now)
    published_date = models.DateTimeField(
            blank=True, null=True)

    def publish(self):
        self.published_date = timezone.now()
        self.save()

    def __str__(self):
        return self.title

Je potrebné pridať nový model do databázy. To spravíme nasledujúcimi dvoma príkazmi v konzole:

python manage.py makemigrations blog 
python manage.py migrate blog

Django admin

Na pridávanie, editovanie a mazanie postov, ktoré sme práve namodelovali, budeme používať Django admina.
Otvorme súbor blog/admin.py a nahraďme jeho obsah týmto:

from django.contrib import admin
from .models import Post

admin.site.register(Post)

Importujeme model Post definovaný v predchádzajúcej kapitole. Aby bol náš model viditeľný na adminskej stránke, musíme ho zaregistrovať pomocou admin.site.register(Post).
Pozrieme si náš Post model v administrátorskom rozhraní. Spustíme server a prejdeme na adresu http://127.0.0.1:8000/admin/. Tam sa zobrazí prihlasovacia stránka. Na prihlasovanie je nutné vytvoriť superusera príkazom v konzole:

python manage.py createsuperuser

Výsledok by mal vyzerať takto:

Username: admin
Email address: admin@admin.com
Password:
Password (again):
Superuser created successfully.

V prehliadači sa prihlásime ako superuser, zobrazí sa nástenka (dashboard) Django admina. Pridáme nejaké blog posty (nezabudneme určiť aj dátum publikovania.

Django URL

Chceme, aby 'http://127.0.0.1:8000/' bola domovská stránka nášho blogu a zobrazovala zoznam príspevkov. Tiež chceme udržiavať súbor mysite/urls.py čistý, takže naimportujeme URL z našej aplikácie blog do hlavného súboru mysite/urls.py. Pridáme tam teda riadok, ktorý importuje blog.urls. Tiež treba importovať funkciu include. Súbor mysite/urls.py by mal vyzerať takto:

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

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

Django teraz presmeruje všetko, čo prichádza na 'http://127.0.0.1:8000/' do blog.urls a tam bude hľadať ďalšie inštrukcie.

blog.urls

Vytvoríme prázdny súbor s názvom urls.py v priečinku blog.

Do súboru blog/urls.py vložíme:

 from django.urls import path 
from . import views

urlpatterns = [
path('', views.post_list, name='post_list'),
]

Tým sme priradili view s názvom post_list koreňovej URL.

blog/views.py

View je miesto, kam dávame "logiku" našej aplikácie. Bude požadovať informáciu z modelu a pošle to do šablóny. Šablónu (template) budeme vytvárať neskôr.Views sú umiestnené v súbore views.py. Naše views budeme pridávať do súboru blog/views.py Tam vytvoríme view pre post_list:

def post_list(request):
    return render(request, 'blog/post_list.html', {})

HTML šablóna

Šablóny sú uložené v zložke blog/templates/blog. Takže najprv vytvoríme v zložke blogu zložku s názvom templates. Potom vytvoríme ďalšiu zložku s názvom blog v zložke templates:

blog
└───templates
    └───blog

Následne vytvoríme súbor post_list.html v zložke blog/templates/blog Do neho vložíme:

<html>
    <head>
        <title>My first django blog</title>
    </head>
    <body>
        <div>
            <h1><a href="/">My first django blog</a></h1>
        </div>

        <div>   
        </div>
    </body>
</html>

Django ORM a QuerySety

QuerySet je zoznam objektov daného modelu. QuerySet umožňuje čítať dáta z databázy, filtrovať a zoraďovať ich.

Django shell (konzola)

python manage.py shell 


>>> from blog.models import Post
//Vypísanie všetkyých Post objektov
>>> Post.objects.all()
//Vytvorenie objektu
>>> from django.contrib.auth.models import User
>>> me = User.objects.get(username='admin')
>>> Post.objects.create(author=me, title='Sample title', text='Test')

Dynamické dáta v šablónach

Máme rozdielne kúsky na svojom mieste: Post model je definovaný v models.py, máme post_list v views.py a pridanú šablónu. Ale ako prinútime HTML šablónu, aby zobrazovala náš príspevok? Otvoríme blog/views.py. Musíme zahrnúť model, ktorý sme napísali v models.py. Pridáme import:

from .models import Post 

Teraz upravíme súbor blog/views.py aby vyzeral takto:

from django.shortcuts import render 
from .models import Post

def post_list(request): posts = Post.objects.all() return render(request, 'blog/post_list.html', {'posts': posts})

Posledná chýbajúca časť je predanie posts QuerySetu do šablóny. Vytvárame premennú pre náš QuerySet: posts. Odteraz ho môžeme referovať pod týmto menom.

Šablóny Django

Šablónové tagy v Djangu nám umožňujú previesť Pythonovské veci do HTML. Na vypísanie premennej v Django šablónach použijeme dvojitú zloženú zátvorku s názvom premennej vo vnútri: Do post_list.html vložíme medzi div-y:

{{ posts }} 

To nám však vráti len obyčajný QuerySet, preto si trošku upravíme vzhľad a nahradíme to nasledovným kódom:

{% for post in posts %}
    <div>
        <p>published: {{ post.published_date }}</p>
        <h1><a href="">{{ post.title }}</a></h1>
        <p>{{ post.text|linebreaksbr }}</p>
    </div>
{% endfor %}

CSS a Bootstrap

Chceme si našu stránku trochu skrášiť, preto použijeme Bootstrap. Do head v našom HTML vložíme:

<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">

CSS sa ukladá medzi statické súbory. Django vie, kde ich má hľadať, preto vytvoríme príslušné adresáre. V adresári blog vytvoríme adresár static, v ňom adresár css a v ňom súbor blog.css

blog
     └─── static
          └─── css
               └─── blog.css

Ešte musíme povedať našej HTML šablóne, že sme pridali nejaké CSS. Otvor súbor blog/templates/blog/post_list.html a pridaj tento riadok na úplný začiatok:

{% load static %}

Medzi <head> a </head>, po odkazoch na Bootstrap CSS súbory pridať tento riadok:

<link rel="stylesheet" href="{% static 'css/blog.css' %}">

Tiež si trochu upravíme font a tiež tam pridáme:

<link href="//fonts.googleapis.com/css?family=Lobster&subset=latin,latin-ext" rel="stylesheet" type="text/css">

Pridáme triedu s názvom page-header do divu hlavičky stránky a triedu s názvom post do divu v ktorom je blog post.
Potom si konečne vyplníme css súbor:

.page-header {
    background-color: #ff9400;
    margin-top: 0;
    padding: 20px 20px 20px 40px;
}

.page-header h1, .page-header h1 a, .page-header h1 a:visited, .page-header h1 a:active {
    color: #ffffff;
    font-size: 36pt;
    text-decoration: none;
}

.content {
    margin-left: 40px;
}

h1, h2, h3, h4 {
    font-family: 'Lobster', cursive;
}

.date {
    color: #828282;
}

.save {
    float: right;
}

.post-form textarea, .post-form input {
    width: 100%;
}

.top-menu, .top-menu:hover, .top-menu:visited {
    color: #ffffff;
    float: right;
    font-size: 26pt;
    margin-right: 20px;
}

.post {
    margin-bottom: 70px;
}

.post h1 a, .post h1 a:visited {
    color: #000000;
}

Vytvorenie základnej šablóny

Vytvoríme súbor base.html v blog/templates/blog/ Do nej vložíme:

{% load static %}

<html>
    <head>
        <title>My first django blog</title>
        <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
        <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">
        <link rel="stylesheet" href="{% static 'css/blog.css' %}">
        <link href="//fonts.googleapis.com/css?family=Lobster&subset=latin,latin-ext" rel="stylesheet" type="text/css">
    </head>
    <body>
        <div class="page-header">
                <a href="{% url 'post_new' %}" class="top-menu"><span class="glyphicon glyphicon-plus"></span></a>
            <h1><a href="/">My first django blog</a></h1>
           
        </div>
        <div class="content container">
            <div class="row">
                <div class="col-md-8">
                {% block content %}
                {% endblock %}
                </div>
            </div>
        </div>
    </body>
</html>

A celý post_list.html nahradíme týmto:

{% extends 'blog/base.html' %}

{% block content %}
    {% for post in posts %}
        <div class="post">
            <div class="date">
                {{ post.published_date }}
            </div>
            <h1><a href="">{{ post.title }}</a></h1>
            <p>{{ post.text|linebreaksbr }}</p>
        </div>
    {% endfor %}
{% endblock %}

Vytvorenie šablóny odkazu na post detail

V post_list.html pridáme odkaz na detail stránky, teda daný riadok bude vyzerať takto:

<h1><a href="{% url 'post_detail' pk=post.pk %}">{{ post.title }}</a></h1>

Notácia {% %} znamená, že používame tagy Django šablóny.

Vytvorme URL v súbore blog/urls.py tak, aby odkazoval Django na view nazvaný post_detail, ktorý zobrazí celý príspevok blogu. Pridáme tam riadok:

path('post/<pk>/', views.post_detail, name='post_detail'),

Taktiež do views pridáme view na post_detail : (Nezabudnime pridať import get_object_or_404 z django.shortcuts)

def post_detail(request, pk):
    post = get_object_or_404(Post, pk=pk)
    return render(request, 'blog/post_detail.html', {'post': post})

Ešte nám ostáva vytvoriť si šablónu - post_detail.html. Bude vyzerať takto:

{% extends 'blog/base.html' %}

{% block content %}
    <div class="post">
        {% if post.published_date %}
            <div class="date">
                {{ post.published_date }}
            </div>
        {% endif %}
        <h1>{{ post.title }}</h1>
        <p>{{ post.text|linebreaksbr }}</p>
    </div>
{% endblock %}

Formuláre Django

Posledná vec, ktorú chceme urobiť na našej web stránke je vytvoriť príjemný spôsob pridávania a úpravy blog postov. Vytvoríme formulár pre náš Post model. Tak ako všetky ostatné dôležité časti Djanga, formuláre majú svoj vlastný súbor: forms.py. Musíme vytvoriť súbor s týmto názvom v adresári blog. Do neho vložíme:

from django import forms

from .models import Post

class PostForm(forms.ModelForm):

    class Meta:
        model = Post
        fields = ('title', 'text',)

Link na stránku s formulárom prídáme do blog/templates/blog/base.html. Pridáme link do divu s názvom page-header:

<a href="{% url 'post_new' %}" class="top-menu"><span class="glyphicon glyphicon-plus"></span></a>

Ešte si musíme pridať url pre tento formulár do blog/urls.py

    path('post/new/$', views.post_new, name='post_new'),

Ešte si musíme pridať view pre tento formulár, teda do blog/views.py pridáme:

 from .forms import PostForm

A potom náš view: (Nezabudnime pridať import from django.utils import timezone)

def post_new(request):
    if request.method == "POST":
        form = PostForm(request.POST)
        if form.is_valid():
            post = form.save(commit=False)
            post.author = request.user
            post.published_date = timezone.now()
            post.save()
            return redirect('post_detail', pk=post.pk)
    else:
        form = PostForm()
    return render(request, 'blog/post_edit.html', {'form': form})

Tiež musíme vytvoriť súbor post_edit.html. Aby formulár fungoval, potrebujeme niekoľko vecí: Musíme zobraziť formulár. Môžeme to urobiť (napríklad) pomocou {{ form.as_p }}. Riadok vyššie musí byť obalený HTML tagom:

<form method="POST">...</form>Potrebujeme tlačidlo Uložiť. Vytvoríme ho ako HTML tlačidlo: <button type="submit">Uložiť</button>A nakoniec, hneď za otváracím tagom <form ...> musíme pridať {% csrf_token %}.
Teda post_edit.html bude vyzerať takto:

 {% extends 'blog/base.html' %}

{% block content %}
    <h1>New post</h1>
    <form method="POST" class="post-form">{% csrf_token %}
        {{ form.as_p }}
        <button type="submit" class="save btn btn-default">Save</button>
    </form>
{% endblock %}

Úprava formuláru

Otvor blog/templates/blog/post_detail.html a pridaj tento riadok

 <a class="btn btn-default" href="{% url 'post_edit' pk=post.pk %}"><span class="glyphicon glyphicon-pencil"></span></a>

V blog/urls.py pridáme tento riadok:

 path('post/<pk>/edit/$', views.post_edit, name='post_edit'),

Znova použijeme šablónu blog/templates/blog/post_edit.html, takže posledná vec, čo nám chýba je view. Otvor blog/views.py a na úplný koniec súboru pridaj toto:

def post_edit(request, pk):
    post = get_object_or_404(Post, pk=pk)
    if request.method == "POST":
        form = PostForm(request.POST, instance=post)
        if form.is_valid():
            post = form.save(commit=False)
            post.author = request.user
            post.published_date = timezone.now()
            post.save()
            return redirect('post_detail', pk=post.pk)
    else:
        form = PostForm(instance=post)
    return render(request, 'blog/post_edit.html', {'form': form})

Čas na úlohu!

Teraz chceme, aby sa na každý blog post dali pridávať LIKE-y. Úlohou je pridať do každého detailu postu tlačidlo "Like" a taktiež počítadlo likeov.
S vytvorením HTML buttonu prídem pomôcť :) Have fun!