Created abstract model to take care of default values

This commit is contained in:
Swen Kooij 2016-10-24 11:50:21 +03:00
parent cdaacdfac5
commit c081b0431d
8 changed files with 136 additions and 75 deletions

View File

@ -61,15 +61,15 @@ Usage
Preparation Preparation
^^^^^^^^^^^ ^^^^^^^^^^^
Declare fields on your model as ``LocalizedField``: Inherit your model from ``LocalizedModel`` and declare fields on your model as ``LocalizedField``:
.. code-block:: python .. code-block:: python
from django.db import models from localized_fields.models import LocalizedModel
from localized_fields.fields import LocalizedField from localized_fields.fields import LocalizedField
class MyModel(models.Model): class MyModel(LocalizedModel):
title = LocalizedField() title = LocalizedField()
@ -160,11 +160,11 @@ Besides ``LocalizedField``, there's also:
.. code-block:: python .. code-block:: python
from django.db import models from localized_fields.models import LocalizedModel
from localized_fields.fields import (LocalizedField, from localized_fields.fields import (LocalizedField,
LocalizedAutoSlugField) LocalizedAutoSlugField)
class MyModel(models.Model): class MyModel(LocalizedModel):
title = LocalizedField() title = LocalizedField()
slug = LocalizedAutoSlugField(populate_from='title') slug = LocalizedAutoSlugField(populate_from='title')
@ -176,10 +176,10 @@ Besides ``LocalizedField``, there's also:
.. code-block:: python .. code-block:: python
from django.db import models from localized_fields.models import LocalizedModel
from localized_fields.fields import (LocalizedField, from localized_fields.fields import (LocalizedField,
LocalizedBleachField) LocalizedBleachField)
class MyModel(models.Model): class MyModel(LocalizedModel):
title = LocalizedField() title = LocalizedField()
description = LocalizedBleachField() description = LocalizedBleachField()

View File

@ -1,8 +1,10 @@
from typing import Callable from typing import Callable
from django import forms
from django.conf import settings from django.conf import settings
from django.utils.text import slugify from django.utils.text import slugify
from ..forms import LocalizedFieldForm
from .localized_field import LocalizedField from .localized_field import LocalizedField
from .localized_value import LocalizedValue from .localized_value import LocalizedValue
@ -28,6 +30,24 @@ class LocalizedAutoSlugField(LocalizedField):
return name, path, args, kwargs return name, path, args, kwargs
def formfield(self, **kwargs):
"""Gets the form field associated with this field.
Because this is a slug field which is automatically
populated, it should be hidden from the form.
"""
defaults = {
'form_class': LocalizedFieldForm
}
defaults.update(kwargs)
form_field = super().formfield(**defaults)
form_field.widget = forms.HiddenInput()
return form_field
def pre_save(self, instance, add: bool): def pre_save(self, instance, add: bool):
"""Ran just before the model is saved, allows us to built """Ran just before the model is saved, allows us to built
the slug. the slug.

View File

@ -17,9 +17,6 @@ class LocalizedField(HStoreField):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
"""Initializes a new instance of :see:LocalizedValue.""" """Initializes a new instance of :see:LocalizedValue."""
if 'default' not in kwargs:
kwargs['default'] = LocalizedValue()
super(LocalizedField, self).__init__(*args, **kwargs) super(LocalizedField, self).__init__(*args, **kwargs)
@staticmethod @staticmethod

View File

@ -0,0 +1,29 @@
from django.db import models
from .fields import LocalizedField, LocalizedValue
class LocalizedModel(models.Model):
"""A model that contains localized fields."""
class Meta:
abstract = True
def __init__(self, *args, **kwargs):
"""Initializes a new instance of :see:LocalizedModel.
Here we set all the fields that are of :see:LocalizedField
to an instance of :see:LocalizedValue in case they are none
so that the user doesn't explicitely have to do so."""
super(LocalizedModel, self).__init__(*args, **kwargs)
for field in self._meta.get_fields():
if not isinstance(field, LocalizedField):
continue
value = getattr(self, field.name, None)
if not isinstance(value, LocalizedValue):
value = LocalizedValue()
setattr(self, field.name, value)

47
tests/fake_model.py Normal file
View File

@ -0,0 +1,47 @@
from django.contrib.postgres.operations import HStoreExtension
from django.db import connection, migrations
from django.db.migrations.executor import MigrationExecutor
from localized_fields.fields import LocalizedAutoSlugField, LocalizedField
from localized_fields.models import LocalizedModel
MODEL = None
def get_fake_model():
"""Creates a fake model to use during unit tests."""
global MODEL
if MODEL:
return MODEL
class TestModel(LocalizedModel):
"""Model used for testing the :see:LocalizedAutoSlugField."""
app_label = 'localized_fields'
title = LocalizedField()
slug = LocalizedAutoSlugField(populate_from='title')
class TestProject:
def clone(self, *args, **kwargs):
return self
class TestMigration(migrations.Migration):
operations = [
HStoreExtension()
]
with connection.schema_editor() as schema_editor:
migration_executor = MigrationExecutor(schema_editor.connection)
migration_executor.apply_migration(
TestProject(),
TestMigration('eh', 'localized_fields')
)
schema_editor.create_model(TestModel)
MODEL = TestModel
return MODEL

View File

@ -1,12 +1,10 @@
from django.conf import settings from django.conf import settings
from django.contrib.postgres.operations import HStoreExtension
from django.db import connection, migrations, models
from django.db.migrations.executor import MigrationExecutor
from django.test import TestCase from django.test import TestCase
from django.utils.text import slugify from django.utils.text import slugify
from localized_fields.fields import (LocalizedAutoSlugField, LocalizedField, from localized_fields.fields import LocalizedAutoSlugField
LocalizedValue)
from .fake_model import get_fake_model
class LocalizedAutoSlugFieldTestCase(TestCase): class LocalizedAutoSlugFieldTestCase(TestCase):
@ -20,39 +18,7 @@ class LocalizedAutoSlugFieldTestCase(TestCase):
super(LocalizedAutoSlugFieldTestCase, cls).setUpClass() super(LocalizedAutoSlugFieldTestCase, cls).setUpClass()
class TestModel(models.Model): cls.TestModel = get_fake_model()
"""Model used for testing the :see:LocalizedAutoSlugField."""
app_label = 'localized_fields'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.title = self.title or LocalizedValue()
self.slug = self.slug or LocalizedValue()
title = LocalizedField()
slug = LocalizedAutoSlugField(populate_from='title')
class TestProject:
def clone(self, *args, **kwargs):
return self
class TestMigration(migrations.Migration):
operations = [
HStoreExtension()
]
with connection.schema_editor() as schema_editor:
migration_executor = MigrationExecutor(schema_editor.connection)
migration_executor.apply_migration(
TestProject(),
TestMigration('eh', 'localized_fields')
)
schema_editor.create_model(TestModel)
cls.TestModel = TestModel
def test_populate(self): def test_populate(self):
"""Tests whether the :see:LocalizedAutoSlugField's """Tests whether the :see:LocalizedAutoSlugField's

View File

@ -235,33 +235,6 @@ class LocalizedFieldTestCase(TestCase):
assert not LocalizedField().clean(None) assert not LocalizedField().clean(None)
assert not LocalizedField().clean(['huh']) assert not LocalizedField().clean(['huh'])
@staticmethod
def test_default_value():
"""Tests whether the default value is a :see:LocalizedValue
instance."""
field = LocalizedField()
assert field.default
assert isinstance(field.default, LocalizedValue)
for lang_code, _ in settings.LANGUAGES:
assert not field.default.get(lang_code)
@staticmethod
def test_default_value_override():
"""Tests whether the default value of a field
can correctly be overriden."""
default_value = LocalizedValue(get_init_values())
field = LocalizedField(default=default_value)
assert field.default
assert isinstance(field.default, LocalizedValue)
for lang_code, _ in settings.LANGUAGES:
assert default_value.get(lang_code) == field.default.get(lang_code)
@staticmethod @staticmethod
def test_formfield(): def test_formfield():
"""Tests whether the :see:formfield function """Tests whether the :see:formfield function

View File

@ -0,0 +1,29 @@
from django.test import TestCase
from localized_fields.fields import LocalizedValue
from .fake_model import get_fake_model
class LocalizedModelTestCase(TestCase):
"""Tests whether the :see:LocalizedModel class."""
TestModel = None
@classmethod
def setUpClass(cls):
"""Creates the test model in the database."""
super(LocalizedModelTestCase, cls).setUpClass()
cls.TestModel = get_fake_model()
@classmethod
def test_defaults(cls):
"""Tests whether all :see:LocalizedField
fields are assigned an empty :see:LocalizedValue
instance when the model is instanitiated."""
obj = cls.TestModel()
assert isinstance(obj.title, LocalizedValue)