#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)
Подробности см. в официальных документах.