refactor: move generate_slug to logic

This commit is contained in:
Mike 2022-08-12 14:23:41 -07:00
parent f6afc45613
commit 653ed7fd38
4 changed files with 52 additions and 20 deletions

View file

@ -1,27 +1,12 @@
import re
import secrets
import string
from django.core.exceptions import ValidationError
from django.db import models
from django.utils.text import slugify
from django.utils.translation import gettext_lazy as _
from eav.forms import CSVFormField
def generate_slug(name: str) -> str:
"""Generates a valid slug based on ``name``."""
slug = slugify(name, allow_unicode=False)
if not slug:
# Fallback to ensure a slug is always generated by using a random one
chars = string.ascii_lowercase + string.digits
randstr = ''.join(secrets.choice(chars) for _ in range(8))
slug = 'rand-{0}'.format(randstr)
return slug.encode('utf-8', 'surrogateescape').decode()
class EavSlugField(models.SlugField):
"""
The slug field used by :class:`~eav.models.Attribute`

22
eav/logic/slug.py Normal file
View file

@ -0,0 +1,22 @@
import secrets
import string
from typing import Final
from django.utils.text import slugify
SLUGFIELD_MAX_LENGTH: Final = 50
def generate_slug(name: str) -> str:
"""Generates a valid slug based on ``name``."""
slug = slugify(name, allow_unicode=False)
if not slug:
# Fallback to ensure a slug is always generated by using a random one
chars = string.ascii_lowercase + string.digits
randstr = ''.join(secrets.choice(chars) for _ in range(8))
slug = 'rand-{0}'.format(randstr)
slug = slug.encode('utf-8', 'surrogateescape').decode()
return slug[:SLUGFIELD_MAX_LENGTH]

View file

@ -10,6 +10,7 @@ optional metaclass for each eav model class.
"""
from copy import copy
from typing import Final
from django.contrib.contenttypes import fields as generic
from django.contrib.contenttypes.models import ContentType
@ -22,8 +23,9 @@ from django.utils.translation import gettext_lazy as _
from eav import register
from eav.exceptions import IllegalAssignmentException
from eav.fields import CSVField, EavDatatypeField, EavSlugField, generate_slug
from eav.fields import CSVField, EavDatatypeField
from eav.logic.entity_pk import get_entity_pk_type
from eav.logic.slug import SLUGFIELD_MAX_LENGTH, generate_slug
from eav.validators import (
validate_bool,
validate_csv,
@ -42,6 +44,9 @@ except ImportError:
from django_jsonfield_backport.models import JSONField
CHARFIELD_LENGTH: Final = 100
class EnumValue(models.Model):
"""
*EnumValue* objects are the value 'choices' to multiple choice *TYPE_ENUM*
@ -73,7 +78,7 @@ class EnumValue(models.Model):
_('Value'),
db_index=True,
unique=True,
max_length=50,
max_length=SLUGFIELD_MAX_LENGTH,
)
def __str__(self):
@ -94,7 +99,7 @@ class EnumGroup(models.Model):
See :class:`EnumValue` for an example.
"""
name = models.CharField(_('Name'), unique=True, max_length=100)
name = models.CharField(_('Name'), unique=True, max_length=CHARFIELD_LENGTH)
values = models.ManyToManyField(EnumValue, verbose_name=_('Enum group'))
def __str__(self):
@ -191,7 +196,7 @@ class Attribute(models.Model):
name = models.CharField(
verbose_name=_('Name'),
max_length=100,
max_length=CHARFIELD_LENGTH,
help_text=_('User-friendly attribute name'),
)
@ -202,7 +207,7 @@ class Attribute(models.Model):
"""
slug = models.SlugField(
verbose_name=_('Slug'),
max_length=50,
max_length=SLUGFIELD_MAX_LENGTH,
db_index=True,
unique=True,
help_text=_('Short unique attribute label'),

20
tests/test_logic.py Normal file
View file

@ -0,0 +1,20 @@
from hypothesis import given
from hypothesis import strategies as st
from eav.logic.slug import SLUGFIELD_MAX_LENGTH, generate_slug
@given(st.text())
def test_generate_slug(name: str) -> None:
"""Ensures slug generation works properly."""
slug = generate_slug(name)
assert slug
@given(st.text(min_size=SLUGFIELD_MAX_LENGTH))
def test_generate_long_slug_text(name: str) -> None:
"""Ensures a slug isn't generated longer than maximum allowed length."""
slug = generate_slug(name)
assert len(slug) <= SLUGFIELD_MAX_LENGTH