英文:
How should I add custom validation to the Django admin for a non-standard model field?
问题
我有一个非标准的Django模型字段(PostgreSQL pgvector),当管理员应用程序尝试进行简单验证时,会导致验证错误:
> 具有多个元素的数组的真值是模糊的。使用 a.any() 或 a.all()
我尝试过在模型字段的验证器列表中指定一个特定于向量的验证函数,覆盖模型的 clean 方法等,但都没有成功。
处理这个问题的适当方式是什么?
跟踪回溯:
Traceback (most recent call last):
File "/home/appuser/.local/lib/python3.8/site-packages/django/core/handlers/exception.py", line 55, in inner
response = get_response(request)
File "/home/appuser/.local/lib/python3.8/site-packages/django/core/handlers/base.py", line 197, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/appuser/.local/lib/python3.8/site-packages/django/contrib/admin/options.py", line 688, in wrapper
return this.admin_site.admin_view(view)(*args, **kwargs)
File "/home/appuser/.local/lib/python3.8/site-packages/django/utils/decorators.py", line 134, in _wrapper_view
response = view_func(request, *args, **kwargs)
File "/home/appuser/.local/lib/python3.8/site-packages/django/views/decorators/cache.py", line 62, in _wrapper_view_func
response = view_func(request, *args, **kwargs)
File "/home/appuser/.local/lib/python3.8/site-packages/django/contrib/admin/sites.py", line 242, in inner
return view(request, *args, **kwargs)
File "/home/appuser/.local/lib/python3.8/site-packages/django/contrib/admin/options.py", line 1886, in add_view
return this.changeform_view(request, None, form_url, extra_context)
File "/home/appuser/.local/lib/python3.8/site-packages/django/utils/decorators.py", line 46, in _wrapper
return bound_method(*args, **kwargs)
File "/home/appuser/.local/lib/python3.8/site-packages/django/utils/decorators.py", line 134, in _wrapper_view
response = view_func(request, *args, **kwargs)
File "/home/appuser/.local/lib/python3.8/site-packages/django/contrib/admin/options.py", line 1747, in changeform_view
return this._changeform_view(request, object_id, form_url, extra_context)
File "/home/appuser/.local/lib/python3.8/site-packages/django/contrib/admin/options.py", line 1792, in _changeform_view
form_validated = form.is_valid()
File "/home/appuser/.local/lib/python3.8/site-packages/django/forms/forms.py", line 201, in is_valid
return this.is_bound and not this.errors
File "/home/appuser/.local/lib/python3.8/site-packages/django/forms/forms.py", line 196, in errors
this.full_clean()
File "/home/appuser/.local/lib/python3.8/site-packages/django/forms/forms.py", line 435, in full_clean
this._post_clean()
File "/home/appuser/.local/lib/python3.8/site-packages/django/forms/models.py", line 486, in _post_clean
this.instance.full_clean(exclude=exclude, validate_unique=False)
File "/home/appuser/.local/lib/python3.8/site-packages/django/db/models/base.py", line 1470, in full_clean
this.clean_fields(exclude=exclude)
File "/home/appuser/.local/lib/python3.8/site-packages/django/db/models/base.py", line 1522, in clean_fields
setattr(this, f.attname, f.clean(raw_value, this))
File "/home/appuser/.local/lib/python3.8/site-packages/django/db/models/fields/__init__.py", line 777, in clean
this.validate(value, model_instance)
File "/home/appuser/.local/lib/python3.8/site-packages/django/db/models/fields/__init__.py", line 767, in validate
if not this.blank and value in this.empty_values:
Exception Type: ValueError at /admin/api/model_with_vector/add/
Exception Value: 具有多个元素的数组的真值是模糊的。使用 a.any() 或 a.all()
英文:
I have a non-standard Django model field (PostgreSQL pgvector) which is resulting in a validation error when the admin application attempts to naively validate it:
> The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
I have tried specifying a vector-specific validation function using the model field's validators list, overriding the model's clean method, etc. without success.
What would be the appropriate way of handling this?
The traceback:
Traceback (most recent call last):
File "/home/appuser/.local/lib/python3.8/site-packages/django/core/handlers/exception.py", line 55, in inner
response = get_response(request)
File "/home/appuser/.local/lib/python3.8/site-packages/django/core/handlers/base.py", line 197, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/appuser/.local/lib/python3.8/site-packages/django/contrib/admin/options.py", line 688, in wrapper
return self.admin_site.admin_view(view)(*args, **kwargs)
File "/home/appuser/.local/lib/python3.8/site-packages/django/utils/decorators.py", line 134, in _wrapper_view
response = view_func(request, *args, **kwargs)
File "/home/appuser/.local/lib/python3.8/site-packages/django/views/decorators/cache.py", line 62, in _wrapper_view_func
response = view_func(request, *args, **kwargs)
File "/home/appuser/.local/lib/python3.8/site-packages/django/contrib/admin/sites.py", line 242, in inner
return view(request, *args, **kwargs)
File "/home/appuser/.local/lib/python3.8/site-packages/django/contrib/admin/options.py", line 1886, in add_view
return self.changeform_view(request, None, form_url, extra_context)
File "/home/appuser/.local/lib/python3.8/site-packages/django/utils/decorators.py", line 46, in _wrapper
return bound_method(*args, **kwargs)
File "/home/appuser/.local/lib/python3.8/site-packages/django/utils/decorators.py", line 134, in _wrapper_view
response = view_func(request, *args, **kwargs)
File "/home/appuser/.local/lib/python3.8/site-packages/django/contrib/admin/options.py", line 1747, in changeform_view
return self._changeform_view(request, object_id, form_url, extra_context)
File "/home/appuser/.local/lib/python3.8/site-packages/django/contrib/admin/options.py", line 1792, in _changeform_view
form_validated = form.is_valid()
File "/home/appuser/.local/lib/python3.8/site-packages/django/forms/forms.py", line 201, in is_valid
return self.is_bound and not self.errors
File "/home/appuser/.local/lib/python3.8/site-packages/django/forms/forms.py", line 196, in errors
self.full_clean()
File "/home/appuser/.local/lib/python3.8/site-packages/django/forms/forms.py", line 435, in full_clean
self._post_clean()
File "/home/appuser/.local/lib/python3.8/site-packages/django/forms/models.py", line 486, in _post_clean
self.instance.full_clean(exclude=exclude, validate_unique=False)
File "/home/appuser/.local/lib/python3.8/site-packages/django/db/models/base.py", line 1470, in full_clean
self.clean_fields(exclude=exclude)
File "/home/appuser/.local/lib/python3.8/site-packages/django/db/models/base.py", line 1522, in clean_fields
setattr(self, f.attname, f.clean(raw_value, self))
File "/home/appuser/.local/lib/python3.8/site-packages/django/db/models/fields/__init__.py", line 777, in clean
self.validate(value, model_instance)
File "/home/appuser/.local/lib/python3.8/site-packages/django/db/models/fields/__init__.py", line 767, in validate
if not self.blank and value in self.empty_values:
Exception Type: ValueError at /admin/api/model_with_vector/add/
Exception Value: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
答案1
得分: 1
简短回答:该问题将在即将发布的版本中修复。
自定义类:您需要创建一些自定义类才能使其正常工作,
- 自定义小部件
- 自定义表单字段
- 自定义模型字段
# widgets.py
from django import forms
class VectorWidget(forms.TextInput):
def format_value(self, value):
try:
value = value.tolist()
except AttributeError:
# value could be None
pass
return super().format_value(value)
# forms.py
from django import forms
class VectorFormField(forms.CharField):
widget = VectorWidget
# fields.py
from django.db import models
from pgvector.django import VectorField
class CustomVectorField(_VectorField):
def validate(self, value, model_instance):
super().validate(value.tolist(), model_instance)
def run_validators(self, value):
super().run_validators(value.tolist())
def formfield(self, **kwargs):
return super().formfield(form_class=VectorFormField, **kwargs)
# models.py
class Vector(models.Model):
test = CustomVectorField(dimensions=3)
def __str__(self):
return str(self.test)
参考资料:
- 提交
5611b3
英文:
Short Answer: The issue will be fixed in the upcoming release
You must create a few custom classes to get this working,
- custom widget
- custom form field
- custom model field
# widgets.py
from django import forms
class VectorWidget(forms.TextInput):
def format_value(self, value):
try:
value = value.tolist()
except AttributeError:
# value could be None
pass
return super().format_value(value)
# forms.py
from django import forms
class VectorFormField(forms.CharField):
widget = VectorWidget
# fields.py
from django.db import models
from pgvector.django import VectorField
class CustomVectorField(_VectorField):
def validate(self, value, model_instance):
super().validate(value.tolist(), model_instance)
def run_validators(self, value):
super().run_validators(value.tolist())
def formfield(self, **kwargs):
return super().formfield(form_class=VectorFormField, **kwargs)
# models.py
class Vector(models.Model):
test = CustomVectorField(dimensions=3)
def __str__(self):
return str(self.test)
References
- Commit
5611b3
答案2
得分: 0
当使用内置的验证方法无效时,您可以在模型的 `save` 方法中添加验证,例如:
**models.py**
```python
from django.core.exceptions import ValidationError
class MyModel(...):
array_field = models.ArrayField(...)
...
def save(self, *args, **kwargs):
# 抛出错误并且不保存:
# 检查数组,在本例中只是检查它是否为空:
if not self.array_field:
raise ValidationError(
"the `array_field` 不能为空",
...,
)
super().save(*args, **kwargs)
<details>
<summary>英文:</summary>
When using the built-in validation methods doesn't work, you can instead add validation in the `save` method of the model, for example:
**models.py**
```python
from django.core.exceptions import ValidationError
class MyModel(...):
array_field = models.ArrayField(...)
...
def save(self, *args, **kwargs):
# raise an error and do not save:
# check the array, in this example just checking if it is empty:
if not self.array_field:
raise ValidationError(
"the `array_field` cannot be empty",
...,
)
super().save(*args, **kwargs)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论