Refs #28577 -- Added check for HStoreField to prevent mutable default.

This commit is contained in:
Tim Graham 2018-04-03 11:12:56 -04:00 committed by GitHub
parent 167d98528a
commit 4f7467b690
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 35 additions and 4 deletions

View File

@ -6,15 +6,18 @@ from django.core import exceptions
from django.db.models import Field, TextField, Transform from django.db.models import Field, TextField, Transform
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from .mixins import CheckFieldDefaultMixin
__all__ = ['HStoreField'] __all__ = ['HStoreField']
class HStoreField(Field): class HStoreField(CheckFieldDefaultMixin, Field):
empty_strings_allowed = False empty_strings_allowed = False
description = _('Map of strings to strings/nulls') description = _('Map of strings to strings/nulls')
default_error_messages = { default_error_messages = {
'not_a_string': _('The value of "%(key)s" is not a string or null.'), 'not_a_string': _('The value of "%(key)s" is not a string or null.'),
} }
_default_hint = ('dict', '{}')
def db_type(self, connection): def db_type(self, connection):
return 'hstore' return 'hstore'

View File

@ -1,11 +1,11 @@
import json import json
from django.core import exceptions, serializers from django.core import checks, exceptions, serializers
from django.forms import Form from django.forms import Form
from django.test.utils import modify_settings from django.test.utils import isolate_apps, modify_settings
from . import PostgreSQLTestCase from . import PostgreSQLTestCase
from .models import HStoreModel from .models import HStoreModel, PostgreSQLModel
try: try:
from django.contrib.postgres import forms from django.contrib.postgres import forms
@ -190,6 +190,34 @@ class TestQuerying(HStoreTestCase):
) )
@isolate_apps('postgres_tests')
class TestChecks(PostgreSQLTestCase):
def test_invalid_default(self):
class MyModel(PostgreSQLModel):
field = HStoreField(default={})
model = MyModel()
self.assertEqual(model.check(), [
checks.Warning(
msg=(
"HStoreField default should be a callable instead of an "
"instance so that it's not shared between all field "
"instances."
),
hint='Use a callable instead, e.g., use `dict` instead of `{}`.',
obj=MyModel._meta.get_field('field'),
id='postgres.E003',
)
])
def test_valid_default(self):
class MyModel(PostgreSQLModel):
field = HStoreField(default=dict)
self.assertEqual(MyModel().check(), [])
class TestSerialization(HStoreTestCase): class TestSerialization(HStoreTestCase):
test_data = json.dumps([{ test_data = json.dumps([{
'model': 'postgres_tests.hstoremodel', 'model': 'postgres_tests.hstoremodel',