Возможно ли преобразовать эти FBV, которые возвращают HttpResponse(), в CBV? (Django)
В настоящее время у меня есть следующие представления на основе функций, их цель - предпринять определенное действие, основанное на том, что выбрал пользователь:
@login_required()
@csrf_exempt
def remove_member(request, pk, project_id):
if request.method == 'POST':
user = get_object_or_404(User, id=pk)
project = get_object_or_404(Project, id=project_id)
project.members.remove(user)
html = '<div class="alert alert-success" role="alert" id="message-response">' \
'Update successful! ' + user.first_name + ' is no longer part of your team. </div>'
return HttpResponse(html)
@login_required()
@csrf_exempt
def demote_admin(request, pk, project_id):
if request.method == 'POST':
user = get_object_or_404(User, id=pk)
project = get_object_or_404(Project, id=project_id)
project.admin.remove(user)
html = '<div class="alert alert-success" role="alert" id="message-response">' \
'Update successful! ' + user.first_name + ' is no longer an admin. </div>'
return HttpResponse(html)
Я использую htmx в шаблоне, чтобы заполнить div с возвращенным html.
Существует несколько функций, похожих на приведенные выше примеры. Поэтому я хотел бы преобразовать их в одну CBV, чтобы уменьшить избыточность. Новая CBV также потребует некоторой проверки, чтобы предпринять соответствующее действие. Однако я не уверен, какой класс лучше всего подойдет для этого, и какой метод лучше всего переопределить в этом сценарии.
(admin и members - поля M2M, назначенные модели Project)
Нет причин объединять эти два разных действия в одно представление на основе класса.
Однако вы можете преобразовать их в собственные представления на основе классов и расширить из базового представления на основе классов. Но это только сократит некоторые строки и добавит несколько дополнительных строк.
from django.views.generic.base import View
from django.contrib.auth.mixins import LoginRequiredMixin
@csrf_exempt
class AbstractUserProjectView(LoginRequiredMixin, View):
def post(request, pk, project_id):
user = get_object_or_404(User, id=pk)
project = get_object_or_404(Project, id=project_id)
message = self.perform_action(user, project)
return HttpResponse(
'<div class="alert alert-success" role="alert" id="message-response">' + message + '</div>'
)
@csrf_exempt
class RemoveMemberView(LoginRequiredMixin, View):
def perform_action(user, project):
project.members.remove(user)
return 'Update successful! ' + user.first_name + ' is no longer part of your team.'
@csrf_exempt
class DemoteAdminView(LoginRequiredMixin, View):
def perform_action(user, project):
project.admin.remove(user)
return 'Update successful! ' + user.first_name + ' is no longer an admin.'
Но я бы предложил написать их как их собственные взгляды, например:
from django.views.generic.base import View
from django.contrib.auth.mixins import LoginRequiredMixin
@csrf_exempt
class RemoveMemberView(LoginRequiredMixin, View):
def post(request, pk, project_id):
user = get_object_or_404(User, id=pk)
project = get_object_or_404(Project, id=project_id)
project.members.remove(user)
return HttpResponse(
'<div class="alert alert-success" role="alert" id="message-response">' \
'Update successful! ' + user.first_name + ' is no longer part of your team. </div>'
)
@csrf_exempt
class DemoteAdminView(LoginRequiredMixin, View):
def post(request, pk, project_id):
user = get_object_or_404(User, id=pk)
project = get_object_or_404(Project, id=project_id)
project.admin.remove(user)
return HttpResponse(
'<div class="alert alert-success" role="alert" id="message-response">' \
'Update successful! ' + user.first_name + ' is no longer an admin. </div>'
)
Спасибо за все советы относительно csrf и редиректов. Я придумал следующее решение этих проблем:
Вид:
class TeamUpdateView(ProjectAuthMixin, View):
@staticmethod
def post(request, *args, **kwargs):
member = kwargs['pk']
project = Project.objects.get(slug=kwargs['slug'])
action = kwargs['edit']
if action == 'remove-member':
project.members.remove(member)
messages.success(request, "Successfully removed user.")
elif action == 'remove-admin':
project.admin.remove(member)
messages.success(request, "Successfully removed user from admin group.")
elif action == 'promote-admin':
project.admin.add(member)
messages.success(request, "Successfully promoted user to admin.")
return HttpResponseRedirect(reverse('customerportal:team', args=(project.slug,)))
Шаблон:
<div class="dropdown-menu">
<form action="{% url 'customerportal:team-edit' slug 'remove-member' member.id %}" method="post">
{% csrf_token %}
<button type="submit" value="Submit" class="btn btn-block btn-primary">Remove Member</button>
</form>
</div>
Вы могли бы еще немного улучшить свое решение и добиться безопасного отображения имени пользователя в сообщении.
from django.shortcuts import get_object_or_404
class TeamUpdateView(ProjectAuthMixin, View):
@staticmethod
def post(request, *args, **kwargs):
# use get_object_or_404() to return a 404 error
# if a non-existing user or project is used
member = get_object_or_404(User, pk=kwargs['pk'])
project = get_object_or_404(Project, slug=kwargs['slug'])
action = kwargs.get('edit')
if action == 'remove-member':
project.members.remove(member)
# as we have the user object, we can add the username to the message
# escaping is done by the template engine
messages.success(request, "Successfully removed '%s'." % member.username)
elif action == 'remove-admin':
project.admin.remove(member)
messages.success(request, "Successfully removed '%s' from admin group." % member.username)
elif action == 'promote-admin':
project.admin.add(member)
messages.success(request, "Successfully promoted '%s' to admin." % member.username)
return HttpResponseRedirect(reverse('customerportal:team', args=(project.slug,)))
Шаблон остается неизменным
<div class="dropdown-menu">
<form action="{% url 'customerportal:team-edit' slug 'remove-member' member.id %}" method="post">
{% csrf_token %}
<button type="submit" value="Submit" class="btn btn-block btn-primary">Remove Member</button>
</form>
</div>