确实有办法解决你的问题!
您需要对ModelAdmin.get_form()
提供的
子类化表单并覆盖它:
class BusinessDocumentCommentForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
# Voila, now you can access request anywhere in your form methods by using self.request!
super(BusinessDocumentCommentForm, self).__init__(*args, **kwargs)
if self.request.GET.get('document_pk', False):
#Do something
def clean(self):
# Do something with self.request
# etc.
class Meta:
model = BusinessDocumentComment
class BusinessDocumentCommentAdmin(admin.ModelAdmin):
form = BusinessDocumentCommentForm
def get_form(self, request, obj=None, **kwargs):
AdminForm = super(BusinessDocumentCommentAdmin, self).get_form(request, obj, **kwargs)
class AdminFormWithRequest(AdminForm):
def __new__(cls, *args, **kwargs):
kwargs['request'] = request
return AdminForm(*args, **kwargs)
return AdminFormWithRequest
这个解决方案对我有用。您可以在表单中的任何位置使用
self.request
来使用它,包括 def clean(self)
class MyModelAdmin(admin.ModelAdmin):
form = MyForm
def get_form(self, request, *args, **kwargs):
form = super(MyModelAdmin, self).get_form(request, *args, **kwargs)
form.request = request
return form
ModelAdmin
类中有许多挂钩可以让您执行此操作 - 请查看django.contrib.admin.options
中的代码。
可能对您有帮助的两个方法是
ModelAdmin.save_form
和 ModelAdmin.save_model
,这两个方法都传递请求对象。因此,您可以在 Admin 子类中重写这些方法并执行您需要的任何额外处理。
评论后已编辑
您说得很对,这不会让您根据用户的权限验证表单。不幸的是,表单实例化深深地埋藏在
add_view
和 change_view
的 ModelAdmin
方法中。
如果不复制大量现有代码,就没有多少可能性。您可以重写
*_view
方法;或者您可以尝试重写 modelform_factory
函数以返回一个已嵌入请求对象的新类;或者您可以尝试摆弄表单类 __new__
方法来执行相同的操作,但由于表单元类,这很棘手。
使用此函数作为表单类的代理,允许我们在表单实例上注入请求,以便我们可以在干净的方法中访问它。
通过使用如下解决方案(get_form_class_with_request),您可以将请求注入隔离到表单实例创建的时刻。这确保了每个表单实例都有自己的请求数据,从而降低了共享状态导致的冲突和意外行为的风险。
def get_form_class_with_request(
form_class: type[forms.ModelForm], request: HttpRequest
) -> Callable[[tuple[Any, ...], dict[str, Any]], ModelForm]:
def init_form(*args, **kwargs) -> ModelForm:
form_instance = form_class(*args, **kwargs)
form_instance.request = request
form_instance.current_user = request.user
return form_instance
init_form.base_fields = form_class.base_fields
return init_form
class CustomModelAdmin(admin.ModelAdmin):
form = YourForm
def get_form(self, request, *args, **kwargs):
form = super().get_form(request, *args, **kwargs)
form_proxy = get_form_class_with_request(form, request)
return form_proxy
总体而言,最佳实践是将特定于请求的数据保留在请求范围内,并避免将其直接存储在表单类或其他共享对象中,以保持适当的隔离并防止潜在问题。