Модели Django (динамические?)

#python #django #django-rest-framework

#python #django #django-rest-framework

Вопрос:

Я только начинаю сайт Django;

Я решил использовать модель (с базой данных SQLite), которая обладает следующими свойствами:

 class Flow(models.Model):
    owner = models.ForeignKey(User, on_delete=models.CASCADE,
                              verbose_name="Owner", default="ADMIN")

    source = models.CharField(default='HTTP', choices=SOURCE_CHOICES, editable=True, max_length=12)
    name = models.CharField(max_length=50, default=" ")
    date = models.DateTimeField(verbose_name="Creation date")
  

Я хочу добавить другие поля в эту модель в зависимости от значения исходного поля.

Например, если выбрано исходное поле: «Файл». Я создам дополнительное поле (например, имя файла, каталог файла …) Если выбрано значение «Http», я создам URL-адрес поля. Таким образом, в зависимости от исходного поля у меня будут разные поля и типы.

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

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

1. Если вы действительно хотите погрузиться в динамические модели, то вот ссылка code.djangoproject.com/wiki/DynamicModels . Пожалуйста, проверьте, помогает ли это.

2. Вы, вероятно, скорее хотите создать все эти поля по умолчанию и разрешить им быть нулевыми; или вы должны создать вторую модель, которая просто содержит произвольное имя и значение с внешним ключом Flow , т. Е. Хранилище значений «один ко многим».

3. Я бы также исследовал доступные пакеты типа form builder, поскольку они могут быть полезны в зависимости от того, что вы делаете с динамическими данными. pypi.org/project/django-form-builder

Ответ №1:

Даже если вы можете создать динамическое поле в Django, вы не можете создать динамический столбец в таблице Sqlite FLOW .

Если вы планируете использовать одни и те же типы полей в разных случаях, вы можете создать поле с абстрактным именем, например path . Это может быть как URL-адрес, так и путь к локальному файлу.

Обычным способом вам нужно создать все столбцы для всех вариантов для таблицы БД.

 class Flow(models.Model):
    owner = models.ForeignKey(User, on_delete=models.CASCADE,
                              verbose_name="Owner", default="ADMIN")

    source = models.CharField(default='HTTP', choices=SOURCE_CHOICES, editable=True, max_length=12)
    name = models.CharField(max_length=50, default=" ")
    date = models.DateTimeField(verbose_name="Creation date")
    local_path = models.ImageField(upload_to='files', null=True, blank=True) # when source is file
    url = models.URLField(null=True, blank=True) # when source is http
  

So local_path может быть пустым при использовании HTTP исходного кода.

Внутри представления вы можете динамически получать (или устанавливать) значение через сериализатор:

 class FlowSerializer(serializers.ModelSerializer):
    path = serializers.SerializerMethodField(method_name='get_path_value')

    class Meta:
        model = Flow
        fields = ('owner', 'source', 'name', 'date', 'path')

    def get_path_value(self, instance):
        if instance.source == 'HTTP':
            return instance.url
        else:
            return instance.local_path
  

Так path будет по-разному для разных источников.
И, возможно, вам потребуется установить django rest framework для этого решения.

ПРАВКА1: ответ на вопрос

Так что, если я правильно понимаю, наилучшей практикой должно быть создание «пустых» столбцов

Вы обязательно должны описать все столбцы в таблице (если вы не используете не Sql-подобную БД, такую как MongoDB). Так что да, создание «пустых» столбцов — это только один из возможных способов.

Но вы можете переопределить save метод в модели для динамически сохраняемых полей:

 class Flow(models.Model):
  temp_path = None
  path = models...
  url = models...
  choice = models...
  
  def save(self, *args, **kwargs):
    if choice == 'HTTP':
      self.url = temp_path
    else:
      self.path = temp_path
    super().save(*args, **kwargs)
  

Приведенный выше код — это просто краткая идея. На самом деле не рабочий код.

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

1. Спасибо за ваш ответ! Итак, если я хорошо понимаю, наилучшей практикой должно быть создание «пустых» столбцов. По-прежнему ли это лучшая практика, зная, что я хочу, чтобы пользователь выполнял POST-запрос с помощью форм для создания «потока»?

2. добавлено EDIT1 , чтобы ответить на ваш вопрос

3. что касается вашего вопроса, который вы только что удалили: взгляните на commandlinefu.com

Ответ №2:

Для этого вы можете реализовать пользовательский тип поля модели, это поможет вам сохранить объект объединения в одном столбце базы данных. Необработанный тип в базе данных может быть строкой JSON или другими сериализованными типами, для использования поля модели это просто собственный объект python!

Вот фрагмент примера кода: основными задачами являются эти два метода:

 class HandField(models.Field):
    # ...

    def from_db_value(self, value, expression, connection):
        if value is None:
            return value
        return parse_hand(value)

    def to_python(self, value):
        if isinstance(value, Hand):
            return value

        if value is None:
            return value

        return parse_hand(value)
  

Подробности см. в официальных документах.