这是有关django的问题。我有一个模特说“汽车”。这将具有一些基本字段,例如“颜色”,“车辆所有者名称”,“车辆成本”。
我想提供一个表格,用户可以根据他要添加的汽车添加额外的字段。例如,如果用户添加“汽车”,则他将在运行时动态地在表单中添加其他字段,例如“汽车里程”,“校准制造商”。假设用户想要添加“卡车”,他将添加“可以运载的货物”,“许可证”等。
如何在Django中实现这一目标?
这里有两个问题:
有几种方法:
如果必须允许站点用户/管理员直接定义其数据,我相信其他人将向你展示如何执行上述前两种方法。第三种方法是你要的,更疯狂的是,我将向你展示如何做。我不建议在几乎所有情况下都使用它,但有时它是合适的。
动态模型
一旦知道要做什么,这就相对简单了。你需要:
1.存储模型定义
这取决于你。我想你将拥有一个模型,CustomCarModel
并CustomField
让用户/管理员定义和存储所需字段的名称和类型。你不必直接镜像Django字段,可以创建自己的类型,以便用户更好地理解。
forms.ModelForm
与内联表单集一起使用可让用户构建其自定义类。
2.抽象模型
同样,这很简单,只需为所有动态模型创建具有公共字段/方法的基本模型即可。使该模型抽象。
3.建立动态模型
定义一个函数,该函数接收所需的信息(可能是#1类的实例)并生成一个模型类。这是一个基本示例:
from django.db.models.loading import cache
from django.db import models
def get_custom_car_model(car_model_definition):
""" Create a custom (dynamic) model class based on the given definition.
"""
# What's the name of your app?
_app_label = 'myapp'
# you need to come up with a unique table name
_db_table = 'dynamic_car_%d' % car_model_definition.pk
# you need to come up with a unique model name (used in model caching)
_model_name = "DynamicCar%d" % car_model_definition.pk
# Remove any exist model definition from Django's cache
try:
del cache.app_models[_app_label][_model_name.lower()]
except KeyError:
pass
# We'll build the class attributes here
attrs = {}
# Store a link to the definition for convenience
attrs['car_model_definition'] = car_model_definition
# Create the relevant meta information
class Meta:
app_label = _app_label
db_table = _db_table
managed = False
verbose_name = 'Dynamic Car %s' % car_model_definition
verbose_name_plural = 'Dynamic Cars for %s' % car_model_definition
ordering = ('my_field',)
attrs['__module__'] = 'path.to.your.apps.module'
attrs['Meta'] = Meta
# All of that was just getting the class ready, here is the magic
# Build your model by adding django database Field subclasses to the attrs dict
# What this looks like depends on how you store the users's definitions
# For now, I'll just make them all CharFields
for field in car_model_definition.fields.all():
attrs[field.name] = models.CharField(max_length=50, db_index=True)
# Create the new model class
model_class = type(_model_name, (CustomCarModelBase,), attrs)
return model_class
4.更新数据库表的代码
上面的代码将为你生成一个动态模型,但不会创建数据库表。我建议使用South进行表操作。这里有几个功能,你可以将它们连接到保存前/保存后信号:
import logging
from south.db import db
from django.db import connection
def create_db_table(model_class):
""" Takes a Django model class and create a database table, if necessary.
"""
table_name = model_class._meta.db_table
if (connection.introspection.table_name_converter(table_name)
not in connection.introspection.table_names()):
fields = [(f.name, f) for f in model_class._meta.fields]
db.create_table(table_name, fields)
logging.debug("Creating table '%s'" % table_name)
def add_necessary_db_columns(model_class):
""" Creates new table or relevant columns as necessary based on the model_class.
No columns or data are renamed or removed.
XXX: May need tweaking if db_column != field.name
"""
# Create table if missing
create_db_table(model_class)
# Add field columns if missing
table_name = model_class._meta.db_table
fields = [(f.column, f) for f in model_class._meta.fields]
db_column_names = [row[0] for row in connection.introspection.get_table_description(connection.cursor(), table_name)]
for column_name, field in fields:
if column_name not in db_column_names:
logging.debug("Adding field '%s' to table '%s'" % (column_name, table_name))
db.add_column(table_name, column_name, field)
在那里,你拥有了!你可以调用get_custom_car_model()传递Django模型,该模型可用于执行常规django查询:
CarModel = get_custom_car_model(my_definition)
CarModel.objects.all()
问题
class_prepared
定义模型的信号中为定义的每个实例运行。ForeignKeys/ ManyToManyFields
可能不起作用(我没有尝试过)总结
如果你对增加的复杂性和问题感到满意,请尽情享受!它运行着,由于Django和Python的灵活性,它可以按预期运行。你可以将模型输入Django ModelForm
,让用户编辑其实例,并直接使用数据库的字段执行查询。如果上面没有什么你不了解的地方,最好不要采用这种方法(我故意不解释某些概念对初学者的意义)。把事情简单化!
我确实不认为有很多人需要这样做,但是我自己使用了它,因为我们表中有很多数据,并且确实非常需要让用户自定义列,而这些列很少更改。
问题内容: 我正在开发一个多租户应用程序,其中一些用户可以定义自己的数据字段(通过管理员)以收集表单中的其他数据并报告数据。后一点使得JSONField不是一个很好的选择,所以我有以下解决方案: 请注意,CustomDataField如何具有Site的ForeignKey-每个Site将具有一组不同的自定义数据字段,但是使用相同的数据库。然后可以将各种具体的数据字段定义为: 这导致以下用途: 但这
问题内容: 我正在开发一个多租户应用程序,其中一些用户可以定义自己的数据字段(通过管理员)以收集表单中的其他数据并报告数据。后一点使得JSONField不是一个很好的选择,所以我有以下解决方案: 请注意,CustomDataField如何具有Site的ForeignKey-每个Site将具有一组不同的自定义数据字段,但是使用相同的数据库。然后可以将各种具体的数据字段定义为: 这导致以下用途: 但这
问题内容: 我有一个Django应用,该应用需要以下形式的属性: 然后钩住它们的post_save信号,以根据attributeN定义更新其他固定模型。 我想测试这种行为,即使该应用程序是项目中的唯一应用程序,测试也应该可以进行(除了它自己的依赖项之外,不需要安装其他包装器应用程序)。如何仅为测试数据库创建和附加/注册/激活模拟模型?(或者有可能吗?) 允许我使用测试治具的解决方案会很棒。 问题答
问题内容: 是否有可能做类似这样的一个东西,还是其他什么东西? 如果我可以扩展它,那就更好了: 问题答案: 如果和是模型中的字段,则可以使用**运算符将关键字参数传递到字典中。 假设你的模型称为MyModel: 至于第二个问题,字典必须是最后一个参数。同样,并且应该是模型中的字段。
我有一个巨大的字符串,我想保存为Django模型中的文件。为了做到这一点,我编写了以下代码: 这产生了一个错误, ’_ io。TextIOWrapper对象没有属性“_committed” 但是在网上搜索解决方案后,我陷入了死胡同。任何建议将不胜感激! 环境: 请求方法:获取请求 URL:http://127.0.0.1:8000/app/dbkarga/6/ Django版本:1.11.1 Py
问题内容: 是否有任何使用Spring或java替换模板字符串以及值的API。 例如: 其中参数(,)中的形式。 问题答案: 我最喜欢的模板引擎是Apache Velocity 也可以与Spring很好地集成,此处有介绍性文章