65. Django | Views - MantsSk/CA_PTUA14 GitHub Wiki
Toliau dirbsime su views. Django turi du views įgyvendinimo mechanizmus, vienas iš jų yra function based, kitas - class based views. Plačiau apie privalumus ir trūkumus ir kodėl apskritai taip yra, jeigu įdomu, pasiskaitykite čia, arba django dokumentacijoje. Mūsų pavyzdys leidžia pademonstruoti abu būdus, tad tą ir padarysime. Pradėsime nuo intuityvesnio, function based.
papildykime /library/urls.py:
urlpatterns = [
path('', views.index, name='index'),
path('authors/', views.authors, name='authors'),
]
atsidarykime views.py ir sukurkime funkciją autorių sąrašui:
def authors(request):
authors = Author.objects.all()
context = {
'authors': authors
}
print(authors)
return render(request, 'authors.html', context=context)
Sukurkime šabloną:
{% extends "base.html" %}
{% block content %}
<h1>Authors</h1>
{% for author in authors %}
<li>{{author.first_name}} {{author.last_name}}</li>
{% endfor %}
{% endblock %}
Tiesiog banaliai išvardinome autorius.
Sekantis logiškas žingsnis būtų, kad paspaudus ant autoriaus vardo-pavardės mus nuvestų į jo aprašymą. Kadangi mūsų autoriai turi labai mažai laukų, kad jų anketos nebūtų labai nykios, sukurkime jiems tekstinį lauką 'description', ir praleiskime migracijas.
description = models.TextField('Description', max_length=2000, default='')
Po to reikia sukurti dinaminį URL maršrutą pavieniams autoriams. Įterpkime eilutę į urlpatterns sąrašą faile /library/urls.py:
path('authors/<int:author_id>', views.author, name='author'),
kaip sufleruoja šios elutės parametrai, reikia sukurti funkciją author faile views.py:
from django.shortcuts import render, get_object_or_404
def author(request, author_id):
author = get_object_or_404(Author, pk=author_id)
context = {
'author': author
}
return render(request, 'author.html', context=context)
- importuojame funkciją, kuri pagal nurodytą primary key traukia konkretų objektą iš modelio Author.
- funkcijos parametruose įrašome author_id. Jį funkcija pasigaus iš naršyklės, priklausomai, ant kurio autoriaus paspausite.
pakoreguokime authors.html taip, kad kiekvienas autorius būtų nuoroda į savo paties aprašymą:
{% for author in authors %}
<li><a href="{% url 'author' author.id %}">{{author.first_name}} {{author.last_name}}</a></li>
{% endfor %}
- {% url 'author' author.id %} perduoda skaičiuką į views.py funkciją. Kuri savo ruožtu pasidalina tuo numeriuku su urls.py, todėl URL adrese matysima kažką panašaus į 127.0.0.1:8000/authors/2
belieka sukurti author.html:
{% extends "base.html" %}
{% block content %}
<div class="container author">
<h4>{{ author.first_name }} {{ author.last_name }}</h4>
<hr/>
<p>{{ author.description }}</p>
</hr>
</br>
<h5>We have these {{ author.first_name }} {{ author.last_name }} books:</h5>
{% for book in author.books.all %}
<li>{{ book.title }}</li>
{% endfor %}
</div>
{% endblock %}
Dabar pamėginkime knygas views'uose išdėlioti per klases. Pirmiausiai papildykime urlpatterns sąrašą:
path('books/', views.BookListView.as_view(), name='books'),
Sukurkime klasę views.py:
from django.views import generic
class BookListView(generic.ListView):
model = Book
template_name = 'book_list.html'
...ir book_list.html:
{% extends "base.html" %}
{% block content %}
<h1>Book list</h1>
{% if book_list %}
<ul>
{% for book in book_list %}
<li>
<a href="{% url 'book-detail' book.id %}">{{ book.title }}</a> ({{ book.author }})
</li>
{% endfor %}
</ul>
{% else %}
<p>No books</p>
{% endif %}
{% endblock %}
Atrodo ganėtinai paprasta ir mažiau kodo. Viską sugeneruoja automatiškai, pagal tam tikras taisykles. Tačiau, jei prireiktų nestandartinių dalykų, tektų pakeitimus nurodyti klasės atributuose. Tarkime:
class BookListView(generic.ListView):
model = Book
# patys galite nustatyti šablonui kintamojo vardą
context_object_name = 'book_list'
# gauti sąrašą knygų su pavadinimu
queryset = Book.objects.filter(title='Title 1')
template_name = 'book_list.html'
Taip pat yra galimybė koreguoti modelio metodus per paveldėjimą:
class BookListView(generic.ListView):
model = Book
def get_queryset(self):
return Book.objects.filter(title='Title 1')
Jei, tarkime, į kontekstą prireiktų pridėti kintamąjį, nesusijusį su pačiu modeliu, galėtume daryti taip:
class BookListView(generic.ListView):
model = Book
def get_context_data(self, **kwargs):
context = super(BookListView, self).get_context_data(**kwargs)
context['data'] = 'random text'
return context
Taigi, views'ai per klases yra šiek tiek greičiau rašomi (kai gerai žinote, ką rašyti), tačiau mažiau intuityvūs, nepanašūs į kitų web karkasų metodus. Jeigu modelis turi potencialą darytis sudėtingas, ateityje gali kilti sunkumų, todėl mėgstantiems tiesiog rezultatą, būtų pasiūlymas - iš pradžių CVB view'sų privengti.
Dabar sukursime klasę pavienių knygų aprašymams:
class BookDetailView(generic.DetailView):
model = Book
template_name = 'book_detail.html'
Papildykime urlpatterns sąrašą (urls.py):
path('books/<int:pk>', views.BookDetailView.as_view(), name='book-detail'),
...ir book_detail.html:
{% extends "base.html" %}
{% block content %}
<h1>{{ book.title }}</h1>
<p><strong>Author:</strong> <a href="{% url 'author' book.author.pk %}">{{ book.author }}</a></p>
<p><strong>Description:</strong> {{ book.summary }}</p>
<p><strong>ISBN:</strong> {{ book.isbn }}</p>
<p><strong>Genre:</strong> {{ book.genre.all|join:", " }}</p>
<div style="margin-left:20px;margin-top:20px">
<h4>Copies:</h4>
{% for copy in book.bookinstance_set.all %}
<hr>
<p class="{% if copy.status == 'av' %}text-success{% elif copy.status == 't' %}text-danger{% else %}text-warning{% endif %}">
{{ copy.get_status_display }}
</p>
{% if copy.status != 'av' %}
<p><strong>Due back:</strong> {{ copy.due_back }}</p>
{% endif %}
<p class="text-muted"><strong>Id:</strong> {{ copy.id }}</p>
{% endfor %}
</div>
{% endblock %}
Paskutinis dalykas - tai nesujinginėta navigacija. Sutvarkykime base.html:
{% block sidebar %}
<ul class="sidebar-nav">
<li><a href="{% url 'index' %}">Home</a></li>
<li><a href="{% url 'authors' %}">Authors</a></li>
<li><a href="{% url 'books' %}">Books</a></li>
</ul>
{% endblock %}
Tęsti kurti Django užduotį – Autoservisas:
- Sukurti puslapį (per funkciją views faile), pvz. autoservice/automobiliai, kuriame būtų atvaizduoti visi servise užregistruoti automobiliai.
- Paspaudus ant automobilio nuorodos, būtų rodoma detali informacija apie automobilį (savininkas, automobilio modelis, valstybinis numeris, VIN kodas)
- Sukurti puslapį (per klasę views faile), pvz. autoservice/uzsakymai, kuriame būtų atvaizduoti visi serviso užsakymai.
- Paspaudus ant užsakymo nuorodos, būtų rodoma detali informacija apie užsakymą. Čia pat būtų matomos ir užsakymo eilučių informacija.