8000 Fix JSONField on Django 2 by aarranz · Pull Request #453 · Wirecloud/wirecloud · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Fix JSONField on Django 2 #453

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 9 additions & 23 deletions src/wirecloud/commons/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@
import json

from django.core.exceptions import ValidationError
from django.db import connection, models

from django.utils.encoding import smart_text
from django.db import models


class JSONField(models.TextField):
Expand All @@ -24,9 +22,8 @@ def get_default(self):
if callable(self.default):
return copy.deepcopy(self.default())
return copy.deepcopy(self.default)
if not self.empty_strings_allowed or (self.null and not connection.features.interprets_empty_strings_as_nulls):
return None
return ""
else:
return None if self.null else {}

def from_db_value(self, value, expression, connection, context):
return self.to_python(value)
Expand All @@ -36,11 +33,10 @@ def to_python(self, value):
Convert the input JSON value into python structures, raises
django.core.exceptions.ValidationError if the data can't be converted.
"""
if self.blank and not value:
return {}
if self.null and value is None:
return None

value = value or '{}'
if isinstance(value, bytes):
value = str(value, 'utf-8')
if isinstance(value, str):
try:
return json.loads(value)
Expand All @@ -49,16 +45,6 @@ def to_python(self, value):
else:
return value

def validate(self, value, model_instance):
"""Check value is a valid JSON string, raise ValidationError on
error."""
if isinstance(value, str):
super(JSONField, self).validate(value, model_instance)
try:
json.loads(value)
except Exception as err:
raise ValidationError(str(err))

def get_prep_value(self, value):
"""Convert value to JSON string before save"""
try:
Expand All @@ -67,9 +53,9 @@ def get_prep_value(self, value):
raise ValidationError(str(err))

def value_to_string(self, obj):
"""Return value from object converted to string properly"""
return smart_text(self.get_prep_value(self._get_val_from_obj(obj)))
"""Converts obj to a string. Used to serialize the value of the field."""
return self.value_from_object(obj)

def value_from_object(self, obj):
"""Return value dumped to string."""
return self.get_prep_value(self._get_val_from_obj(obj))
return self.get_prep_value(super(JSONField, self).value_from_object(obj))
11 changes: 7 additions & 4 deletions src/wirecloud/commons/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
from wirecloud.commons.tests.admin_commands import BaseAdminCommandTestCase, ConvertCommandTestCase, StartprojectCommandTestCase
from wirecloud.commons.tests.basic_views import BasicViewTestCase
from wirecloud.commons.tests.commands import CreateOrganizationCommandTestCase
from wirecloud.commons.tests.fields import JSONFieldTestCase
from wirecloud.commons.tests.search_indexes import QueryParserTestCase, SearchAPITestCase, GroupIndexTestCase, UserIndexTestCase
from wirecloud.commons.tests.template import TemplateUtilsTestCase
from wirecloud.commons.tests.utils import GeneralUtilsTestCase, HTMLCleanupTestCase, WGTTestCase, HTTPUtilsTestCase

__all__ = (
"BaseAdminCommandTestCase", "ConvertCommandTestCase",
"StartprojectCommandTestCase", "BasicViewTestCase",
"BaseAdminCommandTestCase", "BasicViewTestCase", "ConvertCommandTestCase",
"CreateOrganizationCommandTestCase", "GeneralUtilsTestCase",
"GroupIndexTestCase", "HTMLCleanupTestCase", "HTTPUtilsTestCase",
"JSONFieldTestCase", "QueryParserTestCase",
"ResetSearchIndexesCommandTestCase", "SearchAPITestCase",
"TemplateUtilsTestCase", "GeneralUtilsTestCase",
"HTMLCleanupTestCase", "WGTTestCase", "HTTPUtilsTestCase"
"StartprojectCommandTestCase", "TemplateUtilsTestCase", "UserIndexTestCase",
"WGTTestCase"
)
126 changes: 126 additions & 0 deletions src/wirecloud/commons/tests/fields.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# -*- coding: utf-8 -*-

# Copyright (c) 2019 Future Internet Consulting and Development Solutions S.L.

# This file is part of W 10000 irecloud.

# Wirecloud is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# Wirecloud is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.

# You should have received a copy of the GNU Affero General Public License
# along with Wirecloud. If not, see <http://www.gnu.org/licenses/>.

from unittest.mock import patch, Mock

from django.core.exceptions import ValidationError
from django.db.models.fields import NOT_PROVIDED
from django.test import TestCase

from wirecloud.commons.fields import JSONField


# Avoid nose to repeat these tests (they are run through wirecloud/commons/tests/__init__.py)
__test__ = False


class JSONFieldTestCase(TestCase):

tags = ('wirecloud-fields', 'wirecloud-noselenium')

def test_get_default_none(self):
field = JSONField()

default = field.get_default()
self.assertEqual(default, {})

def test_get_default_not_provided(self):
field = JSONField(null=False, default=NOT_PROVIDED)

self.assertEqual(field.get_default(), {})

def test_get_default_not_provided_null(self):
field = JSONField(null=True, default=NOT_PROVIDED)

self.assertEqual(field.get_default(), None)

def test_get_default_static_value(self):
obj = {"h": "w"}
field = JSONField(default=obj)

default = field.get_default()
self.assertEqual(default, obj)
default["h"] = "a"
self.assertNotEqual(default, obj)

def test_get_default_callable(self):
obj = {"h": "w"}
field = JSONField(default=lambda: obj)

default = field.get_default()
self.assertEqual(default, obj)
default["h"] = "a"
self.assertNotEqual(default, obj)

def test_from_db_value(self):
field = JSONField()
field.to_python = Mock()
value = '{"a": "b"}'

self.assertEqual(field.from_db_value(value, None, None, None), field.to_python(value))

field.to_python.assert_called_with(value)

def test_to_python_null_none(self):
field = JSONField(null=True)
self.assertEqual(field.to_python(None), None)

def test_to_python_none(self):
field = JSONField(null=False)
self.assertEqual(field.to_python(None), {})

def test_to_python_str(self):
field = JSONField()
obj = {"a": "c"}
self.assertEqual(field.to_python('{"a": "c"}'), obj)

def test_to_python_str_exception(self):
field = JSONField()
self.assertRaises(ValidationError, field.to_python, 'invalid json')

def test_to_python_json(self):
field = JSONField()
obj = {"a": "c"}
self.assertEqual(field.to_python(obj), obj)

def test_get_prep_value_exception(self):
field = JSONField()
self.assertRaises(ValidationError, field.get_prep_value, set())

@patch("wirecloud.commons.fields.json")
def test_implements_value_from_object(self, json):
field = JSONField()
field.set_attributes_from_name("myfield")
obj = Mock(myfield={"a": "b"})
json.dumps.return_value = "serialized json"

self.assertEqual(field.value_from_object(obj), "serialized json")

json.dumps.assert_called_once_with({"a": "b"})

@patch("wirecloud.commons.fields.json")
def test_implements_value_to_string(self, json):
field = JSONField()
field.set_attributes_from_name("myfield")
obj = Mock(myfield={"a": "b"})
json.dumps.return_value = "serialized json"

self.assertEqual(field.value_to_string(obj), "serialized json")

json.dumps.assert_called_once_with({"a": "b"})
0