Как реализовать все методы CRUD в одном представлении на основе классов во фреймворке Django
Всем доброго дня. После бесчисленных попыток решить свою проблему, я решил обратиться сюда за советом. Я пишу небольшое приложение с двумя моделями: Departments и Employees. И я решил переписать все функциональные представления в представления на основе классов. С помощью REST-фреймворка Django мне удалось реализовать следующее решение: Это drf-api-view.py:
from django.core.cache import cache
from rest_framework.generics import ListAPIView, CreateAPIView, RetrieveUpdateDestroyAPIView
from rest_framework.exceptions import ValidationError
from rest_framework.pagination import LimitOffsetPagination
from django_filters.rest_framework import DjangoFilterBackend
from department.models.models import Department, Employee
from department.rest.serializers import DepartmentSerializer, EmployeeSerializer
class DepartmentPagination(LimitOffsetPagination):
default_limit = 10
max_limit = 100
class EmployeePagination(LimitOffsetPagination):
default_limit = 10
max_limit = 100
class DepartmentView(ListAPIView, CreateAPIView, RetrieveUpdateDestroyAPIView):
queryset = Department.objects.all().order_by('title')
serializer_class = DepartmentSerializer
filter_backends = (DjangoFilterBackend,)
pagination_class = DepartmentPagination
lookup_field = 'id'
def list(self, request, *args, **kwargs):
if isinstance(request.resolver_match.kwargs.get('id', None), int):
return super().retrieve(request, *args, **kwargs)
return super().list(request)
def create(self, request, *args, **kwargs):
title = request.data.get('title')
if title is None:
raise ValidationError({'title': 'Must not be empty'})
return super().create(request, *args, **kwargs)
def update(self, request, *args, **kwargs):
response = super().update(request, *args, **kwargs)
if response.status_code == 200:
department = response.data
department_id = department['id']
cache.set(f'department_data_{department_id}', {
'title': department['title'],
'slug': department['slug'],
})
return response
def delete(self, request, *args, **kwargs):
department_id = request.data.get('id')
response = super().delete(request, *args, **kwargs)
if response.status_code == 204:
cache.delete(f'department_data_{department_id}')
return response
Это urlpatterns:
urlpatterns = [
path('get/departments', DepartmentView.as_view()),
path('api/new', DepartmentView().as_view()),
path('api/update', DepartmentView().as_view()),
path('api/<int:id>', DepartmentView.as_view()),
path('api/empl', EmployeeView.as_view()),
path('admin/', admin.site.urls),
]
Возможно, мне следовало использовать ViewSets
, но не в этом дело. Кроме того, это работало.
Но я хотел написать web-сервис и veb-приложение. Дело уперлось в то, что я не смог написать что-то похожее на вышеописанное с помощью Class-Based Views в Django.
Вот мой View:
from django.http import HttpResponseRedirect, HttpResponse, HttpRequest
from django.shortcuts import render, redirect, get_object_or_404
from django.urls import reverse_lazy, reverse
from django.views import View
from django.views.decorators.http import require_http_methods
from django.views.generic import ListView, CreateView, FormView, DetailView, RedirectView, TemplateView
from department.models.models import Department, Employee
from department.forms.forms import DeptForm
from django.views.generic.edit import DeletionMixin, DeleteView
class DepartmentsCustomView(ListView, DetailView, DeleteView, CreateView):
object_list = Department.objects.all().order_by('title')
model = Department
allow_empty = False
form_class = DeptForm
initial = {}
success_url = 'main_page'
object = None
def get(self, request, *args, **kwargs):
context = super().get_context_data(**kwargs)
context['employees'] = Employee.objects.filter(department__id=
request.resolver_match.kwargs.get('pk'))
return render(request, super().get_template_names(), context)
def delete(self, request, *args, **kwargs):
super().delete(request, *args, **kwargs)
return HttpResponseRedirect(reverse('main_page'))
def post(self, request, *args, **kwargs):
if request.method == 'POST':
form = DeptForm(request.POST)
if form.is_valid():
dept = form.save(commit=True)
dept.save()
context = super().get_context_data()
return render(request, 'main_page.html', context)
return render(request, 'add_new_dept.html', {'form': form})
def put(self, request, *args, **kwargs):
self.post(request, *args, **kwargs)
Вот как стали выглядеть urlpatterns:
urlpatterns = [
path('get/departments', DepartmentView.as_view()),
path('api/new', DepartmentView().as_view()),
path('api/update', DepartmentView().as_view()),
path('api/<int:id>', DepartmentView.as_view()),
path('api/empl', EmployeeView.as_view()),
path('admin/', admin.site.urls),
path('', DepartmentsCustomView.as_view(template_name='main_page.html'), name='main_page'),
path('<int:pk>', DepartmentsCustomView.as_view(template_name='department_detail.html'), name='department_detail'),
path('<int:pk>/delete', DepartmentsCustomView.as_view(template_name='dept_deletion.html'), name='dept_deletion'),
path('post', DepartmentsCustomView.as_view(template_name='add_new_dept.html'), name='add_new_dept'),
path('<int:pk>/update', DepartmentsCustomView.as_view(template_name='add_new_dept.html'), name='add_new_dept'),
]
Но когда я пытаюсь удалить отдел, отдел удаляется из базы данных, но я остаюсь на странице 'localhost//25/delete'
Я получаю эту ошибку:
Ошибка значения в /25/delete
Представление department.views.views.DepartmentsCustomView не вернуло объект HttpResponse. Вместо него возвращается None. Когда я пытаюсь добавить новый отдел, он перенаправляет меня на форму, и отдел создается в базе данных, но я остаюсь на странице
'localhost/post'
. То есть я не перенаправляюсь наsuccses_url
, а DepartmentsCustomView работает отдельными частями, и то не полностью. Возможно потому, что я переписал методget
и определилtemplate_name
вurlpatterns
. Возможно, это можно исправить с помощьюMixin
, но я не знаю как. Я прочитал много информации,django.views.generic
исходный код, вопросы на stackoverflow, включая этот вопрос Django - Calling one class method from another in Class Based View. Я перепробовал все свои идеи и буду благодарен за любую подсказку, которая поможет мне закончить начатое. Спасибо, что дочитали до конца.