10 Commits
v6.1 ... v6.4

Author SHA1 Message Date
Swen Kooij
f024e4feb5 Bump version to v6.4 2021-03-22 07:47:23 +02:00
Swen Kooij
92cb5e8b1f Add LocalizedValue.is_empty() 2021-03-22 07:47:00 +02:00
Swen Kooij
5c298ef13e Bump version number to 6.3 2021-03-13 14:01:51 +02:00
Swen Kooij
1b3e5989d3 LocalizedUniqueSlugField should properly deconstruct 'enabled' flag 2021-03-13 13:45:22 +02:00
Swen Kooij
d57f9a41bb Mark pytest as a third-party library for isort
Not sure why it doesn't get that.
2021-03-13 13:32:01 +02:00
Swen Kooij
bd8924224e Add flag to disable LocalizedUniqueSlugField 2021-03-13 13:24:36 +02:00
Swen Kooij
62e1e805c7 Bump version number to v6.2 2020-12-07 10:49:36 +02:00
Swen Kooij
afc39745bf Bump version number to 6.2rc1 2020-11-30 12:28:03 +02:00
Swen Kooij
1406954dec Merge pull request #91 from SectorLabs/immutable-slugs
Add a flag to make LocalizedUniqueSlugField immutable
2020-11-30 12:26:47 +02:00
Swen Kooij
afb94ecf66 Add a flag to make LocalizedUniqueSlugField immutable 2020-11-27 16:36:23 +02:00
6 changed files with 98 additions and 5 deletions

View File

@@ -21,6 +21,10 @@ class LocalizedUniqueSlugField(LocalizedAutoSlugField):
When in doubt, use this over :see:LocalizedAutoSlugField. When in doubt, use this over :see:LocalizedAutoSlugField.
Inherit from :see:AtomicSlugRetryMixin in your model to Inherit from :see:AtomicSlugRetryMixin in your model to
make this field work properly. make this field work properly.
By default, this creates a new slug if the field(s) specified
in `populate_from` are changed. Set `immutable=True` to get
immutable slugs.
""" """
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@@ -28,6 +32,9 @@ class LocalizedUniqueSlugField(LocalizedAutoSlugField):
kwargs["uniqueness"] = kwargs.pop("uniqueness", get_language_codes()) kwargs["uniqueness"] = kwargs.pop("uniqueness", get_language_codes())
self.enabled = kwargs.pop("enabled", True)
self.immutable = kwargs.pop("immutable", False)
super(LocalizedUniqueSlugField, self).__init__(*args, **kwargs) super(LocalizedUniqueSlugField, self).__init__(*args, **kwargs)
self.populate_from = kwargs.pop("populate_from") self.populate_from = kwargs.pop("populate_from")
@@ -42,6 +49,13 @@ class LocalizedUniqueSlugField(LocalizedAutoSlugField):
kwargs["populate_from"] = self.populate_from kwargs["populate_from"] = self.populate_from
kwargs["include_time"] = self.include_time kwargs["include_time"] = self.include_time
if self.enabled is False:
kwargs["enabled"] = self.enabled
if self.immutable is True:
kwargs["immutable"] = self.immutable
return name, path, args, kwargs return name, path, args, kwargs
def pre_save(self, instance, add: bool): def pre_save(self, instance, add: bool):
@@ -59,6 +73,9 @@ class LocalizedUniqueSlugField(LocalizedAutoSlugField):
The localized slug that was generated. The localized slug that was generated.
""" """
if not self.enabled:
return getattr(instance, self.name)
if not isinstance(instance, AtomicSlugRetryMixin): if not isinstance(instance, AtomicSlugRetryMixin):
raise ImproperlyConfigured( raise ImproperlyConfigured(
( (
@@ -76,10 +93,14 @@ class LocalizedUniqueSlugField(LocalizedAutoSlugField):
slug = slugify(value, allow_unicode=True) slug = slugify(value, allow_unicode=True)
current_slug = getattr(instance, self.name).get(lang_code)
if current_slug and self.immutable:
slugs.set(lang_code, current_slug)
continue
# verify whether it's needed to re-generate a slug, # verify whether it's needed to re-generate a slug,
# if not, re-use the same slug # if not, re-use the same slug
if instance.pk is not None: if instance.pk is not None:
current_slug = getattr(instance, self.name).get(lang_code)
if current_slug is not None: if current_slug is not None:
current_slug_end_index = current_slug.rfind("-") current_slug_end_index = current_slug.rfind("-")
stripped_slug = current_slug[0:current_slug_end_index] stripped_slug = current_slug[0:current_slug_end_index]

View File

@@ -136,6 +136,15 @@ class LocalizedValue(dict):
return None return None
def is_empty(self) -> bool:
"""Gets whether all the languages contain the default value."""
for lang_code, _ in settings.LANGUAGES:
if self.get(lang_code) != self.default_value:
return False
return True
def __str__(self) -> str: def __str__(self) -> str:
"""Gets the value in the current language or falls back to the next """Gets the value in the current language or falls back to the next
language if there's no value in the current language.""" language if there's no value in the current language."""

View File

@@ -9,4 +9,4 @@ lines_between_types=1
include_trailing_comma=True include_trailing_comma=True
not_skip=__init__.py not_skip=__init__.py
known_standard_library=dataclasses known_standard_library=dataclasses
known_third_party=django_bleach,bleach known_third_party=django_bleach,bleach,pytest

View File

@@ -36,7 +36,7 @@ with open(
setup( setup(
name="django-localized-fields", name="django-localized-fields",
version="6.1", version="6.4",
packages=find_packages(exclude=["tests"]), packages=find_packages(exclude=["tests"]),
include_package_data=True, include_package_data=True,
license="MIT License", license="MIT License",

View File

@@ -1,5 +1,7 @@
import copy import copy
import pytest
from django import forms from django import forms
from django.conf import settings from django.conf import settings
from django.db import models from django.db import models
@@ -215,6 +217,53 @@ class LocalizedSlugFieldTestCase(TestCase):
for lang_code, lang_name in settings.LANGUAGES: for lang_code, lang_name in settings.LANGUAGES:
assert obj.slug.get(lang_code) == "title-%s" % lang_name.lower() assert obj.slug.get(lang_code) == "title-%s" % lang_name.lower()
@classmethod
def test_disable(cls):
"""Tests whether disabling auto-slugging works."""
Model = get_fake_model(
{
"title": LocalizedField(),
"slug": LocalizedUniqueSlugField(
populate_from="title", enabled=False
),
}
)
obj = Model()
obj.title = "test"
# should raise IntegrityError because auto-slugging
# is disabled and the slug field is NULL
with pytest.raises(IntegrityError):
obj.save()
@classmethod
def test_allows_override_when_immutable(cls):
"""Tests whether setting a value manually works and does not get
overriden."""
Model = get_fake_model(
{
"title": LocalizedField(),
"name": models.CharField(max_length=255),
"slug": LocalizedUniqueSlugField(
populate_from="title", immutable=True
),
}
)
obj = Model()
for lang_code, lang_name in settings.LANGUAGES:
obj.slug.set(lang_code, "my value %s" % lang_code)
obj.title.set(lang_code, "my title %s" % lang_code)
obj.save()
for lang_code, lang_name in settings.LANGUAGES:
assert obj.slug.get(lang_code) == "my value %s" % lang_code
@classmethod @classmethod
def test_unique_slug(cls): def test_unique_slug(cls):
"""Tests whether unique slugs are properly generated.""" """Tests whether unique slugs are properly generated."""
@@ -248,10 +297,13 @@ class LocalizedSlugFieldTestCase(TestCase):
"""Tests whether the :see:deconstruct function properly retains options """Tests whether the :see:deconstruct function properly retains options
specified in the constructor.""" specified in the constructor."""
field = LocalizedUniqueSlugField(populate_from="title") field = LocalizedUniqueSlugField(
enabled=False, immutable=True, populate_from="title"
)
_, _, _, kwargs = field.deconstruct() _, _, _, kwargs = field.deconstruct()
assert "populate_from" in kwargs assert not kwargs["enabled"]
assert kwargs["immutable"]
assert kwargs["populate_from"] == field.populate_from assert kwargs["populate_from"] == field.populate_from
@staticmethod @staticmethod

View File

@@ -38,6 +38,17 @@ class LocalizedValueTestCase(TestCase):
for lang_code, _ in settings.LANGUAGES: for lang_code, _ in settings.LANGUAGES:
assert getattr(value, lang_code) is None assert getattr(value, lang_code) is None
@staticmethod
def test_is_empty():
"""Tests whether a newly constructed :see:LocalizedValue without any
content is considered "empty"."""
value = LocalizedValue()
assert value.is_empty()
value.set(settings.LANGUAGE_CODE, "my value")
assert not value.is_empty()
@staticmethod @staticmethod
def test_init_array(): def test_init_array():
"""Tests whether the __init__ function of :see:LocalizedValue properly """Tests whether the __init__ function of :see:LocalizedValue properly