這幾天準備寫個工作流系統(tǒng)枷餐,因為工作流中一些模板的字段都是不固定的坷衍,于是思考有沒有動態(tài)的模型字段寝优,剛好找到了某個大神寫的東西,覺得有用(還沒有實踐)枫耳,于是記錄一下乏矾。
原文地址: https://stackoverflow.com/questions/7933596/django-dynamic-model-fields
翻譯地址:http://stackoverflow.org.cn/front/ask/view?ask_id=17340
我正在開發(fā)一個多租戶應(yīng)用程序,其中一些用戶可以通過管理員定義自己的數(shù)據(jù)字段迁杨,以收集表單中的其他數(shù)據(jù)并報告數(shù)據(jù)钻心。 后一位使JSONField不是一個很好的選擇,所以我有以下解決方案:
class CustomDataField(models.Model):
"""
Abstract specification for arbitrary data fields.
Not used for holding data itself, but metadata about the fields.
"""
site = models.ForeignKey(Site, default=settings.SITE_ID)
name = models.CharField(max_length=64)
class Meta:
abstract = True
class CustomDataValue(models.Model):
"""
Abstract specification for arbitrary data.
"""
value = models.CharField(max_length=1024)
class Meta:
abstract = True
注意CustomDataField如何具有一個ForeignKey到站點 - 每個站點將有一組不同的自定義數(shù)據(jù)字段铅协,但使用相同的數(shù)據(jù)庫捷沸。 然后可以將各具體數(shù)據(jù)字段定義為:
class UserCustomDataField(CustomDataField):
pass
class UserCustomDataValue(CustomDataValue):
custom_field = models.ForeignKey(UserCustomDataField)
user = models.ForeignKey(User, related_name='custom_data')
class Meta:
unique_together=(('user','custom_field'),)
這有以下用途
tom_field = UserCustomDataField.objects.create(name='zodiac', site=my_site) #probably created in the admin
user = User.objects.create(username='foo')
user_sign = UserCustomDataValue(custom_field=custom_field, user=user, data='Libra')
user.custom_data.add(user_sign) #actually, what does this even do?
但這感覺很笨重,特別是需要手動創(chuàng)建相關(guān)數(shù)據(jù)并將其與具體模型相關(guān)聯(lián)狐史。 有更好的方法嗎亿胸?
已被搶先棄用的選項:
- 自定義SQL即時修改表。 部分原因是因為這不會擴大预皇,部分是因為它太多了。
- 無數(shù)據(jù)解決方案婉刀,如NoSQL吟温。 我沒有反對他們,但他們還不是很好突颊。 最終這些數(shù)據(jù)是打字的鲁豪,并且存在使用第三方報告應(yīng)用程序的可能性潘悼。
- JSONField,如上所列爬橡,因為它不會很好地與查詢治唤。
原文有四個采納答案,但我覺得只有一種更合適糙申,下面只記錄那一張答案宾添。
JSONField:
JSON / JSONB字段支持任何JSON的可編碼的數(shù)據(jù)類型,而不僅僅是鍵/值對柜裸,但也往往是更快(對于JSONB)比Hstore更緊湊缕陕。幾個包實現(xiàn)JSON / JSONB字段,包括django-pgfields疙挺,但從Django 1.9扛邑,JSONField是一個內(nèi)置的使用JSONB存儲。
JSONField類似于HStoreField铐然,并且可以使用大型字典執(zhí)行得更好蔬崩。它還支持除字符串以外的類型,例如整數(shù)搀暑,布爾和嵌套字典沥阳。
使用:
#app/models.py
from django.contrib.postgres.fields import JSONField
class Something(models.Model):
name = models.CharField(max_length=32)
data = JSONField(db_index=True)
在shell中創(chuàng)建:
>>> instance = Something.objects.create(
name='something',
data={'a': 1, 'b': 2, 'nested': {'c':3}}
)
索引查詢幾乎與HStoreField相同,除了嵌套是可能的险掀。 復雜索引可能需要手動創(chuàng)建(或腳本遷移)沪袭。
>> Something.objects.filter(data__a=1)
>>> Something.objects.filter(data__nested__c=3)
>>> Something.objects.filter(data__has_key='a')
感覺這個方法簡單,可以試一下