如何向Django管理员为非标准模型字段添加自定义验证?

huangapple go评论94阅读模式
英文:

How should I add custom validation to the Django admin for a non-standard model field?

问题

我有一个非标准的Django模型字段(PostgreSQL pgvector),当管理员应用程序尝试进行简单验证时,会导致验证错误:

> 具有多个元素的数组的真值是模糊的。使用 a.any() 或 a.all()

我尝试过在模型字段的验证器列表中指定一个特定于向量的验证函数,覆盖模型的 clean 方法等,但都没有成功。

处理这个问题的适当方式是什么?

跟踪回溯:

  1. Traceback (most recent call last):
  2. File "/home/appuser/.local/lib/python3.8/site-packages/django/core/handlers/exception.py", line 55, in inner
  3. response = get_response(request)
  4. File "/home/appuser/.local/lib/python3.8/site-packages/django/core/handlers/base.py", line 197, in _get_response
  5. response = wrapped_callback(request, *callback_args, **callback_kwargs)
  6. File "/home/appuser/.local/lib/python3.8/site-packages/django/contrib/admin/options.py", line 688, in wrapper
  7. return this.admin_site.admin_view(view)(*args, **kwargs)
  8. File "/home/appuser/.local/lib/python3.8/site-packages/django/utils/decorators.py", line 134, in _wrapper_view
  9. response = view_func(request, *args, **kwargs)
  10. File "/home/appuser/.local/lib/python3.8/site-packages/django/views/decorators/cache.py", line 62, in _wrapper_view_func
  11. response = view_func(request, *args, **kwargs)
  12. File "/home/appuser/.local/lib/python3.8/site-packages/django/contrib/admin/sites.py", line 242, in inner
  13. return view(request, *args, **kwargs)
  14. File "/home/appuser/.local/lib/python3.8/site-packages/django/contrib/admin/options.py", line 1886, in add_view
  15. return this.changeform_view(request, None, form_url, extra_context)
  16. File "/home/appuser/.local/lib/python3.8/site-packages/django/utils/decorators.py", line 46, in _wrapper
  17. return bound_method(*args, **kwargs)
  18. File "/home/appuser/.local/lib/python3.8/site-packages/django/utils/decorators.py", line 134, in _wrapper_view
  19. response = view_func(request, *args, **kwargs)
  20. File "/home/appuser/.local/lib/python3.8/site-packages/django/contrib/admin/options.py", line 1747, in changeform_view
  21. return this._changeform_view(request, object_id, form_url, extra_context)
  22. File "/home/appuser/.local/lib/python3.8/site-packages/django/contrib/admin/options.py", line 1792, in _changeform_view
  23. form_validated = form.is_valid()
  24. File "/home/appuser/.local/lib/python3.8/site-packages/django/forms/forms.py", line 201, in is_valid
  25. return this.is_bound and not this.errors
  26. File "/home/appuser/.local/lib/python3.8/site-packages/django/forms/forms.py", line 196, in errors
  27. this.full_clean()
  28. File "/home/appuser/.local/lib/python3.8/site-packages/django/forms/forms.py", line 435, in full_clean
  29. this._post_clean()
  30. File "/home/appuser/.local/lib/python3.8/site-packages/django/forms/models.py", line 486, in _post_clean
  31. this.instance.full_clean(exclude=exclude, validate_unique=False)
  32. File "/home/appuser/.local/lib/python3.8/site-packages/django/db/models/base.py", line 1470, in full_clean
  33. this.clean_fields(exclude=exclude)
  34. File "/home/appuser/.local/lib/python3.8/site-packages/django/db/models/base.py", line 1522, in clean_fields
  35. setattr(this, f.attname, f.clean(raw_value, this))
  36. File "/home/appuser/.local/lib/python3.8/site-packages/django/db/models/fields/__init__.py", line 777, in clean
  37. this.validate(value, model_instance)
  38. File "/home/appuser/.local/lib/python3.8/site-packages/django/db/models/fields/__init__.py", line 767, in validate
  39. if not this.blank and value in this.empty_values:
  40. Exception Type: ValueError at /admin/api/model_with_vector/add/
  41. 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:

  1. Traceback (most recent call last):
  2. File "/home/appuser/.local/lib/python3.8/site-packages/django/core/handlers/exception.py", line 55, in inner
  3. response = get_response(request)
  4. File "/home/appuser/.local/lib/python3.8/site-packages/django/core/handlers/base.py", line 197, in _get_response
  5. response = wrapped_callback(request, *callback_args, **callback_kwargs)
  6. File "/home/appuser/.local/lib/python3.8/site-packages/django/contrib/admin/options.py", line 688, in wrapper
  7. return self.admin_site.admin_view(view)(*args, **kwargs)
  8. File "/home/appuser/.local/lib/python3.8/site-packages/django/utils/decorators.py", line 134, in _wrapper_view
  9. response = view_func(request, *args, **kwargs)
  10. File "/home/appuser/.local/lib/python3.8/site-packages/django/views/decorators/cache.py", line 62, in _wrapper_view_func
  11. response = view_func(request, *args, **kwargs)
  12. File "/home/appuser/.local/lib/python3.8/site-packages/django/contrib/admin/sites.py", line 242, in inner
  13. return view(request, *args, **kwargs)
  14. File "/home/appuser/.local/lib/python3.8/site-packages/django/contrib/admin/options.py", line 1886, in add_view
  15. return self.changeform_view(request, None, form_url, extra_context)
  16. File "/home/appuser/.local/lib/python3.8/site-packages/django/utils/decorators.py", line 46, in _wrapper
  17. return bound_method(*args, **kwargs)
  18. File "/home/appuser/.local/lib/python3.8/site-packages/django/utils/decorators.py", line 134, in _wrapper_view
  19. response = view_func(request, *args, **kwargs)
  20. File "/home/appuser/.local/lib/python3.8/site-packages/django/contrib/admin/options.py", line 1747, in changeform_view
  21. return self._changeform_view(request, object_id, form_url, extra_context)
  22. File "/home/appuser/.local/lib/python3.8/site-packages/django/contrib/admin/options.py", line 1792, in _changeform_view
  23. form_validated = form.is_valid()
  24. File "/home/appuser/.local/lib/python3.8/site-packages/django/forms/forms.py", line 201, in is_valid
  25. return self.is_bound and not self.errors
  26. File "/home/appuser/.local/lib/python3.8/site-packages/django/forms/forms.py", line 196, in errors
  27. self.full_clean()
  28. File "/home/appuser/.local/lib/python3.8/site-packages/django/forms/forms.py", line 435, in full_clean
  29. self._post_clean()
  30. File "/home/appuser/.local/lib/python3.8/site-packages/django/forms/models.py", line 486, in _post_clean
  31. self.instance.full_clean(exclude=exclude, validate_unique=False)
  32. File "/home/appuser/.local/lib/python3.8/site-packages/django/db/models/base.py", line 1470, in full_clean
  33. self.clean_fields(exclude=exclude)
  34. File "/home/appuser/.local/lib/python3.8/site-packages/django/db/models/base.py", line 1522, in clean_fields
  35. setattr(self, f.attname, f.clean(raw_value, self))
  36. File "/home/appuser/.local/lib/python3.8/site-packages/django/db/models/fields/__init__.py", line 777, in clean
  37. self.validate(value, model_instance)
  38. File "/home/appuser/.local/lib/python3.8/site-packages/django/db/models/fields/__init__.py", line 767, in validate
  39. if not self.blank and value in self.empty_values:
  40. Exception Type: ValueError at /admin/api/model_with_vector/add/
  41. Exception Value: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

答案1

得分: 1

简短回答:该问题将在即将发布的版本中修复。

自定义类:您需要创建一些自定义类才能使其正常工作,

  • 自定义小部件
  • 自定义表单字段
  • 自定义模型字段
  1. # widgets.py
  2. from django import forms
  3. class VectorWidget(forms.TextInput):
  4. def format_value(self, value):
  5. try:
  6. value = value.tolist()
  7. except AttributeError:
  8. # value could be None
  9. pass
  10. return super().format_value(value)
  1. # forms.py
  2. from django import forms
  3. class VectorFormField(forms.CharField):
  4. widget = VectorWidget
  1. # fields.py
  2. from django.db import models
  3. from pgvector.django import VectorField
  4. class CustomVectorField(_VectorField):
  5. def validate(self, value, model_instance):
  6. super().validate(value.tolist(), model_instance)
  7. def run_validators(self, value):
  8. super().run_validators(value.tolist())
  9. def formfield(self, **kwargs):
  10. return super().formfield(form_class=VectorFormField, **kwargs)
  1. # models.py
  2. class Vector(models.Model):
  3. test = CustomVectorField(dimensions=3)
  4. def __str__(self):
  5. return str(self.test)

参考资料

英文:

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
  1. # widgets.py
  2. from django import forms
  3. class VectorWidget(forms.TextInput):
  4. def format_value(self, value):
  5. try:
  6. value = value.tolist()
  7. except AttributeError:
  8. # value could be None
  9. pass
  10. return super().format_value(value)
  1. # forms.py
  2. from django import forms
  3. class VectorFormField(forms.CharField):
  4. widget = VectorWidget
  1. # fields.py
  2. from django.db import models
  3. from pgvector.django import VectorField
  4. class CustomVectorField(_VectorField):
  5. def validate(self, value, model_instance):
  6. super().validate(value.tolist(), model_instance)
  7. def run_validators(self, value):
  8. super().run_validators(value.tolist())
  9. def formfield(self, **kwargs):
  10. return super().formfield(form_class=VectorFormField, **kwargs)
  1. # models.py
  2. class Vector(models.Model):
  3. test = CustomVectorField(dimensions=3)
  4. def __str__(self):
  5. return str(self.test)

References

答案2

得分: 0

  1. 当使用内置的验证方法无效时您可以在模型的 `save` 方法中添加验证例如
  2. **models.py**
  3. ```python
  4. from django.core.exceptions import ValidationError
  5. class MyModel(...):
  6. array_field = models.ArrayField(...)
  7. ...
  8. def save(self, *args, **kwargs):
  9. # 抛出错误并且不保存:
  10. # 检查数组,在本例中只是检查它是否为空:
  11. if not self.array_field:
  12. raise ValidationError(
  13. "the `array_field` 不能为空",
  14. ...,
  15. )
  16. super().save(*args, **kwargs)
  1. <details>
  2. <summary>英文:</summary>
  3. When using the built-in validation methods doesn&#39;t work, you can instead add validation in the `save` method of the model, for example:
  4. **models.py**
  5. ```python
  6. from django.core.exceptions import ValidationError
  7. class MyModel(...):
  8. array_field = models.ArrayField(...)
  9. ...
  10. def save(self, *args, **kwargs):
  11. # raise an error and do not save:
  12. # check the array, in this example just checking if it is empty:
  13. if not self.array_field:
  14. raise ValidationError(
  15. &quot;the `array_field` cannot be empty&quot;,
  16. ...,
  17. )
  18. super().save(*args, **kwargs)

huangapple
  • 本文由 发表于 2023年7月14日 03:50:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/76682791.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定