menu

Kurs Django Podstawa – #4 – Koszyk – Formularz

Posted on: August 7, 2024

Kurs Django Podstawa – #4 – Koszyk – Formularz

Kurs Django Podstawa – #4 – Koszyk – Formularz

“Koszyk Formularz”

Celem tego rozdziału jest kolejna rozbudowa naszej strony (zobacz rozdział #3 Django). Będziemy chcieli dodać interaktywną funkcjonalność w postaci koszyka w naszym sklepie, który wyświetli nam w formie podsumowania wszystkie produkty, które chcemy kupić. 

 

Najpierw musimy stworzyć przy każdym produkcie opcję dodaj do koszyka, potem zarezerwować odpowiednie miejsce w bazie danych na nasz koszyk, następnie spróbować jakoś wyświetlić  zawartość koszyka w oddzielnej podstronie. Aby wykonać powyższe operacje, wykorzystamy znany Tobie pewnie formularz, a więc do dzieła!!!

Najpierw zaktualizujemy klasę Produkt o dodatkowy parametr liczba sztuk w koszyku - np. dodane

dodane = models.IntegerField(default=0)

Ta linijka dodaje nam nowy atrybut typu Integer (liczby całkowite, mogą być ujemne, ale na razie się tym nie przejmujmy) i ustawia go domyślnie na zero, żeby na starcie koszyk był pusty. Proste prawda ;D

kurs-django-robot-4-im1.png

Aby zaakceptować zmiany w pliku models.py, klepiemy standardowe dwa kody w konsoli, pamiętając o tym, że serwer jest wyłączony, ale aktywne jest środowisko wirtualne (nazwa w konsoli jest w nawiasach).

python manage.py makemigrations python manage.py migrate

Włączamy serwer jako admin i widzimy dodatkowe okienko Dodane dla każdego obiektu klasy Produkt, ustawione domyślnie na zero.

kurs-django-robot-4-im2.png

Teraz dodamy okienko do wpisania ilości produktów i przycisk dodaj do koszyka w interfejsie naszej aplikacji.

Najpierw zaimplementujemy (ciekawe słowo zamiast napiszemy kod xP) formularz, aby to zrobić, potrzebujemy utworzyć nowy plik forms.py w naszym folderze Sklep (w folderze z plikiem models.py)

kurs-django-robot-4-im3.png

Teraz zdefiniujmy nasz formularz, korzystając z modelu Produkt i chcemy mieć możliwość wpisania ilości sztuk dodanych do koszyka, zmieniając atrybut dodane.
Model to klasa, do której ma się odwołać formularz, czyli w naszym przypadku Produkt,
a w fields i labels informujemy Django o atrybucie, w naszym przypadku dodane.

kurs-django-robot-4-im4.png
from django import forms from .models import Produkt class KoszykForm(forms.ModelForm): class Meta: model = Produkt fields = ['dodane'] labels = {'dodane':''}

Potem wprowadzamy nowy adres URL, pod którym wykona się nasz kod z formularzem. Chcemy zdobyć informację o konkretnym produkcie i jego ilości w koszyku, więc informujemy Django, że adres URL zapyta też o numer ID produktu.

path('dodajkoszyk/<id>', dodajkoszyk, name='dodajkoszyk'),
kurs-django-robot-4-im5.png

Teraz piszemy naszą funkcję w pliku views.py, na początku pliku dopisujemy 

from .forms import KoszykForm

Żeby plik views.py miał źródło danych o formularzu, który zdefiniowaliśmy wcześniej.

kurs-django-robot-4-im6.png

Piszemy funkcję  dodajkoszyk.

Pobieramy obiekt z danym id (podany w adresie URL), przypisujemy go w formularzu tak, żeby wyświetlał domyślnie wartość zero dla pustego pola oraz zostawił wpisaną wartość po wysłaniu formularza (gdy zapytanie jest POST) i jeśli zostały wypełnione wszystkie okienka formularza, jest walidacyjny (poprawny), zapisał formularz. Potem Django ma zapakować dane i wyświetlić nam stronę produkt.html.

def dodajkoszyk(request,id): produkt = Produkt.objects.get(pk=id) p_id = id if request.method != 'POST': form = KoszykForm(instance=produkt) else: form = KoszykForm(instance=produkt, data=request.POST) if form.is_valid(): form.save() dane = {'produkt': produkt,'p_id':p_id, 'form':form} return render(request, 'Sklep/produkt.html', dane)

 

kurs-django-robot-4-im7.png

Aktualizujemy plik produkt.html o formularz, uwzględniamy, że adres ma się odwołać do konkretnego produktu (obiektu klasy Produkt), Django, wie, że produkt.id to numer id produktu, no właśnie wie?

<form action="{% url 'dodajkoszyk' produkt.id %}" method='post'> {% csrf_token %} {{ form }} <button name="submit">dodaj do koszyka</button> </form>

 

kurs-django-robot-4-im8.png

Jako że chcemy, aby formularz był widoczny z poziomu danego produktu, musimy zdefiniować formularz w funkcji produkt w pliku views.py o dodatkowe linie

form = KoszykForm()

i uwzględnić to przy wysyłaniu danych

dane = {'produkt':produkt,'p_id':p_id,'form':form}

 

kurs-django-robot-4-im9.png

Już mamy poprawnie działającą funkcję dodajkoszyk, która daje nam informację o chęci zakupu danej ilości produktów i przechowuje ją w bazie danych. Żeby ją aktywować, musimy kliknąć w dany produkt, czyli aktywować funkcję produkt z konkretnym id, w ten sposób w otrzymanej odpowiedzi od Django, będzie tam czekał również dodany formularz, który wykorzystuje ten sam numer id produktu.

kurs-django-robot-4-im10.png

Po kliknięciu przycisku dodaj do koszyka (aktywujemy funkcję dodajkoszyk), zmieni nam się wartość dodane w bazie danych z 0 na 5

kurs-django-robot-4-im11.png

Teraz zabierzmy się za wyświetlenie zawartości koszyka na oddzielnej stronie.

Stwórzmy podstronę koszyk.html, która wyświetli napis “Koszyk jest pusty jak słoik po ogórkach” i sprawmy, żeby była dostosowana do obecnej struktury, czyli żeby wyświetlała się jako 3 nagłówek obok Strona główna oraz Pokaż mi swoje towary.

Aktualizujemy plik szablon.html o nowy odnośnik, pod którym chowa się adres URL /koszyk

<a href="/koszyk">Koszyk</a>
kurs-django-robot-4-im12.png

następnie plik urls.py

path('koszyk', koszyk, name='koszyk'),
kurs-django-robot-4/im13.png

W pliku views.py dodajemy póki co funkcję koszyk, która wyświetli tylko plik koszyk.html.

def koszyk(request): return render(request, 'Sklep/koszyk.html')
kurs-django-robot-4-im14.png

i dodajmy plik koszyk.html 

{% extends 'Sklep/szablon.html' %} {% block wszystko %}

Twój koszyk jest pusty jak słoik po ogórkach

{% endblock wszystko %}
kurs-django-robot-4-im15.png
kurs-django-robot-4-im16.png

Teraz przejdźmy do wyświetlenia naszej listy zakupów i całkowitej kwoty do zapłaty.

Plik views.py modyfikujemy w ukazany sposób. 

def koszyk(request): produkty_koszyk = Produkt.objects.exclude(dodane="0") cena = 0 for produkt in produkty_koszyk: cena = cena + float(produkt.cena) * int(produkt.dodane) dane = {'produkty_koszyk': produkty_koszyk, 'cena': cena} return render(request, 'Sklep/koszyk.html', dane)

 

kurs-django-robot-4-im17.png

W funkcji koszyk chcemy, żeby pobrane zostały wszystkie produkty z wyjątkiem tych, gdzie wartość atrybutu dodane jest równa 0, zapisane pod zmienną produkty_koszyk. (Wszystkie produkty, które dodaliśmy do koszyka, przesyłając ich konkretną liczbę sztuk)

Zsumujmy też całą kwotę przez dodanie do ceny startowej 0, kwotę równą ilości dodanych produktów (int - wartości całkowite, integer) razy cenę jednostkową (float - wartości z ułamkiem) i nadpiszmy ją pod zmienną cena (Python automatycznie  w tym przypadku wybierze dla niej typ float). W utworzonej pętli for dla każdego zamówionego produktu sumowana jest kwota za wszystkie zamówione sztuki i dodawana do ceny końcowej.

Natomiast w pliku koszyk.html po prostu to wyświetlamy.

{% extends 'Sklep/szablon.html' %} {% block wszystko %}

Twój koszyk:

{% if produkty_koszyk %} {% for produkt in produkty_koszyk %}

nazwa: {{produkt.nazwa}}, ilość zakupionych sztuk: {{produkt.dodane}}

{% endfor %} {% else %}

Twój koszyk jest pusty jak słoik po ogórkach

{% endif %}

Całkowita kwota do zapłaty: {{cena}} Złotych

{% endblock wszystko %}

 

kurs-django-robot-4-im18.png

Kod sprawdza, czy lista istnieje, czy istnieje jakiś produkt, który ma atrybut dodane inną niż zero. Konkretnie, czy przekazana zmienna produkty_koszyk coś zawiera. Jeśli tak, dla każdego elementu z listy (produktu) wyświetli jego nazwę (produkt.nazwa) oraz ilość zamówionych sztuk (produkt.dodane). Natomiast jeśli zmienna produkty_koszyk jest pusta (nic nie zostało dodane do koszyka), wyświetli napis. Prócz tego wyświetli również całkowitą kwotę do zapłaty za wszystkie produkty w koszyku (obliczoną i przesłaną zmienną cena), jeśli ich nie ma, wyświetli zero.

kurs-django-robot-4-im19.png

PS: poprawiliśmy dużą literę w nagłówku dla Koszyk w pliku szablon.html oraz literówkę dla Przekaźnika 4 kanałowego xP w bazie danych.

 

Podsumowując, udało się wprowadzić nową funkcjonalność “koszyka zakupów”, bez zaburzania struktury już napisanej aplikacji. Mało tego, możemy w łatwy sposób dodać nowe produkty w bazie danych, które będą zachowywały się w dokładnie taki sam sposób co już dodane i automatycznie odziedziczą te same funkcje. W kolejnym rozdziale, spróbujemy zasymulować kupno i wysłanie maila z daną listą oraz zmniejszenie dostępnej ilości o ilość zakupionych sztuk, jak się pewnie domyśliłeś, wprowadzimy nowy atrybut “ilość dostępnych sztuk” dla klasy Produkt.

Category: Kurs Django Podstawa