Skip to content

Commit

Permalink
Merge pull request #30 from maykinmedia/feature-validate-slug-fields
Browse files Browse the repository at this point in the history
Add slug field validation
  • Loading branch information
swrichards authored Dec 13, 2024
2 parents e2f4b2f + 9c38ec3 commit bad0d33
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 1 deletion.
6 changes: 5 additions & 1 deletion django_setup_configuration/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from django.db import models
from django.db.models.fields import NOT_PROVIDED, Field

from pydantic import constr
from pydantic.fields import FieldInfo


Expand Down Expand Up @@ -47,6 +48,9 @@ class UNMAPPED_DJANGO_FIELD:
pass


_SLUG_RE = r"^[-a-zA-Z0-9_]+\z"


class DjangoModelRefInfo(FieldInfo):
"""
A FieldInfo representing a reference to a field on a Django model.
Expand Down Expand Up @@ -153,8 +157,8 @@ def _get_python_type(
models.TextField: str,
models.EmailField: str,
models.URLField: str,
models.SlugField: str,
models.UUIDField: str,
models.SlugField: constr(pattern=_SLUG_RE),
# Integer-based fields
models.AutoField: int,
models.SmallAutoField: int,
Expand Down
1 change: 1 addition & 0 deletions testapp/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class TestModel(models.Model):
nullable_str = models.CharField(null=True, blank=False, max_length=1)
nullable_and_blank_str = models.CharField(null=True, blank=False, max_length=1)
blank_str = models.CharField(null=False, blank=True, max_length=1)
slug = models.SlugField()

field_with_help_text = models.IntegerField(help_text="This is the help text")
field_with_verbose_name = models.IntegerField(verbose_name="The Verbose Name")
Expand Down
54 changes: 54 additions & 0 deletions tests/test_django_model_ref_field.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
from typing import Literal

from django.core.exceptions import ValidationError as DjangoValidationError
from django.core.validators import validate_slug

import pytest
from pydantic import ValidationError
from pydantic.fields import PydanticUndefined

from django_setup_configuration.fields import DjangoModelRef
Expand Down Expand Up @@ -51,6 +55,56 @@ class Config(ConfigurationModel):
assert field.is_required() is True


@pytest.mark.parametrize(
"invalid_values",
(
"",
"hello world",
"[email protected]",
"$price",
"my.variable",
"résumé",
"hello!",
"!",
"#",
"+",
),
)
def test_slug_validation_fails_on_both_pydantic_and_django(invalid_values):

class Config(ConfigurationModel):
slug = DjangoModelRef(TestModel, "slug")

with pytest.raises(ValidationError):
Config(slug=invalid_values)

with pytest.raises(DjangoValidationError):
validate_slug(invalid_values)


@pytest.mark.parametrize(
"valid_values",
(
"a",
"foo-bar",
"foo_bar",
"foo_bar_baz",
"foo-bar-baz",
"fO0-B4r-Baz",
"foo-bar-baz",
"foobarbaz",
"FooBarBaz",
),
)
def test_slug_validation_succeeds_on_both_pydantic_and_django(valid_values):

class Config(ConfigurationModel):
slug = DjangoModelRef(TestModel, "slug")

Config.model_validate(dict(slug=valid_values))
validate_slug(valid_values) # does not raise


def test_no_default_makes_field_required():

class Config(ConfigurationModel):
Expand Down

0 comments on commit bad0d33

Please sign in to comment.