models: Improve conversion of CustomProfileField values.

These values are currently either a string already or a List[int]. We
should do the conversion in
do_update_user_custom_profile_data_if_changed properly: if the value is
already a string, it can be used directly - if it's not, orjson.dumps is
a more future-proof way of converting than str(). Using orjson.dumps
here also allows us to change the converter of the USER type
CustomProfileField to orjson.loads, which is nicer to have than
ast.literal_eval.
While orjson.dumps() and str() give the same output when
given the special case of List[int],
ast.literal_eval was previously used due to orjson.loads not being
a good inverse function to str in general. That gets straightened out
now.
This commit is contained in:
Mateusz Mandera
2021-09-19 20:11:34 +02:00
committed by Tim Abbott
parent cacff28578
commit 491f763f4e
2 changed files with 14 additions and 7 deletions

View File

@@ -7746,17 +7746,24 @@ def do_update_user_custom_profile_data_if_changed(
user_profile=user_profile, field_id=custom_profile_field["id"]
)
if not created and field_value.value == str(custom_profile_field["value"]):
# field_value.value is a TextField() so we need to have field["value"]
# in string form to correctly make comparisons and assignments.
if isinstance(custom_profile_field["value"], str):
custom_profile_field_value_string = custom_profile_field["value"]
else:
custom_profile_field_value_string = orjson.dumps(
custom_profile_field["value"]
).decode()
if not created and field_value.value == custom_profile_field_value_string:
# If the field value isn't actually being changed to a different one,
# we have nothing to do here for this field.
# Note: field_value.value is a TextField() so we need to cast field['value']
# to a string for the comparison in this if.
continue
field_value.value = str(custom_profile_field["value"])
field_value.value = custom_profile_field_value_string
if field_value.field.is_renderable():
field_value.rendered_value = render_stream_description(
str(custom_profile_field["value"])
custom_profile_field_value_string
)
field_value.save(update_fields=["value", "rendered_value"])
else:

View File

@@ -1,4 +1,3 @@
import ast
import datetime
import re
import secrets
@@ -20,6 +19,7 @@ from typing import (
)
import django.contrib.auth
import orjson
from bitfield import BitField
from bitfield.types import BitHandler
from django.conf import settings
@@ -3878,7 +3878,7 @@ class CustomProfileField(models.Model):
(SELECT, gettext_lazy("List of options"), validate_select_field, str, "SELECT"),
]
USER_FIELD_TYPE_DATA: List[UserFieldElement] = [
(USER, gettext_lazy("Person picker"), check_valid_user_ids, ast.literal_eval, "USER"),
(USER, gettext_lazy("Person picker"), check_valid_user_ids, orjson.loads, "USER"),
]
SELECT_FIELD_VALIDATORS: Dict[int, ExtendedValidator] = {