有幾個方法:
- 鍵/值模型(簡單,很好的支持)
- 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