Skip to content

Commit 7b6b3c0

Browse files
authored
Merge pull request #73 from Aristotle-Metadata-Enterprises/fix-custom-prep-save
added support for custom get_db_prep_save
2 parents c6eda44 + 479c49e commit 7b6b3c0

File tree

7 files changed

+92
-3
lines changed

7 files changed

+92
-3
lines changed

garnett/fields.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,18 @@ def get_prep_value(self, value):
114114
return value
115115
return super().get_prep_value(value)
116116

117+
def get_db_prep_save(self, value, connection):
118+
"""This ensures that any custom get_db_prep_save() method in self.field can be triggered"""
119+
if hasattr(value, "items"):
120+
value = {
121+
lang_code: self.field.get_db_prep_save(text, connection)
122+
for lang_code, text in value.items()
123+
}
124+
elif type(value) == str:
125+
value = self.field.get_db_prep_save(value, connection)
126+
return value
127+
return super().get_db_prep_save(value, connection)
128+
117129
def from_db_value(self, value, expression, connection):
118130
value = super().from_db_value(value, expression, connection)
119131
if hasattr(self.field, "from_db_value"):

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "django-garnett"
3-
version = "0.4.7"
3+
version = "0.4.8"
44
description = "Simple translatable Django fields"
55
authors = ["Aristotle Metadata Enterprises"]
66
license = "BSD-3-Clause"

tests/library_app/migrations/0001_initial.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ class Migration(migrations.Migration):
4949
),
5050
),
5151
("category", models.JSONField(blank=True, null=True)),
52+
("other_info", library_app.models.CustomTestingField(blank=True, default=''))
5253
],
5354
),
5455
migrations.CreateModel(

tests/library_app/migrations/0002_make_translatable.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88

99
model_fields = {
10-
"book": ["title", "description"],
10+
"book": ["title", "description", "other_info"],
1111
}
1212

1313

@@ -41,5 +41,15 @@ class Migration(migrations.Migration):
4141
help_text="The name for a book. (Multilingal field)",
4242
),
4343
),
44+
migrations.AlterField(
45+
model_name="book",
46+
name="other_info",
47+
field=garnett.fields.TranslatedField(
48+
library_app.models.CustomTestingField(
49+
blank=True, default=''
50+
),
51+
fallback=None,
52+
),
53+
),
4454
step_2_safe_prepare_translations("library_app", model_fields),
4555
]

tests/library_app/models.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,43 @@
77
from garnett.utils import get_languages, get_current_language
88

99

10+
RANDOM_STR = "f6e56ce9-cc87-45ac-8a19-8c34136e6f52"
11+
BLEACH_STR = "string to be replace"
12+
13+
14+
class CustomTestingField(models.TextField):
15+
def get_db_prep_save(self, value, connection):
16+
"""
17+
Note: If there is data migration when migrating to TranslatedField, the manually added
18+
step_1_safe_encode_content() function in the migration file will base64 encode the value in the field
19+
before get_db_prep_save is called.
20+
21+
For example:
22+
old value = "this is a book"
23+
new value = '{"en": "dGhpcyBpcyBhIGJvb2s="}'
24+
25+
The new value is then parse to the get_db_prep_save() function.
26+
If custom get_db_prep_save() function is used you will need to make sure that the custom get_db_prep_save() function is
27+
not modifying the input value.
28+
29+
Some examples,
30+
1. if the custom get_db_prep_save() function append a fix str to all input value:
31+
input value = '{"en": "dGhpcyBpcyBhIGJvb2s="}'
32+
return value = '{"en": "dGhpcyBpcyBhIGJvb2s="}1234567'
33+
this would raise "django.db.utils.DataError: invalid input syntax for type json" because the return value
34+
from the custom get_db_prep_save() function is not valid json
35+
36+
2. if the custom get_db_prep_save() function bleach certain substring (e.g dGhpcy) on the input value:
37+
input value = '{"en": "dGhpcyBpcyBhIGJvb2s="}'
38+
return value = '{"en": "BpcyBhIGJvb2s="}'
39+
this would modify the base64 value and decoding the modfied base64 value would return unexpected result
40+
"""
41+
if value is None:
42+
return super().get_db_prep_save(value, connection)
43+
bleached_value = value.replace(BLEACH_STR, RANDOM_STR)
44+
return super().get_db_prep_save(bleached_value, connection)
45+
46+
1047
def validate_length(value):
1148
if len(value) < 3:
1249
raise ValidationError(_("Title is too short"))
@@ -70,6 +107,8 @@ class Book(models.Model):
70107

71108
category = models.JSONField(blank=True, null=True)
72109

110+
other_info = fields.Translated(CustomTestingField(blank=True, default=""))
111+
73112
def get_absolute_url(self):
74113
return f"/book/{self.pk}"
75114

tests/tests/test_field.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import garnett.exceptions
66
from garnett.context import set_field_language
77
from garnett.fields import TranslatedField
8+
from library_app.models import Book, RANDOM_STR, BLEACH_STR
89

910
book_data = dict(
1011
title={
@@ -50,3 +51,29 @@ def test_validate_bad_value_type(self):
5051
with set_field_language("fr"), self.assertRaises(ValidationError) as err:
5152
self.field.clean(value, None)
5253
self.assertEqual(err.exception, 'Invalid value for language "en"')
54+
55+
def test_trigger_get_db_prep_save(self):
56+
content = "This is a book and this string to be replace"
57+
Book.objects.create(
58+
title={
59+
"en": "A book",
60+
"de": "Eine Gut Buch",
61+
},
62+
author="No one",
63+
description="No description",
64+
category={"dewey": 123},
65+
number_of_pages=100,
66+
other_info=content,
67+
)
68+
# Expect only one object is created
69+
books = Book.objects.all()
70+
self.assertEqual(len(books), 1)
71+
72+
# Expect CustomTestingField to be bleached
73+
book = books[0]
74+
self.assertEqual(book.other_info, content.replace(BLEACH_STR, RANDOM_STR))
75+
76+
# Expect other fields will not be bleached
77+
self.assertNotIn(RANDOM_STR, book.title)
78+
self.assertNotIn(RANDOM_STR, book.author)
79+
self.assertNotIn(RANDOM_STR, book.description)

tox.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,4 @@ commands =
2222
poetry config virtualenvs.create false
2323
poetry install
2424
pip install "django~={env:DJANGO_VERSION}"
25-
coverage run --append --source=. ./tests/manage.py test tests
25+
coverage run --append --source=. ./tests/manage.py test tests -v 2

0 commit comments

Comments
 (0)