Opened 8 months ago

Last modified 8 months ago

#29145 new Cleanup/optimization

Allow CIText values to be compared as the database would compare them (case-insensitively)

Reported by: Дилян Палаузов Owned by: nobody
Component: contrib.postgres Version: 2.0
Severity: Normal Keywords:
Cc: Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Tim Graham)

For comparing two model instances on equality one can iterate over all fields in the instance and compare the fields for equality, without querying the database. This does not work for django.contrib.postgres.fields.citext.CIText, where "a" is equal to "A".

Under the premise that python and postgresql use the same collation, tweak the system to compare two citext-fields in a case-insensitive manner for equality, without touching the database (as it is done for all other fields).

Attaching to each citext-field returned from the model an __eq__ doing .lower() could help.

Change History (4)

comment:1 Changed 8 months ago by Simon Charette

Model equality (Model.__eq__) is determined by the type(instance), instance.pk tuple and not by the value of its other fields. That makes Foo(id=1, field='bar') == Foo(id=1, field='baz').

Are you talking about your own version of model equality?

comment:2 Changed 8 months ago by Дилян Палаузов

I am not talking about model equality, but about a field equality.

The use case is a list of models-instances without IDs and the list can contain the same instance several times. I want to send a single SELECT and assign IDs to all objects in the list.

However, the list can contains twice the same object while the SELECT will return the object only once. Moreover the objects are returned in any order. So the result of SELECT needs to be matched with the objects from the list, comparing field-by-field of what was requested if it matches the currently processed row. For this matching to work universally with == in case CICharField fields 'a' == 'A' must also match.

comment:3 Changed 8 months ago by Jon Dufresne

A potentially related ticket is #28405. If CIText values had an __eq__, that might solve the ModelFormSet.validate_unique() issue.

comment:4 Changed 8 months ago by Tim Graham

Component: Uncategorizedcontrib.postgres
Description: modified (diff)
Summary: CIText and __eq__Allow CIText values to be compared as the database would compare them (case-insensitively)
Triage Stage: UnreviewedAccepted
Type: UncategorizedCleanup/optimization

Tentatively accepting, although I'm not certain about the complexity this will require. I'm thinking that whenever a value is assigned to a CI field, that value will be have to wrapped in a str subclass that implements __eq__() to do the case-insensitive comparison. I guess a perfect implementation that considers database collation, for example, may not be feasible.

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