Django中UpdateView无法正常更新的问题求助
Django UpdateView提交后触发添加视图逻辑的问题排查
我正在开发一个流媒体平台风格的Django项目用于作品集展示,在影片数据库管理模块(实现影片增删改)中,使用UpdateView更新影片信息时遇到问题:
- 编辑页面能正常访问,表单也正确加载了影片原有信息
- 点击保存后,却触发了添加影片的
ManageFilmsView里的提示:"This film is already in the database" - 目前看起来提交请求后被重定向到了添加视图,试图创建新条目,和UpdateView的预期功能不符
想明确保存按钮的提交逻辑,是否需要重写UpdateView的方法?接下来该做哪些排查?
相关代码
Views代码
class ManageFilmsView(FormView, ListView): model = Film template_name = "manage-films.html" context_object_name = "films" form_class = AddFilmForm success_url = reverse_lazy("manage_films") def get_queryset(self): parameter = self.kwargs.get("letter") if self.kwargs.get("letter") else "a" return Film.objects.filter(title__startswith=parameter) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) letters = list(string.ascii_uppercase) context["letters"] = letters context["selected_letter"] = ( self.kwargs.get("letter") if self.kwargs.get("letter") else "a" ) return context def form_valid(self, form): search_title = form.cleaned_data["title"].replace(" ", "+") search_year = form.cleaned_data["year"] response = requests.get( f"http://www.omdbapi.com/?apikey={api_key}&t={search_title}&y={search_year}" ) response.raise_for_status() film_data = response.json() if Film.objects.filter(title=film_data["Title"]).exists(): messages.add_message( self.request, messages.INFO, f"This film is already present in the database.", ) else: film = Film( title=film_data["Title"], year=film_data["Year"], genre=film_data["Genre"], country=film_data["Country"], director=film_data["Director"], actors=film_data["Actors"], runtime=film_data["Runtime"], poster=film_data["Poster"], plot=film_data["Plot"], ) film.save() messages.add_message( self.request, messages.SUCCESS, f"{ film.title } successfully added to the database.", ) return HttpResponseRedirect(self.get_success_url()) def form_invalid(self, form): messages.add_message(self.request, messages.ERROR, "Something went wrong.") return HttpResponseRedirect(self.get_success_url()) class FilmsListView(ListView): model = Film context_object_name = "films" template_name = "manage-films-list.html" def get_queryset(self): parameter = self.kwargs.get("letter") if self.kwargs.get("letter") else "a" return Film.objects.filter(title__startswith=parameter) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) letters = list(string.ascii_uppercase) context["letters"] = letters context["selected_letter"] = ( self.kwargs.get("letter") if self.kwargs.get("letter") else "a" ) return context class FilmEditView(UpdateView): model = Film fields = [ "title", "year", "genre", "country", "director", "actors", "runtime", "poster", "trailer", "plot", "why", ] template_name = "edit-film.html" success_url = reverse_lazy("films_list")
URLs代码
urlpatterns = [ path("", ManageFilmsView.as_view(), {"letter": None}, name="manage_films"), ] htmxpatterns = [ path("<str:letter>", FilmsListView.as_view(), name="films_list"), path("edit/<int:pk>", FilmEditView.as_view(), name="edit_film"), path("delete/<int:pk>", DeleteFilmView.as_view(), name="delete_film"), ] urlpatterns += htmxpatterns
编辑页面模板(简化版)
{% load widget_tweaks %} <h2 class="text-xl my-4 ml-10 p-4">Here are the details to edit the informations about the film "{{ film.title }}"</h2> <form action="" action="" class="w-3/5 ml-10 flex flex-col" method="POST"> {% csrf_token %} <div class="mb-4"> <label class="mb-1 text-gray-100">{{ form.title.label|upper }}</label> {% render_field form.title class="bg-gray-50 border border-gray-300 text-gray-950 text-lg rounded-lg block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white" %} </div> <div class="mb-4"> <label class="mb-1 text-gray-100">{{ form.genre.label|upper }}</label> {% render_field form.genre class="bg-gray-50 border border-gray-300 text-gray-950 text-lg rounded-lg block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white" %} </div> <button type="submit" value="Update" class="w-1/4 mt-2 mb-20 text-gray-100 bg-gray-900 hover:bg-gray-950 dark:bg-gray-600 dark:hover:bg-red-900 font-medium rounded-lg text-sm px-5 py-2.5 text-center place-items-center">SAVE</button> </form>
问题排查与修复方案
核心原因分析
- 表单提交路径错误
模板里的form标签写了两个重复的action="",虽然浏览器会忽略重复属性,但空action可能导致请求提交到错误的路径(比如父页面的manage_films路径),从而触发添加视图的逻辑。 - URL路由匹配优先级
主路由的空路径""会匹配所有未被更具体路由捕获的请求,如果表单提交路径有误,会直接触发ManageFilmsView。
具体排查步骤
- 检查请求路径:打开浏览器开发者工具的Network面板,提交表单时查看POST请求的
Request URL,确认是否指向/edit/[影片ID]。如果不是,说明表单action存在问题。 - 修复表单action:把模板里的重复
action=""替换为明确的路由指向:action="{% url 'edit_film' film.pk %}",确保请求提交到UpdateView的正确路径。 - 验证UpdateView独立功能:直接访问
/edit/[影片ID]并提交表单,观察是否触发更新逻辑,排除路由或中间件的干扰。 - 添加调试日志:在
FilmEditView和ManageFilmsView的form_valid方法中添加打印语句,确认哪个视图被触发,进一步定位问题。
关键代码修复
修改编辑页面的表单action:
{% load widget_tweaks %} <h2 class="text-xl my-4 ml-10 p-4">编辑影片 "{{ film.title }}" 的信息</h2> <form action="{% url 'edit_film' film.pk %}" class="w-3/5 ml-10 flex flex-col" method="POST"> {% csrf_token %} <!-- 表单字段保持不变 --> <button type="submit" class="w-1/4 mt-2 mb-20 text-gray-100 bg-gray-900 hover:bg-gray-950 dark:bg-gray-600 dark:hover:bg-red-900 font-medium rounded-lg text-sm px-5 py-2.5 text-center place-items-center">保存</button> </form>
如果需要验证UpdateView的执行情况,可以重写form_valid添加提示:
class FilmEditView(UpdateView): # 原有属性保持不变 def form_valid(self, form): messages.add_message(self.request, messages.SUCCESS, f"{self.object.title} 信息更新成功") return super().form_valid(form)
内容的提问来源于stack exchange,提问作者Voyageur Zen
相关产品推荐
相关产品推荐

