Django:重写视图类方法的最佳实践是什么?
form_valid (and Other CBV Methods) in Django Great question! Rewriting methods like form_valid in Django class-based views (CBVs) is super common, but following a few best practices will keep your code clean, maintainable, and aligned with Django's design principles. Let's break this down using your example.
First: Fix Redundant Database Operations in Your Code
Looking at your current form_valid implementation:
def form_valid(self, form): self.object = form.save(commit=False) self.object.creator = self.request.user self.object.save() return super().form_valid(form)
The issue here is that super().form_valid(form) will call form.save() again (since that's how CreateView's default form_valid works). That means you're saving the same object twice to the database—unnecessary overhead.
Here's the quick fix: Either skip the super() call and return a redirect directly, or adjust how you handle the save to leverage the parent class logic without duplication:
Option 1: Handle Redirect Yourself
def form_valid(self, form): self.object = form.save(commit=False) self.object.creator = self.request.user self.object.save() # Use Django's built-in get_success_url() for flexibility return redirect(self.get_success_url())
Option 2: Let Parent Class Handle the Final Save
If you prefer to keep using the parent class's logic (e.g., if you're relying on other mixins), you can modify the form instance before letting the parent save it:
def form_valid(self, form): # Modify the form's instance directly before saving form.instance.creator = self.request.user # Now let the parent class handle saving and redirecting return super().form_valid(form)
This way, you avoid calling save() twice—cleaner and more efficient.
General Best Practices for Overriding CBV Methods
Reuse Logic with Mixins
If you find yourself repeating the sameform_validlogic (like setting a creator) across multiple views, extract it into a mixin. This keeps your code DRY (Don't Repeat Yourself) and makes updates easier:class SetCreatorMixin: def form_valid(self, form): form.instance.creator = self.request.user return super().form_valid(form) # Now use it in your view class AuthorCreate(SetCreatorMixin, CreateView): model = Author form_class = AuthorForm template_name = 'app/create_author.html'Mixins are Django's way of reusing view logic—just make sure to place them before the base view in the inheritance order.
Keep View Logic Focused
If yourform_validis getting too complex (e.g., handling multiple object saves, sending emails), consider moving some logic to the form class or a separate service layer. Views should primarily handle request/response flow, not business logic. For example, you could add asave_with_creatormethod to yourAuthorForm:class AuthorForm(forms.ModelForm): class Meta: model = Author fields = ['name', 'bio'] def save_with_creator(self, creator): instance = self.save(commit=False) instance.creator = creator instance.save() return instanceThen in your view:
def form_valid(self, form): self.object = form.save_with_creator(self.request.user) return redirect(self.get_success_url())Always Leverage Django's Built-in Methods
Use methods likeget_success_url()instead of hardcoding URLs. If you set asuccess_urlattribute on your view, or if your model has aget_absolute_url()method,get_success_url()will handle it automatically—no need to rewrite redirect logic.Test Your Overrides
It's easy to introduce bugs when overriding methods. Write tests to verify:- The object is saved correctly with the expected fields (like
creatorset to the current user) - The view redirects to the correct URL on success
- Any edge cases (e.g., anonymous users, invalid forms) are handled properly
- The object is saved correctly with the expected fields (like
Avoid Overcomplicating
Don't override a method just to tweak a small detail if there's a simpler way. For example, if you only need to set a field based on the request, using a mixin or modifying the form instance (like we did earlier) is better than rewriting the entireform_validflow.
内容的提问来源于stack exchange,提问作者Aliquis

