CustomFormView
The CustomFormView provides a custom form attached to an existing model object. Use it when you need a form that operates on an object but does not follow the standard create/update/delete pattern — for example, a contact form, an approval action, or a send-message action.
View Classes
| Class | Description |
|---|---|
CustomFormView |
Object-based custom form view (no permission check) |
CustomFormViewPermissionRequired |
Object-based custom form view with view permission required |
CustomFormNoObjectView |
Non-object-based custom form view (no permission check) |
CustomFormNoObjectViewPermissionRequired |
Non-object-based custom form view with view permission required |
CustomFormView inherits from CrudViewProcessFormMixin, CrudView, FormMixin, and Django's DetailView — it loads a model object from the URL just like a detail view, and renders a form alongside it.
CustomFormNoObjectView is the same but does not load a model object. Use it for forms that are not tied to a specific instance.
Basic Usage
Define a form, then a view with cv_key and cv_path set:
from django.forms.fields import CharField
from django.utils.translation import gettext as _
from crud_views.lib.crispy import Column12, CrispyModelForm, CrispyModelViewMixin
from crud_views.lib.views import MessageMixin
from crud_views.lib.views.form import CustomFormViewPermissionRequired
from crud_views.lib.viewset import ViewSet
from .models import Author
cv_author = ViewSet(model=Author, name="author")
class AuthorContactForm(CrispyModelForm):
submit_label = _("Send")
subject = CharField(label="Subject", required=True)
body = CharField(label="Body", required=True)
class Meta:
model = Author
fields = ["subject", "body"]
def get_layout_fields(self):
return Column12("subject"), Column12("body")
class AuthorContactView(MessageMixin, CrispyModelViewMixin, CustomFormViewPermissionRequired):
cv_key = "contact"
cv_path = "contact"
cv_icon_action = "fa-solid fa-envelope"
cv_viewset = cv_author
form_class = AuthorContactForm
cv_message_template_code = "Successfully contacted author »{object}«"
cv_context_actions = ["parent", "detail", "update", "delete", "contact"]
cv_header_template_code = _("Contact Author")
cv_paragraph_template_code = _("Send a message to the Author")
def cv_form_valid(self, context):
form = context["form"]
# process form.cleaned_data here, e.g. send an email
pass
The view is auto-registered with cv_author via cv_key and cv_path, so its URL is included automatically in cv_author.urlpatterns.
Configuration
| Attribute | Type | Default | Description |
|---|---|---|---|
cv_key |
str |
— | Required. Unique key within the ViewSet (e.g. "contact") |
cv_path |
str |
— | Required. URL path segment (e.g. "contact") |
cv_viewset |
ViewSet |
— | The ViewSet this view belongs to |
form_class |
Form |
— | The form class to render |
cv_success_key |
str |
"list" |
ViewSet key to redirect to after a valid form submission |
cv_context_actions |
list[str] |
from settings | Actions shown in the header area |
cv_header_template_code |
str |
— | Translatable header text |
cv_paragraph_template_code |
str |
— | Translatable paragraph text below the header |
Form Processing Hooks
Override cv_form_valid to handle the submitted form data:
| Hook | Description |
|---|---|
cv_form_valid(context) |
Called when the form is valid — implement your action here |
cv_form_valid_hook(context) |
Called after cv_form_valid (used by MessageMixin) |
The context dict contains at least "form" (the bound, validated form) and "object" (the loaded model instance, for object-based views).
After cv_form_valid_hook, the view redirects to cv_success_key (default: "list").
Adding a Success Message
Combine with MessageMixin to display a flash message after a successful submission:
class AuthorContactView(MessageMixin, CrispyModelViewMixin, CustomFormViewPermissionRequired):
...
cv_message_template_code = "Successfully contacted author »{object}«"
Non-Object View
Use CustomFormNoObjectView when the form is not tied to a specific model instance:
from crud_views.lib.views.form import CustomFormNoObjectViewPermissionRequired
class SiteFeedbackView(CrispyModelViewMixin, CustomFormNoObjectViewPermissionRequired):
cv_key = "feedback"
cv_path = "feedback"
cv_viewset = cv_site
form_class = FeedbackForm
def cv_form_valid(self, context):
# process feedback
pass
CrispyModelViewMixin
CrispyModelViewMixin (alias of CrispyViewMixin) enables crispy-forms support for the view's form. When added to a view, it passes the current view instance (cv_view) as an extra argument when constructing the form. This allows the form to generate context-aware submit and cancel buttons.
Add it to any view that uses a CrispyModelForm or CrispyForm:
class AuthorContactView(CrispyModelViewMixin, CustomFormViewPermissionRequired):
form_class = AuthorContactForm # must extend CrispyModelForm or CrispyForm
...
See CreateView for details on defining CrispyModelForm forms.