有几个方法:
- 键/值模型(简单,很好的支持)
- JSON数据的文本字段(方便,灵活,不能搜索/索引很容易)
- 动态模型定义(不那么容易,很多隐藏问题)
这听起来像你想要的最后一个,但我不知道这是最适合你的。 Django非常易于更改/更新,如果系统管理员需要额外的字段,只需为它们添加它们并使用south进行迁移即可。我不喜欢通用键/值数据库模式,像Django这样的强大框架的重点在于,您可以轻松编写和重写自定义模式,而无需使用通用方法。
如果您必须允许网站用户/管理员直接定义他们的数据,我相信其他人会告诉您如何执行上述前两种方法。第三种方法是你所要求的,并且更疯狂一些,我会告诉你如何去做。我不建议在几乎所有情况下都使用它,但有时候这是适当的。
动态模型
一旦你知道该怎么做,这是相对简单的。你需要:
- 1或2个型号存储字段的名称和类型
- (可选)的抽象模型,为您的(子类)动态模型
- 函数定义常用功能需要
- 代码来构建或更新数据库表时,当字段被添加/移除建立(或重建)的动态模型/重命名
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()
问题
- 你的模型是从Django中隐藏,直到代码创建它们运行。但是,您可以在
class_prepared
信号中为定义模型运行get_custom_car_model
,以获得您定义的每个实例。
ForeignKeys
/ManyToManyFields
可能无法正常工作(我没试过)
- 您将要使用Django的模型缓存,所以你不必运行查询和创建模型要使用这个每一次。为简单起见,我已将上述内容留在了上面
- 您可以将动态模型添加到管理员中,但您还需要动态创建管理员类,并使用信号适当地注册/重新注册/取消注册。
概述
如果你是罚款增加复杂性和问题,尽情享受!它正在运行,它的工作原理与Django和Python的灵活性一样。您可以将模型提供给Django的ModelForm
以让用户编辑他们的实例,并直接使用数据库的字段执行查询。如果上面有任何你不明白的地方,你可能最好不要采用这种方法(我故意没有解释一些概念适用于初学者)。把事情简单化!
我真的不认为很多人需要这个,但是我自己也使用过它,我们在表中有很多数据,真的需要让用户自定义列,而这些列很少会改变。
**你可能想看看这个问题的主题:http://stackoverflow.com/q/7933596/497056 – 2012-02-19 13:40:31