Skip to content

Django: Create, Update, Delete rodinių klasės

DonatasNoreika edited this page Jan 23, 2024 · 54 revisions

Create, Update, Delete rodinių klasės

ListView klasė

Iš pradžių sukuriame (patobuliname jau įprastą ListView). Tam, kad šį puslapį galėtų peržiūrėti tik prisijungę vartotojai, paveldime LoginRequiredMixin. Faile library/views:

from django.views import generic
from django.contrib.auth.mixins import LoginRequiredMixin

class BookInstanceListView(LoginRequiredMixin, generic.ListView):
    model = BookInstance
    context_object_name = "instances"
    template_name = 'instances.html'

Sukuriame path, faile library/urls:

    path('instances/', views.BookInstanceListView.as_view(), name='instances'),

Sukuriame html, faile instances.html:

{% extends "base.html" %}
{% block "title" %}Knygų egzemplioriai{% endblock%}
{% block "content" %}

<h1>Egzemplioriai:</h1>
{% for instance in instances %}
<p><a href="{% url 'instance' instance.pk %}">{{ instance.book }}</a> - {{ instance.uuid }}<span class="{% if instance.is_overdue %}text-danger{% endif %}"> ({{ instance.due_back }},
    {{ instance.get_status_display }})</span></p>
<hr>
{% endfor %}
{% endblock %}

DetailView klasė

from django.views import generic
from django.contrib.auth.mixins import LoginRequiredMixin

class BookInstanceDetailView(LoginRequiredMixin, generic.DetailView):
    model = BookInstance
    context_object_name = "instance"
    template_name = "instance.html"

Sukuriame path, faile library/urls:

    path('instances/<int:pk>', views.BookInstanceDetailView.as_view(), name="instance"),

Sukuriame html. Jei objekto pavadinimas nenurodytas, jo laukus pasiekiame per object.. Faile instance.html.html:

{% extends "base.html" %}

{% block "title" %}Egzempliorius{% endblock%}

{% block "content" %}
<h1>Knygos egzempliorius {{ instance.uuid }}</h1>
<p><strong>Knyga: </strong>{{ instance.book }}</p>
<p><strong>Būsena: </strong>{{ instance.get_status_display }}</p>
<p><strong>Paimta iki: </strong>{{ instance.due_back }}</p>
<p><strong>Paėmė: </strong><img class="rounded-circle" style="width: 30px" src="{{ instance.reader.profile.photo.url }}"> {{ instance.reader }}</p>
{% endblock %}

CreateView klasė

from django.views import generic
from django.contrib.auth.mixins import LoginRequiredMixin

class BookByUserCreateView(LoginRequiredMixin, generic.CreateView):
    model = BookInstance
    fields = ['book', 'due_back']
    success_url = "/library/instances/"
    template_name = 'instance_form.html'

    def form_valid(self, form):
        form.instance.reader = self.request.user
        return super().form_valid(form)

Sukuriame path, faile library/urls:

    path('instances/new', views.BookInstanceCreateView.as_view(), name='instance_new'),

Prie knygos egzemplioriaus pridedame metodą:

    def get_absolute_url(self):
        """Nurodo konkretaus aprašymo galinį adresą"""
        return reverse('book-detail', args=[str(self.id)])

Sukuriame html, faile instance_form.html:

{% extends "base.html" %}
{% block "title" %}Egzemplioriaus kūrimas/redagavimas{% endblock%}

{% block "content" %}
<div class="content-section">
    <form method="POST">
    {% csrf_token %}
    {% load crispy_forms_tags %}
        <legend class="border-bottom mb-4">Knygos Egzemplioriaus kūrimas/redagavimas</legend>
        {{ form|crispy }}
        <div class="form-group">
            <button class="btn btn-outline-info" type="submit">Išsaugoti</button>
        </div>
    </form>
</div>
{% endblock %}

Įdedame į instances.html įdedame mygtuką:

<a class="btn btn-secondary btn-sm mt-1 mb-1" href="{% url 'instance_new' %}">Naujas egzempliorius</a>

PAPILDOMAI:

Jei CreateView view'e prireiktų į formą įdėti kintamąjį (id lauką) iš URL adreso, galime padaryti pavyzdžiui taip:

def form_valid(self, form):
    form.instance.reader = User.objects.get(pk=self.kwargs['pk'])
    return super().form_valid(form)    

UpdateView klasė

Kad knygos įrašą leistų atnaujinti tik tam vartotojui, kuris yra nurodytas jos reader lauke, paveldime UserPassesTestMixin ir perrašome metodą test_func, kuris gražina True tik tuomet, kai reader laukas sutampa su prisijungusiu vartotoju.

from django.views import generic
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.mixins import UserPassesTestMixin

class BookByUserUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
    model = BookInstance
    fields = ['book', 'due_back']
    success_url = "/library/instances/"
    template_name = 'instance_form.html'

    def form_valid(self, form):
        form.instance.reader = self.request.user
        return super().form_valid(form)

    def test_func(self):
        instance = self.get_object()
        return instance.reader == self.request.user

Sukuriame path, faile library/urls:

    path('instances/<int:pk>/update', views.BookInstanceUpdateView.as_view(), name='instance_update'),

Įdedame atnaujinimo nuorodą į failą user_book.html:

{% extends "base.html" %}

{% block "title" %}Knygų egzemplioriai{% endblock%}

{% block "content" %}

<a class="btn btn-secondary btn-sm mt-1 mb-1" href="{% url 'instance_new' %}">Naujas egzempliorius</a>
<br>
<br>
<h1>Egzemplioriai:</h1>
{% for instance in instances %}
<p><a href="{% url 'instance' instance.pk %}">{{ instance.book }}</a> - {{ instance.uuid }}<span class="{% if instance.is_overdue %}text-danger{% endif %}"> ({{ instance.due_back }},
    {{ instance.get_status_display }})</span></p>
{% if instance.reader == user %}
<div>
    <a class="btn btn-secondary btn-sm mt-1 mb-1" href="{% url 'instance_update' instance.id %}">Redaguoti</a>
</div>
{% endif %}
<hr>

{% endfor %}
{% endblock %}

DeleteView klasė

from django.views import generic
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.mixins import UserPassesTestMixin

class BookInstanceDeleteView(LoginRequiredMixin, UserPassesTestMixin, generic.DeleteView):
    model = BookInstance
    success_url = "/library/instances/"
    context_object_name = "instance"
    template_name = 'instance_delete.html'

    def test_func(self):
        instance = self.get_object()
        return instance.reader == self.request.user

Sukuriame path, faile library/urls:

    path('instances/<int:pk>/delete', views.BookInstanceDeleteView.as_view(), name='instance_delete'),

Sukuriame html, faile user_book_delete.html:

{% extends "base.html" %}
{% block "title" %}Egzemplioriaus trynimas{% endblock%}
{% block "content" %}
<div class="content-section">
    <form method="POST">
        {% load crispy_forms_tags %}
        {% csrf_token %}
        <fieldset class="form-group">
        <legend class="border-bottom mb-4">Ištrinti egzempliorių</legend>
            <h2>Ar tikrai norite ištrinti knygos egzempliorių {{ instance.uuid }}?</h2>
        </fieldset>
        <div class="form-group">
            <button class="btn btn-outline-danger" type="submit">Taip, ištrinti</button>
            <a class="btn btn-outline-secondary" href="{% url 'instances' %}">Atšaukti</a>
        </div>
    </form>
</div>
{% endblock %}

Įdedame trynimo nuorodą į failą instances.html:

{% extends "base.html" %}

{% block "title" %}Mano Knygos{% endblock%}

{% block "content" %}

<a class="btn btn-secondary btn-sm mt-1 mb-1" href="{% url 'instance_new' %}">Naujas egzempliorius</a>
<br>
<br>
<h1>Egzemplioriai:</h1>
{% for instance in instances %}
<p><a href="{% url 'instance' instance.pk %}">{{ instance.book }}</a> - {{ instance.uuid }}<span class="{% if instance.is_overdue %}text-danger{% endif %}"> ({{ instance.due_back }},
    {{ instance.get_status_display }})</span></p>
{% if instance.reader == user %}
<div>
    <a class="btn btn-secondary btn-sm mt-1 mb-1" href="{% url 'instance_update' instance.id %}">Redaguoti</a>
    <a class="btn btn-danger btn-sm mt-1 mb-1" href="{% url 'instance_delete' instance.id %}">Ištrinti</a>
</div>
{% endif %}
<hr>

{% endfor %}
{% endblock %}

Kaip padaryti patogesnį datos/laiko įvedimą (datepicker)

models.py faile, modelyje turi būti DateField (arba DateTimeField?):

class BookInstance(models.Model):
    uuid = models.UUIDField(default=uuid.uuid4)
    book = models.ForeignKey(to="Book", verbose_name="Knyga", on_delete=models.CASCADE, related_name="instances")
    due_back = models.DateField(verbose_name="Bus prieinama", null=True, blank=True)
    reader = models.ForeignKey(to=User, on_delete=models.SET_NULL, null=True, blank=True)

view.py faile, CreateView klasėje:

class BookInstanceCreateView(LoginRequiredMixin, generic.CreateView):
    model = BookInstance
    # fields = ['book', 'due_back']
    success_url = "/library/instances/"
    template_name = 'instance_form.html'
    form_class = InstanceForm

    def form_valid(self, form):
        form.instance.reader = self.request.user
        return super().form_valid(form)

forms.py faile, nauja forma ir papildoma klasė:

from .models import BookReview, Profilis, BookInstance

class DateInput(forms.DateInput):
    input_type = 'date'

class UserBookCreateForm(forms.ModelForm):
    class Meta:
        model = BookInstance
        fields = ['book', 'reader', 'due_back']
        widgets = {'reader': forms.HiddenInput(), 'due_back': DateInput()}

Dėmesio: jei lauke norite nustatyti DateTime lauką, tai yra ir datą ir laiką, DateInput klasėje input_type reikšmę pakeiskite iš 'date' į "datetime-local".

instance_form.html faile:

{% extends "base.html" %}
{% block "title" %}Egzemplioriaus kūrimas/redagavimas{% endblock%}

{% block "content" %}
<div class="content-section">
    <form method="POST">
    {% csrf_token %}
    {% load crispy_forms_tags %}
        <legend class="border-bottom mb-4">Knygos Egzemplioriaus kūrimas/redagavimas</legend>
        {{ form|crispy }}
        <div class="form-group">
            <button class="btn btn-outline-info" type="submit">Išsaugoti</button>
        </div>
    </form>
</div>
{% endblock %}

Šio patarimo nuoroda

Užduotis

Tęsti kurti Django užduotį – Autoservisas:

  • Jei reikia, perdaryti vartotojo užsakymų puslapius į ListView ir DetailView klases.
  • Padaryti, kad prisijungęs vartotojas galėtų kurti naujus užsakymus (be eilučių, tik pasirinkęs automobilį ir terminą). Panaudoti CreateView
  • Padaryti, kad prisijungęs vartotojas galėtų redaguoti savo užsakymus. Panaudoti UpdateView
  • Padaryti, kad prisijungęs vartotojas galėtų ištrinti savo užsakymus. Panaudoti DeleteView
  • Padaryti, kuriant arba redaguojant užsakymą, datą ir laiką leistų pasirinkti kalendoriuje/laikrodyje (datetimepicker)

Papildoma užduotis

  • Padaryti, kad vartotojas galėtų savo užsakyme įvesti eilutes (pasirinktas paslaugas ir kiekius). Papildomai - padaryti, kad šias eilutes galima būtų redaguoti/ištrinti.

Atsakymas

Dekoratoriai

Iteratoriai ir generatoriai

RegEx

Pillow

Email

NumPy

Pandas

Seaborn

Mašininis mokymasis

Requests, JSON, API

Web Scraping (Beautiful Soup)

Duomenų bazės

Flask

Django

Django REST

Odoo

Linux

Pabaigimo užduotis: savo programos kūrimas

Clone this wiki locally