Django #4

Możesz sprawdzić działanie aplikacji tworząc darmowe konto tutaj.
Kod źródłowy można obrać z Githuba tutaj.

W tym wpisie przedstawię widoki odpowiedzialne za zarządzanie autami i naprawami.

▣ Zacznę od głównego widoku prezentującego auta wpisane przez użytkownika. Maksymalna liczba wpisów na stronie to 10 aut. Po kliknięciu na poszczególne auto wyświetlane są naprawy danego auta. Zarówno wpisy aut jak i napraw są posortowane według daty tzn. najnowsze wpisy są wyświetlane jako pierwsze.

Klasa widoku wyświetlająca auta dziedziczy po klasie ListView oraz po klasie LoginRequiredMixin (aby dostęp był możliwy tylko dla zalogowanych użytkowników).

Na początku definiuję wszystkie atrybuty klasy tzn. używany model – Car, używany szablon – cars.html, nazwa obiektu, pod którą są dostępne dane w kontekście – context_object_name – ‘cars’, a także liczba wpisów na stronie – 10 pojazdów.

W tej klasie przesłaniam dwie metody – get_queryset() odpowiedzialną za filtrowanie danych oraz get_context_data(), w której uzupełniam dane kontekstu o dane z pola wyszukiwania.

Kod klasy CarListView() wygląda następująco:

class CarsListView(LoginRequiredMixin, ListView):
    model = Car
    template_name = 'cars/cars.html'
    context_object_name = 'cars'
    paginate_by = 10

    def get_queryset(self):
        if self.request.GET.get('q'):
            q = self.request.GET.get('q')
            make_results = self.model.objects.filter(
                user=self.request.user, make=q).order_by('-pk')
            model_results = self.model.objects.filter(
                user=self.request.user, model=q).order_by('-pk')
            if make_results.exists():
                return make_results
            elif model_results.exists():
                return model_results
            else:
                return self.model.objects.none()
        return self.model.objects.filter(user=self.request.user).order_by('-pk')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['q'] = self.request.GET.get('q', '')
        return context

Metoda get_queryset() wyświetla wszystkie pojazdy danego użytkownika. Ostatnio dodane auto jest widoczne jako pierwsze (sortowanie ‘-pk’). Jeśli w polu wyszukiwania została wpisana marka lub model pojazdu/pojazdów to zostaną wyświetlone tylko te pojazdy.

Metoda get_context_data() dodaje wpis z pola wyszukiwania do kontekstu, dzięki czemu poprawnie wyświetlane są dane o naprawach aut przy podziale aut na poszczególne strony.

▣ Dodawanie pojazdu odbywa się po wciśnięciu przycisku Add Car w menu aplikacji. Widok, który obsługuje dodawanie auta to klasa AddCarView(), a szablon, który wyświetla formularz dodawania auta to car_form.html (ten sam szablon obsługuje również aktualizację danych opisujących dane auto) .

Klasa AddCarView() dziedziczy funkcjonalność po klasie CreateView() oraz LoginRequiredMixin (tylko zalogowani użytkownicy mogą utworzyć nowy pojazd).

Definiuję następujące atrybuty klasy widoku: model, który używa klasa – Car, fields – pola formularza, które mają być widoczne, oraz success_url – adres url, który zostanie załadowany po pomyślnym wypełnieniu formularza.

Przesłaniam metodę form_valid(), która dodaje użytkownika, który utworzył nowe auto (model Car wymaga zdefiniowania atrybutu user).

Kod klasy AddCarView() wygląda następująco:

class AddCarView(LoginRequiredMixin, CreateView):
    model = Car
    fields = ['make', 'model', 'vrn', 'year']
    success_url = '/'

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

▣ Usuwanie auta jest realizowane za pomocą klasy widoku DeleteCarView(), a szablon, który wyświetla monit czy kasować auto to plik car_confirm_delete.html (wyświetla przycisk Delete, który kasuje auto i przycisk Cancel, który wraca do poprzedniej strony).

Klasa DeleteCarView() dziedziczy funkcjonalność po klasie DeleteView, LoginRequiredMixin (tylko zalogowany użytkownik może skasować auto) oraz UserPassesTestMixin(użytkownik może usunąć tylko auto utworzone przez siebie).

Definiuję argumenty model – używany model Car oraz success_url – adres, pod który będzie załadowany po pomyślnym usunięciu auta – w tym przypadku widok prezentujący wszystkie auta użytkownika.

Tworzę metodę test_func(), która sprawdza, czy użytkownik, który chce usunąć auto jest osobą, która utworzyła dane auto (użytkownik może usunąć tylko utworzone przez siebie auta).

Przesłaniam metodę delete(), która dodatkowo wyświetla wiadomość o skasowaniu auta.

Kod klasy DeleteCarView() wygląda następująco:

class DeleteCarView(LoginRequiredMixin, UserPassesTestMixin, DeleteView):
    model = Car
    success_url = '/'

    def test_func(self):
        if self.get_object().user == self.request.user:
            return True
        return False

    def delete(self, request, *args, **kwargs):
        success_message = f'Car {self.get_object()} has been deleted'
        messages.success(self.request, success_message)
        return super().delete(request, *args, **kwargs)

▣ Uaktualnienie danych opisujących konkretne auto odbywa się za pomocą klasy UpdateCarView(), natomiast szablon wyświetlający formularz do zmiany tych danych to car_form.html.

Klasa UpdateCarView() dziedziczy funkcjonalność po klasie UpdateView, jak również po klasach LoginRequiredMixin (uaktualnienie danych może dokonać tylko zalogowany użytkownik) oraz UserPassesTestMixin (wywoływana jest funkcja sprawdzająca, czy użytkownik, który chce dokonać modyfikacji jest tym, który utworzył dane auto).

Definiuję atrybuty klasy: model – określa model, który jest wykorzystywany do zmiany danych – w tym przypadku model Car. Atrybut fields – określający jakie pola formularza mają być dostępne. Atrybut success_message definiujący łańcuch tekstowy do wyświetlenia jako komunikat o uaktualnieniu danych auta.

Definiuję dwie metody: test_func() oraz get_success_url().

Metoda test_func() sprawdza, czy użytkownik, który chce dokonać modyfikacji danych auta jest tym, który utworzył dane auto.

Metoda get_success_url() przesłania metodę dokonującą modyfikacji danych auta i dodatkowo wyświetla komunikat o zmianie danych i wraca na stronę określoną nazwą: car_detail – wyświetlającą naprawy dla danego auta. Jako dodatkowe parametry przesyłane są za pomocą metody GET: row, p oraz q określające odpowiednio wiersz, stronę oraz łańcuch tekstowy z pola wyszukiwania.

Kod klasy UpdateCarView():

class UpdateCarView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
    model = Car
    fields = ['make', 'model', 'vrn', 'year']
    success_message = 'Car info has been updated'

    def get_success_url(self, **kwargs):
        row = self.request.GET.get('row')
        p = self.request.GET.get('p')
        q = self.request.GET.get('q')
        options = '?p=' + p + '&row=' + row
        options += '&q=' + q
        messages.success(self.request, self.success_message)
        return reverse_lazy('car_detail') + options

    def test_func(self):
        if self.get_object().user == self.request.user:
            return True
        return False

▣ Dodanie notatki o naprawie jest definiowane w klasie AddRepairView() widoku, a formularz jest zdefiniowany w szablonie repair_form.html.

W klasie tej występują następujące argumenty: model – określający wykorzystywany model – w tym przypadku Repair. Następny argument: fields określa jakie są wyświetlane pola formularza. Ostatni argument to łańcuch success_message wyświetlany po pomyślnym dodaniu notatki o naprawie.

Metody obecne w klasie AddRepairView() to: get_context_data(), form_valid() oraz get_success_url().

Metoda get_context_data() dodaje obiekt Car do kontekstu, dzięki czemu jest on widoczny w szablonie.

Metoda form_valid() wykorzystuje dane z formularza do utworzenia nowej instancji modelu. Do poprawnego utworzenia instancji klasy Repair jest konieczne podanie klucza obcego – obiektu Car określającego pojazd, którego dotyczy dana notatka o naprawie.

Metoda get_success_url() określa adres strony, która ma być wyświetlona po pomyślnym dodaniu nowej notatki. W tym przypadku wyświetlona zostanie strona o nazwie car_detail zdefiniowana w cars/urls.py.

class AddRepairView(LoginRequiredMixin, CreateView):
    model = Repair
    fields = ['date', 'description']
    success_message = 'New repair has been added'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['car'] = Car.objects.get(id=self.kwargs['pk'])
        return context

    def form_valid(self, form, **kwargs):
        form.instance.car = Car.objects.get(id=self.kwargs['pk'])
        return super().form_valid(form)

    def get_success_url(self, **kwargs):
        row = self.request.GET.get('row')
        p = self.request.GET.get('p')
        q = self.request.GET.get('q')
        options = '?p=' + p + '&row=' + row
        options += '&q=' + q
        return reverse_lazy('car_detail') + options

— c.d.n —

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *