from slugify import slugify from wtforms_alchemy.validators import Unique, ValidationError class UniqueSlug(Unique): """ Validates slug field related for the specified field. Use `slug` column to point validator to the specific slug field in model. User `limiter_column` to add etra scope limitation. """ def __init__( self, column, slug_column, limiter_column=None, get_session=None, message=None, slug_repr=None, ): super().__init__(column, get_session, message) self.slug_column = slug_column self.limiter_column = limiter_column self.slug_repr = slug_repr or self.get_default_slug_repr() def __call__(self, form, field): query = None if self.limiter_column: columns = self._syntaxes_as_tuples( form, field, self.limiter_column ) self.model = columns[0][1].class_ query = self.query for field_name, column in columns: query = query.filter(column == form[field_name].data) columns = self._syntaxes_as_tuples(form, field, self.column) self.model = columns[0][1].class_ if not query: query = self.query for field_name, column in columns: slug = slugify(str(form[field_name].data)) query = query.filter(self.slug_column == slug) obj = query.first() if not hasattr(form, "_obj"): raise Exception( "Couldn't access Form._obj attribute. Either make your form " "inherit WTForms-Alchemy ModelForm or WTForms-Components " "ModelForm or make this attribute available in your form." ) if obj and not form._obj == obj: if self.message is None: self.message = field.gettext( f"{self.slug_repr} already exists." ) raise ValidationError(self.message) def get_default_slug_repr(self): name = self.slug_column.name slug_repr = " ".join(name.split("_")).capitalize() return slug_repr