Auth Mixins
Mixin classes add authentication and permission checks to class-based views.
from buraq.views.mixins import LoginRequiredMixin, PermissionRequiredMixin, UserPassesTestMixinLoginRequiredMixin
Section titled “LoginRequiredMixin”Redirect unauthenticated users to the login page.
from buraq.views.mixins import LoginRequiredMixinfrom buraq.views.generic import DetailView
class PostDetailView(LoginRequiredMixin, DetailView): model = Post template_name = "posts/detail.html"By default redirects to /accounts/login/. Override login_url to change:
class PostDetailView(LoginRequiredMixin, DetailView): model = Post login_url = "/auth/signin/"To return a 403 instead of redirecting:
class PostDetailView(LoginRequiredMixin, DetailView): model = Post raise_exception = TruePermissionRequiredMixin
Section titled “PermissionRequiredMixin”Require the user to hold a specific permission.
from buraq.views.mixins import PermissionRequiredMixinfrom buraq.views.generic import UpdateView
class PostEditView(PermissionRequiredMixin, UpdateView): model = Post permission_required = "blog.change_post" success_url = "/posts/"Require multiple permissions — all must be held:
class PostPublishView(PermissionRequiredMixin, UpdateView): model = Post permission_required = ["blog.change_post", "blog.publish_post"]Unauthenticated users are redirected to login_url. Authenticated users without the permission get a 403 (or redirect, depending on raise_exception).
UserPassesTestMixin
Section titled “UserPassesTestMixin”Deny access based on a custom condition.
from buraq.views.mixins import UserPassesTestMixinfrom buraq.views.generic import DetailView
class StaffOnlyView(UserPassesTestMixin, DetailView): model = Post
async def test_func(self, request) -> bool: return request.user.is_staffAccessMixin (base class)
Section titled “AccessMixin (base class)”All auth mixins inherit from AccessMixin. Override handle_no_permission() to customize the denied response:
from starlette.responses import JSONResponsefrom buraq.views.mixins import LoginRequiredMixin
class APILoginRequired(LoginRequiredMixin, View): async def handle_no_permission(self, request): return JSONResponse({"error": "authentication required"}, status_code=401)SuccessMessageMixin
Section titled “SuccessMessageMixin”Display a flash success message after a form is successfully submitted. Mix with any FormView, CreateView, or UpdateView.
from buraq.views.mixins import SuccessMessageMixinfrom buraq.views.generic import CreateView
class CreatePostView(SuccessMessageMixin, CreateView): model = Post fields = ["title", "body"] success_url = "/posts/" success_message = "Post '%(title)s' was created successfully."success_message supports %(field)s placeholders filled from form.cleaned_data.
Override get_success_message() for dynamic messages:
class CreatePostView(SuccessMessageMixin, CreateView): model = Post fields = ["title", "body"] success_url = "/posts/"
def get_success_message(self, cleaned_data: dict) -> str: if cleaned_data.get("is_published"): return f"Post '{cleaned_data['title']}' published!" return f"Post '{cleaned_data['title']}' saved as draft."The message is passed to buraq.contrib.messages.success(request, msg) and displayed via the messages framework (add buraq.contrib.messages.middleware.MessageMiddleware to MIDDLEWARE and render {{ messages }} in your base template).
Mixin order
Section titled “Mixin order”Always put mixin classes before the view class:
# Correctclass MyView(LoginRequiredMixin, PermissionRequiredMixin, DetailView): ...
# Wrong — LoginRequiredMixin won't be calledclass MyView(DetailView, LoginRequiredMixin): ...