Opened 9 years ago

Closed 6 months ago

Last modified 6 months ago

#24561 closed New feature (fixed)

Allow model field choices to accept callables.

Reported by: Christopher Grebs Owned by: Natalia Bidart
Component: Database layer (models, ORM) Version: dev
Severity: Normal Keywords:
Cc: Ülgen Sarıkavak Triage Stage: Ready for checkin
Has patch: yes Needs documentation: yes
Needs tests: no Patch needs improvement: yes
Easy pickings: no UI/UX: no

Description

Django 1.8 introduced the ability to pass a callable for 'choices' but it seems the check-framework was not adapted to this.

Pull Request: https://github.com/django/django/pull/4434/

Change History (13)

comment:1 by Tim Graham, 9 years ago

Component: Core (System checks)Database layer (models, ORM)
Patch needs improvement: set
Summary: Allow 'choices'-check to work for callables.Allow model field choices to accept callables.
Triage Stage: UnreviewedAccepted
Type: BugNew feature
Version: 1.8master

It was added for django.forms.ChoiceField, but not model field choices. It might be a reasonable feature request, but it needs to be implemented. It might cause some difficulty in migrations, but I will accept the ticket if someone wants to investigate the possibility.

comment:2 by Christopher Grebs, 9 years ago

Oh, then I misread the feature. I'll try to update the patch to port this to the model field choices as well.

comment:3 by Mariusz Felisiak, 7 years ago

Has patch: unset
Patch needs improvement: unset

See also discussion in #28033.

comment:4 by Sergey Fedoseev, 6 years ago

Cc: Sergey Fedoseev added

comment:5 by Natalia Bidart, 7 months ago

While reviewing/working on #31262, we noticed that the choices refactoring that is being proposed in PR #16943 will help considerably to this ticket. Besides what is discussed in that PR, the following diff should allow model field's callable choices to be serialized as functions (similar to callable default or form ChoiceField's choices). Thanks Mariusz for the idea.

  • django/db/migrations/serializer.py

    diff --git a/django/db/migrations/serializer.py b/django/db/migrations/serializer.py
    index 06657ebaab..2c57a21b7c 100644
    a b from django.conf import SettingsReference  
    1515from django.db import models
    1616from django.db.migrations.operations.base import Operation
    1717from django.db.migrations.utils import COMPILED_REGEX_TYPE, RegexObject
     18from django.utils.choices import CallableChoiceIterator
    1819from django.utils.functional import LazyObject, Promise
    1920from django.utils.version import PY311, get_docs_version
    2021
    class UUIDSerializer(BaseSerializer):  
    329330        return "uuid.%s" % repr(self.value), {"import uuid"}
    330331
    331332
     333class CallableChoiceIteratorSerializer(BaseSerializer):
     334
     335    def serialize(self):
     336        return FunctionTypeSerializer(self.value.choices_func).serialize()
     337
     338
    332339class Serializer:
    333340    _registry = {
    334341        # Some of these are order-dependent.
    class Serializer:  
    351358            types.BuiltinFunctionType,
    352359            types.MethodType,
    353360        ): FunctionTypeSerializer,
     361        CallableChoiceIterator: CallableChoiceIteratorSerializer,
    354362        collections.abc.Iterable: IterableSerializer,
    355363        (COMPILED_REGEX_TYPE, RegexObject): RegexSerializer,
    356364        uuid.UUID: UUIDSerializer,
  • django/db/models/fields/__init__.py

    diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py
    index 7e56bddffe..6600031cf6 100644
    a b class Field(RegisterLookupMixin):  
    315315        if not self.choices:
    316316            return []
    317317
    318         if not is_iterable(self.choices) or isinstance(
    319             self.choices, (str, CallableChoiceIterator)
    320         ):
     318        if not is_iterable(self.choices) or isinstance(self.choices, str):
    321319            return [
    322320                checks.Error(
    323321                    "'choices' must be a mapping (e.g. a dictionary) or an iterable "
Last edited 7 months ago by Natalia Bidart (previous) (diff)

comment:6 by Sergey Fedoseev, 7 months ago

Cc: Sergey Fedoseev removed

comment:7 by Natalia Bidart, 7 months ago

Owner: changed from nobody to Natalia Bidart
Status: newassigned

comment:8 by Natalia Bidart, 7 months ago

Has patch: set

comment:9 by Natalia Bidart, 7 months ago

Needs documentation: set
Patch needs improvement: set

Setting as patch needs improvement because I'd like to cover a few use cases with the community first.

comment:10 by Ülgen Sarıkavak, 7 months ago

Cc: Ülgen Sarıkavak added

comment:12 by Natalia <124304+nessita@…>, 6 months ago

Resolution: fixed
Status: assignedclosed

In 691f70c:

Fixed #24561 -- Added support for callables on model fields' choices.

comment:13 by Natalia Bidart, 6 months ago

Triage Stage: AcceptedReady for checkin
Note: See TracTickets for help on using tickets.
Back to Top