Представления
Представления - основная логика нашего сайта. Перейдём в файл views.py
в нашем приложении и напишем несколько
необходимых для нас функций.
from django.contrib import messages
from django.contrib.auth import login
from django.shortcuts import render, redirect
from .forms import RegistrationForm
def register_request(request):
if request.method == "POST":
form = RegistrationForm(request.POST)
if form.is_valid():
user = form.save()
login(request, user)
messages.success(request, "Вы успешно зарегистрировались!")
return redirect("view_flights")
messages.error(request, "Регистрация не удалась. Проверьте введённые данные.")
else:
form = RegistrationForm()
return render(request=request, template_name="flights/register.html", context={"register_form": form})
Если пользователь отправил GET-запрос, ему нужно вывести форму регистрации. Для этого создадим объект формы
и вызовем функцию render
, которая отправит этот объект в наш шаблон register.html
, отрендерит его
и вернёт пользователю.
Если пользователь отправил POST-запрос, значит он уже заполнил форму и нажал на submit кнопку.
В таком случае нам нужно провалидировать введённые им данные. Для этого создадим объект формы регистрации с этими данными
(получим их из request.POST
) и вызовем метод is_valid()
.
Если метод вернул True
, значит все валидации прошли успешно. В таком случае создаём новый объект пользователя,
авторизуем его с помощью функции login()
, отправим ему сообщение об успехе и переведём на страницу просмотра рейсов
с помощью функции redirect
.
Если метод вернул False
, значит данные в форме заполнены некорректно. Поэтому мы отправим пользователю соответствующее
сообщение и вернём форму с уже введёнными данными так же с помощью функции render
.
from django.contrib import messages
from django.contrib.auth import login, authenticate
from django.contrib.auth.forms import AuthenticationForm
from django.shortcuts import render, redirect
def login_request(request):
if request.method == "POST":
form = AuthenticationForm(request, data=request.POST)
if form.is_valid():
username = form.cleaned_data.get("username")
password = form.cleaned_data.get("password")
user = authenticate(username=username, password=password)
if user:
login(request, user)
messages.info(request, f"Вы вошли как {user.last_name} {user.first_name}.")
return redirect("view_flights")
else:
messages.error(request, "Неверный логин или пароль.")
else:
messages.error(request, "Неверный логин или пароль.")
form = AuthenticationForm()
return render(request=request, template_name="flights/login.html", context={"login_form": form})
Для входа нам достаточно встроенной формы авторизации AuthenticationForm
, воспользуемся ей.
Если пользователь отправил GET-запрос, вернём ему эту форму через шаблон login.html
.
Если же пользователь отправил POST-запрос, так же проверим валидации формы, получим из неё логин и пароль
и проверим их корректность с помощью функции authenticate
. Если проверка успешна, авторизуем пользователя
с помощью функции login
, отправим сообщение об успехе и переведём на страницу просмотра рейсов.
Если же форма не прошла валидацию или введённые данные не прошли проверку, выведем сообщение с ошибкой и вернём заполненную форму обратно.
from django.contrib import messages
from django.contrib.auth import logout
from django.shortcuts import redirect
def logout_request(request):
logout(request)
messages.info(request, "Вы успешно вышли.")
return redirect("login")
Самое базовое представление. Вызываем функцию logout
, отправляем сообщение об успешном выходе и переводим
на страницу входа.
from django.contrib.auth.decorators import login_required
from django.shortcuts import render
from .models import Flight
@login_required
def view_flights(request):
flights = Flight.objects.exclude(bookings__user=request.user).filter(date__gt=timezone.now()).order_by("date")
return render(request, "flights/flights_list.html", {"flights": flights})
С помощью декоратора @login_required
обеспечиваем доступ к этому представлению только для авторизованных
пользователей.
С помощью ORM обращаемся к модели Flight
и получаем список рейсов, исключая из него с помощью метода excluded
те рейсы, на которые у пользователя уже есть бронь, фильтруя с помощью метода filter
только те рейсы, время отправления
которых позже текущего времени, и сортируя их с помощью метода order_by
по времени отправления.
Отправляем этот список в функцию render
вместе с шаблоном flights_list.html
и отправляем пользователю.
from django.contrib.auth.decorators import login_required
from django.shortcuts import render
from django.utils import timezone
from .models import Booking
@login_required
def view_bookings(request, tab):
if tab == "upcoming":
bookings = Booking.objects.filter(user=request.user, flight__date__gte=timezone.now())
else:
bookings = Booking.objects.filter(user=request.user, flight__date__lt=timezone.now())
return render(request, "flights/my_flights.html", {"bookings": bookings, "active_tab": tab})
Это представление так же защищаем от неавторизованных пользователей с помощью декоратора @login_required
.
Для просмотра броней хочется сделать, чтобы была возможность просматривать предстоящие и уже завершённые рейсы.
Для этого будем передавать в маршруте название активной вкладки, которое наше представление получит в виде арумента
tab
.
Если tab == "upcoming"
, то есть просматриваются предстоящие рейсы, с помощью ORM и фильтров будем получать
только те брони, которые, в первую очередь, связаны с нашим пользователем и время рейса которых позже текущего.
В ином случае получаем брони, связанные с нашим пользователем, время рейса которых раньше текущего.
В шаблон my_flights.html
отправляем активную вкладку и полученные брони, рендерим и отправляем пользователю.
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect
from .models import Flight, Booking
@login_required
def book_flight(request, flight_id):
flight = Flight.objects.get(id=flight_id)
Booking.objects.create(user=request.user, flight=flight)
messages.success(request, "Рейс успешно забронирован!")
return redirect("view_flights")
Это представление так же защищаем от неавторизованных пользователей с помощью декоратора @login_required
.
Также это представление должно получить id рейса из маршрута пользователя. С помощью ORM получаем объект выбранного рейса и создаём новую запись в таблице броней, привязав к ней пользователя, отправившего запрос и и полученный рейс.
Отправляем сообщение об успехе и переводим на страницу просмотра рейсов.
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect
from .models import Booking
@login_required
def delete_booking(request, booking_id):
booking = Booking.objects.get(id=booking_id, user=request.user)
booking.delete()
messages.success(request, "Бронь успешно отменена!")
return redirect("view_bookings", "upcoming")
Представление должно получить id брони, которую планируется удалить, поэтому укажем это в аргументах функции.
С помощью ORM получим объект этой брони (в случае если она привязана к этому пользователю) и с помощью метода
delete
удалим её.
Затем вернём сообщение об успехе и переведём на вкладку предстоящих рейсов страницы просмотра броней (кнопка для удаления броней будет только на странице предстоящих рейсов, поэтому переводим именно туда).
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.shortcuts import render, redirect
from .forms import FeedbackForm
from .models import Flight
@login_required
def give_feedback(request, flight_id):
if request.method == "POST":
form = FeedbackForm(request.POST)
if form.is_valid():
feedback = form.save(commit=False)
feedback.user = request.user
feedback.flight = Flight.objects.get(id=flight_id)
feedback.save()
messages.success(request, "Ваш отзыв успешно отправлен!")
return redirect("view_bookings", "past")
else:
form = FeedbackForm()
return render(request, "flights/feedback.html", {"form": form})
В этом представлении используем написанную нами форму FeedbackForm
. Также нам необходим получать id рейса, для которого
пишется отзыв, поэтому напишем его в аргументы функции.
Если пользователь отправил GET-запрос, вернём его отрендеренный шаблон feedback.html
с пустой формой.
Если пользователь отправил POST-запрос, провалидируем введённые им данные и в случае успеха создадим объект на основе полученных данных, привяжем к нему пользователя и рейс и сохраним в БД. Отправим сообщение об успехе и переведём на вкладку прошедших рейсов страницы просмотра броней (кнопка для отзывов будет только на странице прошедших рейсов, поэтому переводим именно туда).
from django.contrib.auth.decorators import login_required
from django.shortcuts import render, get_object_or_404
from .models import Flight
@login_required
def flight_details(request, flight_id):
flight = get_object_or_404(Flight, pk=flight_id)
return render(request, "flights/flight_details.html", {"flight": flight})
Представление получает id рейса и пытается его найти. Если такого рейса не существует, отправляет ошибку 404, в ином
случае отправляем объекта рейса в шаблон flight_details.html
, рендерит и отправляет пользователю.