Django改写save_related后重定向至对象修改页失败问题咨询
问题解答
1. 实现方案的合理性
思路方向是对的:通过捕获文件处理异常、添加用户提示、重定向回修改页来避免触发500错误,但存在两个关键缺陷:
save_related方法设计为无返回值,你返回的HttpResponseRedirect会被Django Admin的上层逻辑忽略,所以重定向不会生效,最终还是会走默认的保存后跳转逻辑(列表页)。- 异常覆盖范围不完整:外层
try仅包裹了file_field存在时的逻辑,若TimeoutError发生在这个分支外不会被捕获;且内层try仅在文件读取成功时才调用super().save_related(),意味着文件读取失败时,关联对象的保存逻辑会被跳过,可能导致数据不一致。
2. 修复重定向问题的可行方案
方案一:移到表单验证阶段(推荐)
将文件读取逻辑放到表单的clean_file_field方法中,在表单验证阶段就捕获错误,Django Admin会自动停留在修改页并显示错误信息,无需手动重定向,这是符合Django Admin流程的标准做法:
from django import forms from django.contrib import admin from .models import MyModel class MyModelForm(forms.ModelForm): class Meta: model = MyModel fields = '__all__' def clean_file_field(self): file = self.cleaned_data.get('file_field') if file: DEFAULT_COLUMN_INDEX = 0 try: # 这里写入你的文件读取与处理逻辑 # 示例: # with file.open() as f: # content = f.read() # # 处理内容,若验证失败直接抛出ValidationError pass except ValidationError as e: raise forms.ValidationError(f"数据处理错误:{str(e)}") except TimeoutError as e: raise forms.ValidationError(f"文件上传超时:{str(e)}") return file class MyModelAdmin(admin.ModelAdmin): form = MyModelForm # 其他Admin配置项...
方案二:通过response_change拦截重定向(适合必须在save_related处理的场景)
如果文件处理依赖已保存的对象,必须在save_related中执行,可以通过设置标志位,在response_change方法中修改重定向目标:
from django.contrib import admin from django.shortcuts import redirect, reverse from django.contrib import messages from .models import MyModel class MyModelAdmin(admin.ModelAdmin): def save_related(self, request, form, formsets, change): self._file_error = False try: cleaned_data = form.cleaned_data if cleaned_data['file_field']: DEFAULT_COLUMN_INDEX = 0 try: # 文件读取与处理逻辑 super().save_related(request, form, formsets, change) except ValidationError as e: messages.error(request, f"数据处理错误:{str(e)}") self._file_error = True except TimeoutError as e: messages.error(request, f"文件上传超时:{str(e)}") self._file_error = True else: super().save_related(request, form, formsets, change) except Exception as e: messages.error(request, f"未知错误:{str(e)}") self._file_error = True def response_change(self, request, obj): if hasattr(self, '_file_error') and self._file_error: return redirect(reverse('admin:mymodel_change', args=[obj.id])) return super().response_change(request, obj)
内容的提问来源于stack exchange,提问作者rezaebrh
相关产品推荐
相关产品推荐

