Django: viết view tạo và sửa bản ghi nhanh gấp đôi bằng CreateView và UpdateView trong 5 phút
Khi cần form tạo và sửa một bản ghi, bạn không cần viết lại cặp view GET/POST quen thuộc. Django đã có sẵn hai class view chuyên việc này là CreateView và UpdateView: chỉ cần khai báo model, danh sách field và template, Django lo phần còn lại — render form, validate, lưu và redirect. Hai view này phù hợp nhất khi form của bạn map trực tiếp lên một model qua ModelForm.
Vấn đề
Trong một app blog, view tạo bài viết bằng hàm thường dài khoảng 25 dòng, view sửa gần như giống hệt, chỉ khác dòng lấy object bằng get_object_or_404 và truyền instance=post. Hai view giống nhau tới 80% nhưng vẫn phải viết và bảo trì riêng — càng nhiều model, càng nhiều code lặp.
# views.py — cách viết bằng hàm: dài và lặp lại
from django.shortcuts import get_object_or_404, redirect, render
from .forms import PostForm
from .models import Post
def post_create(request):
if request.method == "POST":
form = PostForm(request.POST)
if form.is_valid():
post = form.save(commit=False)
post.author = request.user
post.save()
return redirect("post-detail", pk=post.pk)
else:
form = PostForm()
return render(request, "blog/post_form.html", {"form": form})
def post_update(request, pk):
post = get_object_or_404(Post, pk=pk)
if request.method == "POST":
form = PostForm(request.POST, instance=post)
if form.is_valid():
form.save()
return redirect("post-detail", pk=post.pk)
else:
form = PostForm(instance=post)
return render(request, "blog/post_form.html", {"form": form})
Giải pháp
Hai class view dưới đây làm đúng những việc trên, mỗi view chỉ còn 4–5 dòng khai báo. CreateView tự tạo ModelForm từ model và fields, render template theo quy ước <app>/<model>_form.html, lưu object khi form hợp lệ rồi redirect về success_url. UpdateView làm tương tự, chỉ khác là nó tự lấy object theo pk trên URL và nạp form với instance sẵn có. Vì success_url được tính lúc import module — khi đó URLconf chưa load xong — phải dùng reverse_lazy() thay vì reverse().
# views.py — cùng tính năng, chỉ còn khai báo
from django.urls import reverse_lazy
from django.views.generic import CreateView, UpdateView
from .models import Post
class PostCreateView(CreateView):
model = Post
fields = ["title", "content", "category"]
template_name = "blog/post_form.html"
success_url = reverse_lazy("post-list")
class PostUpdateView(UpdateView):
model = Post
fields = ["title", "content", "category"]
template_name = "blog/post_form.html"
success_url = reverse_lazy("post-list")
# urls.py
from django.urls import path
from .views import PostCreateView, PostUpdateView
urlpatterns = [
path("posts/new/", PostCreateView.as_view(), name="post-create"),
path("posts/<int:pk>/edit/", PostUpdateView.as_view(), name="post-update"),
]
Hai tình huống hay gặp: cần gán author trước khi lưu — override form_valid() và set form.instance.author, rồi gọi super().form_valid(form). Cần chặn người khác sửa bài không phải của mình — override get_queryset() để UpdateView chỉ tìm trong bài của user đang đăng nhập; bài người khác trả 404 thay vì mở form.
# views.py — phiên bản hoàn thiện: gán author + chặn sửa bài người khác
from django.urls import reverse_lazy
from django.views.generic import CreateView, UpdateView
from .models import Post
class PostCreateView(CreateView):
model = Post
fields = ["title", "content", "category"]
template_name = "blog/post_form.html"
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
def get_success_url(self):
return reverse_lazy("post-detail", kwargs={"pk": self.object.pk})
class PostUpdateView(UpdateView):
model = Post
fields = ["title", "content", "category"]
template_name = "blog/post_form.html"
success_url = reverse_lazy("post-list")
def get_queryset(self):
# Chỉ tìm trong bài của chính mình: bài người khác trả 404
return Post.objects.filter(author=self.request.user)
Câu hỏi thường gặp
CreateView và UpdateView dùng chung một template được không?
Được — cả hai đều render template theo quy ước <app>/<model>_form.html, nên một template post_form.html dùng chung cho cả tạo và sửa. Để phân biệt, kiểm tra form.instance.pk trong template: tạo mới là None, sửa thì có giá trị.
UpdateView có tự chặn người khác sửa bài của mình không?
Không. Mặc định UpdateView lấy object theo pk mà không kiểm tra quyền sở hữu, nên ai đăng nhập cũng sửa được mọi bản ghi. Muốn chặn, override get_queryset() lọc theo request.user như ví dụ trên, hoặc kết hợp LoginRequiredMixin và UserPassesTestMixin.
💬 Bạn đã thử cách này trong dự án của mình chưa? Nếu gặp lỗi hoặc có cách làm gọn hơn, để lại bình luận bên dưới nhé.
Đọc bản đầy đủ bằng tiếng Anh tại đây: https://linhfish.dev/en/2026/11/12/django-write-create-and-edit-views-twice-as-fast-with-createview-and-updateview-in-5-minutes/
All rights reserved