Динамический выбор поля модели Django, который вызывает API

#django

#django

Вопрос:

Скажем, у меня есть следующая модель:

 class DenyList(models.Model):
    vm_id = models.CharField(max_length=25)
  

Я хочу добавить варианты в vm_id поле, однако варианты являются динамическими через API внешней системы реестра виртуальной машины.

итак, я сделал это следующим образом:

 class MachineChoices(object):

    def get_vms(self):
        if 'makemigrations' in sys.argv or 'migrate' in sys.argv:
            return []
        # calls api, optionally cache, return the vms

    def __iter__(self):
        yield from self.get_vms()


class DenyList(models.Model):
    vm_id = models.CharField(max_length=25, choices=MachineChoices())
  

Вышесказанное работает так:

  1. При создании миграций он не будет вызывать API для установки всех параметров в файле миграции
  2. Он управляется из серверной части, поэтому он работает со всеми формами модели, как в django admin.
  3. Администратор Django отображает метку вместо необработанного значения в отображении списка ( MachineChoices для эффективности требуется реализованное кэширование)

Я не чувствую, что это элегантно, поскольку это связано с хакерством, чтобы обмануть django, особенно во время миграции.

Я знаю, что альтернативой является использование библиотек автозаполнения, но мне нужно настроить с помощью django forms.

Итак, есть ли лучшие способы сделать это?

Комментарии:

1. вы можете использовать __init__ метод form для инициализации выбора.

Ответ №1:

Вместо этого вы можете установить choices значение None (или пустой список) AppConfig .

myapp/apps.py:

 import sys

from django.apps import AppConfig


class MyAppConfig(AppConfig):
    name = 'myapp'

    def ready(self):
        if 'makemigrations' in sys.argv or 'migrate' in sys.argv:
            from . import models
            models.Company.street_num.field.choices = None
  

Если вы не хотите настраивать каждое поле модели специально:

 if 'makemigrations' in sys.argv or 'migrate' in sys.argv:
    for model in self.models.values():
        for field in model._meta.fields:
            field.choices = None
  

Не забудьте включить свой AppConfig in INSTALLED_APPS .

mysite/settings.py:

 INSTALLED_APPS = [
    # ...
    'myapp.apps.MyAppConfig',
]