Opened 14 months ago

Closed 14 months ago

Last modified 12 months ago

#34397 closed Bug (invalid)

Subclasses of JSONField call `get_prep_value` with field as value

Reported by: pheki Owned by: nobody
Component: Database layer (models, ORM) Version: 3.2
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Hi!

Let's say I have a class called PhoneNumber:

@dataclass
class PhoneNumber:
    country_iso_code: str
    national_number: int

I create a field I use to use PhoneNumber in my database:

class PhoneNumberField(JSONField):
    def get_prep_value(
        self, value: Optional[PhoneNumber]
    ) -> Optional[JsonAdapter]:
        if isinstance(value, PhoneNumber):
            return JsonAdapter(dataclasses.asdict(value), encoder=CustomJSONEncoder)
        elif value is None and self.null:
            return None
        else:
            raise Exception("Fetching phone number with unexpected value")

    # Similar from_db_value ommited
    def from_db_value(...):
        ...

The problem is that when I do a KeyTextTransform to get a field, it will call get_prep_value with that field and AFAIK there's no way to know which field is it getting. For from_db_value the same happens, but it's fine as you can inspect the expression column. Example:

User.objects.annotate(
    national_number=KeyTextTransform("national_number", "phone_number")
).filter(
    national_number="12345678"
)[0]

Will call field.get_prep_value("12345678"), forcing the only way to make it work correctly to silently ignore unexpected types. This didn't happen on django 2.2 for django.contrib.postgres.fields.jsonb.JSONField.

Change History (2)

comment:1 by Mariusz Felisiak, 14 months ago

Resolution: invalid
Status: newclosed

If I understand correctly, you have a custom JSONField with your own implementation of get_prep_value(). JSONField no longer use get_prep_value() in Django 4.2+ (see 5c23d9f0c32f166c81ecb6f3f01d5077a6084318) so you check if it works for you, however, even if it doesn't, you can always implement your own expression and use it instead of KeyTextTransform.

comment:2 by Julie Rymer, 12 months ago

This issue was filed for django 3.2 so the recent change in JSONField behaviour has no impact.
However, from what I understand @pheki, wants two different behaviour depending on the field it is called on. For that the solution is to create two custom classes, each implementing the behaviour that you want and assign it to the corresponding field.

Note: See TracTickets for help on using tickets.
Back to Top