django-eav2/eav/fields.py

115 lines
3.4 KiB
Python
Raw Normal View History

2010-09-27 13:28:52 +00:00
import re
from django.core.exceptions import ValidationError
2021-10-16 17:43:20 +00:00
from django.db import models
from django.utils.translation import gettext_lazy as _
2010-09-27 13:28:52 +00:00
2021-10-16 17:45:01 +00:00
from eav.forms import CSVFormField
2021-10-16 17:43:02 +00:00
2010-09-27 13:28:52 +00:00
class EavSlugField(models.SlugField):
"""
2010-09-27 13:28:52 +00:00
The slug field used by :class:`~eav.models.Attribute`
"""
2010-09-27 13:28:52 +00:00
def validate(self, value, instance):
"""
2010-09-27 13:28:52 +00:00
Slugs are used to convert the Python attribute name to a database
lookup and vice versa. We need it to be a valid Python identifier. We
don't want it to start with a '_', underscore will be used in
variables we don't want to be saved in the database.
"""
2010-09-27 13:28:52 +00:00
super(EavSlugField, self).validate(value, instance)
slug_regex = r'[a-z][a-z0-9_]*'
2010-09-27 13:28:52 +00:00
if not re.match(slug_regex, value):
2021-10-16 17:43:02 +00:00
raise ValidationError(
_(
'Must be all lower case, start with a letter, and contain '
'only letters, numbers, or underscores.'
)
)
2010-09-27 13:28:52 +00:00
@staticmethod
def create_slug_from_name(name):
"""Creates a slug based on the name."""
2010-09-27 13:28:52 +00:00
name = name.strip().lower()
# Change spaces to underscores.
2010-09-27 13:28:52 +00:00
name = '_'.join(name.split())
# Remove non alphanumeric characters.
2010-09-27 13:28:52 +00:00
return re.sub('[^\w]', '', name)
class EavDatatypeField(models.CharField):
"""
The datatype field used by :class:`~eav.models.Attribute`.
"""
2010-09-27 13:28:52 +00:00
def validate(self, value, instance):
"""
2010-09-27 13:28:52 +00:00
Raise ``ValidationError`` if they try to change the datatype of an
:class:`~eav.models.Attribute` that is already used by
:class:`~eav.models.Value` objects.
"""
2010-09-27 13:28:52 +00:00
super(EavDatatypeField, self).validate(value, instance)
2010-09-27 13:28:52 +00:00
if not instance.pk:
return
if type(instance).objects.get(pk=instance.pk).datatype == instance.datatype:
return
2010-09-27 13:28:52 +00:00
if instance.value_set.count():
2021-10-16 17:43:02 +00:00
raise ValidationError(
_(
'You cannot change the datatype of an attribute that is already in use.'
)
)
2021-10-16 17:43:02 +00:00
class CSVField(models.TextField): # (models.Field):
description = _("A Comma-Separated-Value field.")
default_separator = ";"
def __init__(self, separator=";", *args, **kwargs):
self.separator = separator
kwargs.setdefault('default', "")
super().__init__(*args, **kwargs)
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
if self.separator != self.default_separator:
kwargs['separator'] = self.separator
return name, path, args, kwargs
def formfield(self, **kwargs):
defaults = {'form_class': CSVFormField}
defaults.update(kwargs)
return super().formfield(**defaults)
def from_db_value(self, value, expression, connection, context=None):
if value is None:
return []
return value.split(self.separator)
def to_python(self, value):
if value is None:
return []
if isinstance(value, list):
return value
return value.split(self.separator)
def get_prep_value(self, value):
if not value:
return ""
if isinstance(value, str):
return value
elif isinstance(value, list):
return self.separator.join(value)
def value_to_string(self, obj):
value = self.value_from_object(obj)
return self.get_prep_value(value)