Django – #9 – Pierwsza aplikacja – URL-e w szablonach

Wprowadzenie.

Tworząc kolejne projekty z pewnością będziemy wykorzystywali linki do przechodzenia między różnymi stronami. Wpisywanie na szywno url-i, gdy projekt przybiera sporych rozmarów, może spowodować sporą utratę czasu w przypadku gdy zmieni się na przykład jeden element ścieżki. W takiej sytuacji jesteśmy zmuszeni odnaleźć wszystkie adresy url i je poprawić. Django na szczęście dostarcza nam mechanizm przy pomocy, którego proces tworzenia url-i jest zautomatyzowany. 

Zakres artykułu.

  • Tworzenie aplikacji Django – Standardowe tworzenie adresów URL
  • Tworzenie aplikacji Django – Automatyzacja adresów URL
  • Tworzenie aplikacji Django – Przestrzeń nazw dla nazw do adresów URL

Tworzenie aplikacji Django – Standardowe tworzenie adresów URL

W celu zademonstrowania omawianego tematu stwórzmy nowy widok „detail” oraz nowy szablon „detail.html„, który będzie pokazywał szczegóły naszych obejrzanych filmów. 

Plik views.py po zmodyfikowaniu wygląda następująco

from django.http import HttpResponse
from django.shortcuts import render

from .models import WatchedMovies

def error_404_my_view(request, exception):
	return render(request, 'myFirstApp/error404.html')

def index(request):
	movies = WatchedMovies.objects.order_by('title')
	context = {
		'movies': movies,
	}
	return render(request, 'myFirstApp/index.html', context)

def myNextPage(request):
	return HttpResponse("To jest moja następna strona!")

def detail(request, watchedMovies_id):
	movie = WatchedMovies.objects.get(pk=watchedMovies_id)
	context = {
		'movie': movie,
	}
	return render(request, 'myFirstApp/detail.html', context)

W nowo dodanej funkcji pojawia się argument „watchedMovies_id„, który będzie podawany w adresie URL. Argument watchedMovies_id jest przekazywany do metody get() do zmiennej pk (primary key) obiektu. W ten oto sposób pobieramy jeden rekord w postaci obiektu z bazy danych o kluczu podstawowym przypisanym do zmiennej pk. 

Nowy szablon detail.html wygląda następująco

{% extends "myFirstApp/base.html" %}

{% block titlepage %}
    Moja strona
{% endblock %}

{% block mybody %}
    <h1> Szczegóły dla filmu  "{{ movie.title }}"</h1>
    {% if movie %}
        <ul>
            <li>Gatunek - {{ movie.genre }}</li>
            <li>Data premiery - {{ movie.release_date }}</li>
            <li>Moja ocena - {{ movie.rate }}</li>
            </br><h3>Obsada</h3>
            {% for star in movie.stars.all %}
                <li>{{ star }}</li>
            {% endfor %}
        </ul>
    {% else %}
        <p>Brak filmów</p>
    {% endif %}
{% endblock %}

W tej części warto zwrócić uwagę na obiekt stars, który jak pamiętamy był zadeklarowana jako relacja wiele do wielu. Przy pomocy pętli for dokonujemy iteracji po wszystkich obiektach. Abyśmy byli w stanie pobierać dane, należy zastosować metodę .all(), która zwraca iterator obiektów.

Zmapujmy teraz URL na widok w pliku urls.py w aplikacji.

from django.urls import path

from . import views

urlpatterns = [
    path('', views.index, name='index'),
    path('myPage/', views.myNextPage, name='myNextPage'),
    path('<int:watchedMovies_id>/detail/', views.detail, name='myDetail'),
    ]

Jak możemy zauważyć w ścieżce zastosowaliśmy konstrukcję <int:watchedMovies_id>. Konstrukcja ta składa się z dwóch członów. int: odpowiedzialny jest za konwertowanie danej, natomiast druga część watchedMovies_id jest ciągiem znaków, który jest przekazywany jako argument do widoku pod tą samą nazwą.

Po wpisaniu w przeglądarkę adresu http://127.0.0.1:8000/myFirstApp/1/detail/ powinniśmy otrzymać następujący efekt.

Natomiast po wpisaniu adresu http://127.0.0.1:8000/myFirstApp/2/detail/ powinniśmy otrzymać.

Zmodyfikujmy teraz szablon index.html w taki sposób abyśmy mogli poprzez linki przechodzić do strony ze szczegółami o filmach.

{% extends "myFirstApp/base.html" %}

{% block titlepage %}
    My index title
{% endblock %}

{% block mybody %}
    <h1> My index page </h1>
    {% if movies %}
        <ul>
            {% for my_movie in movies %}
                <li><a href="/myFirstApp/{{ my_movie.id }}/detail/">{{ my_movie.title }}</a></li>
            {% endfor %}
        </ul>
    {% else %}
        <p>Brak filmów</p>
    {% endif %}
{% endblock %}

Po wpisaniu w przeglądarkę adresu http://127.0.0.1:8000/myFirstApp powinniśmy otrzymać następujący efekt.

Natomiast jak podejrzymy kod źródłowy zobaczymy jak zostały wygenerowane linki.

Tworzenie aplikacji Django – Automatyzacja adresów URL

Jak już wspomniałem Django dostarcza nam mechanizm, który podmieni za nas wszystkie adresy URL jeżeli skorzystamy z pewnego elementu. Tym elementem jest konstrukcja {% url 'nasza_nazwa_name_w_funkcji_path’ argumenty %}. Na tej podstawie zmodyfikujmy teraz plik index.html

{% extends "myFirstApp/base.html" %}

{% block titlepage %}
    My index title
{% endblock %}

{% block mybody %}
    <h1> My index page </h1>
    {% if movies %}
        <ul>
            {% for my_movie in movies %}
                <li><a href="{% url 'myDetail' my_movie.id %}">{{ my_movie.title }}</a></li>
            {% endfor %}
        </ul>
    {% else %}
        <p>Brak filmów</p>
    {% endif %}
{% endblock %}

Po wpisaniu w przeglądarkę adresu http://127.0.0.1:8000/myFirstApp powinniśmy otrzymać taki sam efekt jak wcześniej oraz kod źródłowy powinien być identyczny. W celu przetestowania, czy na pewno wszystko działa prawidłowo zmodyfikujmy plik urls.py w aplikacji gdzie w adresie zamiast detail wpiszemy details.

from django.urls import path

from . import views

urlpatterns = [
    path('', views.index, name='index'),
    path('myPage/', views.myNextPage, name='myNextPage'),
    path('<int:watchedMovies_id>/details/', views.detail, name='myDetail'),
    ]

Strona pod adresem http://127.0.0.1:8000/myFirstApp nie zmieni się, lecz jeżeli teraz podejrzymy kod źródłowy powinniśmy zobaczyć, że w linkach adres jest już z końcówką s w słowie details

Tworzenie aplikacji Django – Przestrzeń nazw dla nazw do adresów URL

Wprowadzone zmiany jeszcze nie do końca rozwiązują nam wszystkie problemy. W rozbudowanych projektach może zdarzyć się tak, że nazwa name w ścieżce może się powtórzyć w kilku aplikacjach, wtedy Django będzie wybierało pierwszą napotkaną nazwę, a niekoniecznie ta nazwa będzie nas interesowała. W tym przypadku z pomocą przychodzi nam mechanizm przestrzeni nazw, który należy zdefiniować w pliku urls.py naszej aplikacji przy pomocy zmiennej app_name. Zmodyfikowany plik wygląda teraz następująco.

from django.urls import path

from . import views

app_name = 'myFirstApp'

urlpatterns = [
    path('', views.index, name='index'),
    path('myPage/', views.myNextPage, name='myNextPage'),
    path('<int:watchedMovies_id>/details/', views.detail, name='myDetail'),
    ]

Jednakże po wprowadzeniu tych zmian będziemy musieli jeszcze zmodyfikować nasze szablony. Z tego powodu, należy pamiętać o definiowaniu przestrzeni nazw na samym początku tworzenia proejktu, ponieważ jak się rozrośnie, wówczas dostarczymy sobie sporej ilości niepotrzebnej pracy. W naszym przypadku mamy do zmodyfikowania plik index.html oraz error404.html w następujący sposób.

Plik index.html

{% extends "myFirstApp/base.html" %}

{% block titlepage %}
    My index title
{% endblock %}

{% block mybody %}
    <h1> My index page </h1>
    {% if movies %}
        <ul>
            {% for my_movie in movies %}
                <li><a href="{% url 'myFirstApp:myDetail' my_movie.id %}">{{ my_movie.title }}</a></li>
            {% endfor %}
        </ul>
    {% else %}
        <p>Brak filmów</p>
    {% endif %}
{% endblock %}

Plik error404.html

{% extends "myFirstApp/base.html" %}

{% block titlepage %}
    My 404 Error Page 
{% endblock %}

{% block mybody %}
    <h1>Strona nie została znaleziona :(</h1>
    <p>Upewnij się, że wpisałeś poprawnie adres URL</p>
    <a href="{% url 'myFirstApp:index' %}">idź do strony domowej</a>
{% endblock %}

Autor artykułu
Dominik Bednarski

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *