Opened 3 years ago

Last modified 14 months ago

#28053 assigned New feature

Allow fields to specify arbitrary indexes via db_index=Index()

Reported by: Marc Tamlyn Owned by: Can Sarıgöl
Component: Database layer (models, ORM) Version: master
Severity: Normal Keywords: indexes migrations
Cc: Markus Holtermann Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: yes
Easy pickings: no UI/UX: no

Description

Expand Field.db_index to allow explicitly setting an index.

Syntax would look something like:

HStoreField(db_index=GinIndex())

Changes needed:

  • Indexes won't necessarily receive fields initially.
  • Fields are responsible for their own indexes. This is tackled here and has implications for #27859, _like indexes on Postgres, and other situations where we customise the indexes. It is possible, but I'm not sure, that Field.get_indexes() could also handle unique conditions, but I think it's better kept separately as not all databases consider uniqueness to be an index.
  • Change to SchemaEditor.alter_field so it receives the to_model, so that the Index can resolve the correct column names. This is extra important for db_index being a functional index (see #26167), although that's not currently supported in the current data.

Change History (8)

comment:1 Changed 3 years ago by Markus Holtermann

Needs documentation: set
Needs tests: set
Triage Stage: UnreviewedAccepted

comment:2 Changed 3 years ago by Tim Graham

Type: UncategorizedNew feature

WIP PR

comment:3 Changed 16 months ago by Can Sarıgöl

Owner: changed from nobody to Can Sarıgöl
Patch needs improvement: unset
Status: newassigned

new WP PR

comment:4 Changed 16 months ago by Can Sarıgöl

Version: 1.11master

comment:5 Changed 15 months ago by Can Sarıgöl

Needs documentation: unset
Needs tests: unset

comment:6 Changed 15 months ago by felixxm

Patch needs improvement: set

comment:7 Changed 15 months ago by Markus Holtermann

I had a chat with felixxm discussing the usefulness of this feature.

The initial idea behind this feature, as far as I can reconstruct from memory, came from the requirement that I wanted to have a custom index on a field by default, because I didn't want to tell users to add a specific index to Meta.indexes. The naïve approach Marc and I agreed upon back in the days was about this:

  • A field has a default_index_class or default_index property/attribute or whatnot. When a field has db_index=True, this index definition would be used.
  • Now, a custom field that would want to require an index, could reject db_index as an argument in __init__ and set it to True all the time.
  • A user could, however, may would like to be able to make adjustments to the index that's defined by the field. Thus, passing their own index definition in place of db_index (and not have the field reject the argument.

This change would also allow to dynamically construct an index based on the other arguments passed to __ini__:

class MyField(CharField):
    def __init__(self, arg1: str, arg2: int, **kwargs):
        db_index = kwargs.pop("db_index", None)
        if db_index is None:
            db_index = MyIndexClass(arg1, math.pi * arg2)
        super().__init__(db_index=db_index, **kwargs)

class MyModel(models.Model):
    field1 = MyField()
    field2 = MyField(db_index=Index(name="foo"))

The key, I believe, is that the implementation of default_index_class or default_index or however the API might look like, would be a prerequisite for this ticket.

Last edited 15 months ago by Markus Holtermann (previous) (diff)

comment:8 Changed 14 months ago by Can Sarıgöl

Hi, thanks for your detailed explanation. Firstly, I wanted to be sure to understand you. Because of that I've issued a commit. I'm using _get_index_type_kwargs to getting kwargs for _create_index_sql. I applied it in this part. what do you think?

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