2009-07-09 31 views
2

我想定義一組模型/對象,它們可以用來表示關係:field_set有許多字段,其中字段是django.db.model字段對象(IPAddressField,FilePathField等)。如何使用任意數量的任意字段類型對對象進行建模? (django orm)

我的目標是有一個ORM模型,它支持以下類型的'API'。

從控制器視圖讓說:

# Desired api below 
def homepage(request): 
    from mymodels.models import ProfileGroup, FieldSet, Field 

    group = ProfileGroup() 
    group.name = 'Profile Information' 
    group.save() 

    geographicFieldSet = FieldSet() 
    # Bind this 'field set' to the 'profile group' 
    geographicFieldSet.profilegroup = group 
    address_field = Field() 
    address_field.name = 'Street Address' 
    address_field.f = models.CharField(max_length=100) 
    # Bind this field to the geo field set 
    address_field.fieldset = geographicFieldSet 

    town_field = Field() 
    town_field.name = 'Town/City' 
    town_field.f = models.CharField(max_length=100) 
    # Bind this field to the geo field set 
    town_field.fieldset = geographicFieldSet 

    demographicFieldSet = FieldSet() 
    demographicFieldSet.profilegroup = group 
    age_field = Field() 
    age_field.name = 'Age' 
    age_field.f = models.IntegerField() 
    # Bind this field to the demo field set 
    age_field.fieldset = demographicFieldSet 

    # Define a 'weight_field' here similar to 'age' above. 

    for obj in [geographicFieldSet, town_field, address_field, 
       demographicFieldSet, age_field, weight_field]: 
    obj.save() 


    # Id also add some methods to these model objects so that they 
    # know how to render themselves on the page... 

    return render_to_response('page.templ', {'profile_group':group}) 

基本上我要支持「邏輯分組域」,因爲我看到自己不同類型的支持許多「字段設置」因此我渴望一個有意義的抽象。

我喜歡定義這個模型,以便我可以定義一組字段,其中字段的字段與字段類型一樣是任意的。所以,我可能有一個字段組「地理」,其中包括字段「國家」(CharField W /選擇),「城」(文本字段)等

繼承人伊夫想出迄今:

class ProfileGroup(models.Model): 
    name = models.CharField(max_length=200) 

# FieldSets have many Fields 
class FieldSet(models.Model): 
    name = models.CharField(max_length=200) 
    profilegroup = models.ForeignKey(ProfileGroup) 

class Field(models.Model): 
    f = models.Field() 
    fieldset = models.ForeignKey(FieldSet) 

儘管使用這些模型會在shell中產生錯誤,並最終不允許我存儲任意字段。

In [1]: from splink.profile_accumulator.models import Field, FieldSet, ProfileGroup 
In [2]: import django.db 
In [3]: profile_group = ProfileGroup() 
In [4]: profile_group.name = 'profile group name' 
In [5]: profile_group.save() 
In [6]: field_set = FieldSet() 
In [7]: field_set.name = 'field set name' 
In [8]: field_set.profilegroup = profile_group 
In [9]: field_set.save() 
In [10]: field = Field() 
In [11]: field.name = 'field name' 
In [12]: field.f = django.db.models.FileField() 
In [13]: field.save() 
--------------------------------------------------------------------------- 
ProgrammingError       Traceback (most recent call last) 

/var/www/splinkpage.com/splinkpage.pinax/splink/<ipython console> in <module>() 

/usr/lib/pymodules/python2.5/django/db/models/base.pyc in save(self, force_insert, force_update) 
    309    raise ValueError("Cannot force both insert and updating in " 
    310      "model saving.") 
--> 311   self.save_base(force_insert=force_insert, force_update=force_update) 
    312 
    313  save.alters_data = True 

/usr/lib/pymodules/python2.5/django/db/models/base.pyc in save_base(self, raw, cls, force_insert, force_update) 
    381    if values: 
    382     # Create a new record. 
--> 383     result = manager._insert(values, return_id=update_pk) 
    384    else: 
    385     # Create a new record with defaults for everything. 

/usr/lib/pymodules/python2.5/django/db/models/manager.pyc in _insert(self, values, **kwargs) 
    136 
    137  def _insert(self, values, **kwargs): 
--> 138   return insert_query(self.model, values, **kwargs) 
    139 
    140  def _update(self, values, **kwargs): 

/usr/lib/pymodules/python2.5/django/db/models/query.pyc in insert_query(model, values, return_id, raw_values) 
    890  part of the public API. 
    891  """ 
    892  query = sql.InsertQuery(model, connection) 
    893  query.insert_values(values, raw_values) 
--> 894  return query.execute_sql(return_id) 

/usr/lib/pymodules/python2.5/django/db/models/sql/subqueries.pyc in execute_sql(self, return_id) 
    307 
    308  def execute_sql(self, return_id=False): 
--> 309   cursor = super(InsertQuery, self).execute_sql(None) 
    310   if return_id: 
    311    return self.connection.ops.last_insert_id(cursor, 

/usr/lib/pymodules/python2.5/django/db/models/sql/query.pyc in execute_sql(self, result_type) 
    1732 
    1733   cursor = self.connection.cursor() 
-> 1734   cursor.execute(sql, params) 
    1735 
    1736   if not result_type: 

/usr/lib/pymodules/python2.5/django/db/backends/util.pyc in execute(self, sql, params) 
    17   start = time() 
    18   try: 
---> 19    return self.cursor.execute(sql, params) 
    20   finally: 
    21    stop = time() 

ProgrammingError: can't adapt 

所以我想知道,如果這是完全錯誤的做法,或者如果我需要使用Django的模型類有點不同得到我想要的東西。

+0

@保羅,如果你讓你的問題更短的也許更多的人會看看吧:) – Evgeny 2009-07-10 17:45:05

回答

0

在SQL中,不存在具有可變數量的列或變量類型列的表。另外,Django在運行時不會修改數據庫佈局,即不會調用ALTER TABLE語句 - 據我所知。

在運行應用程序之前,必須完整定義django數據模型。

您可能會發現this doc page與使用「多對一」關係相關。

實施例:

#profile 
class ProfileGroup(models.Model): 
    ... 

#fieldset 
class FieldSet(models.Model): 
    profile = models.ForeignKey(ProfileGroup) 

#field 1 
class Address(models.Model) 
    owner = models.ForeignKey(FieldSet,related_name='address') 
    #related name above adds accessor function address_set to Profile 
    #more fields like street address, zip code, etc 

#field 2 
class Interest(models.Model) 
    owner = models.ForeignKey(FieldSet,related_name='interest') 
    description = models.CharField() 

#etc. 

填充和訪問字段:

f = FieldSet() 
f.interest_set.create(description='ping pong') 
f.address_set.create(street='... ', zip='... ') 
f.save() 

addresses = f.address_set.all() 
interests = f.interest_set.all() 
#there are other methods to work with sets 

套在這種情況下模擬中的表資料可變字段。但是,在數據庫中,興趣和地址數據存儲在單獨的表格中,並帶有到Profile的外鍵鏈接。

如果您想訪問所有帶有一個存取函數的函數 - 您可以編寫一些將調用包裝到所有相關集合的東西。

即使你不能修改的飛行模型,你可以添加新的車型則發出

manage.py syncdb 

這將創建在數據庫中新表。但是,您將無法使用'syncdb'修改現有表中的字段 - django不會這樣做。您必須爲此手動輸入SQL命令。(所謂的web2py平臺會自動處理,但不幸的是web2py會不會有據可查的是,但它可能在API的質量方面高於Django的切割,是值得考慮看看)

+0

進出口基本試圖創建一個抽象,以便我可以定義「場組」,我不知道提前知道場類型,也不能確定組中有多少場。你可以想象一種不同的方法,而我從上面開始支持它嗎? – Paul 2009-07-10 02:11:13

1

我看到的幾個問題代碼。首先,用這個類定義:

class Field(models.Model): 
    f = models.Field() 
    fieldset = models.ForeignKey(FieldSet) 

類models.Field不應該直接用於字段定義。它是Django中所有字段類型的基類,因此它缺少特定字段類型的用途。

的第二個問題是以下行:

In [12]: field.f = django.db.models.FileField() 

當您指定的屬性您Field實例f,你應該給被保存到數據庫中的特定值。例如,如果您使用CharField來定義Field.f,則可以在此處指定一個字符串。 models.Field雖然沒有特定的賦值。您正在嘗試分配一些明顯不可能保存到數據庫的內容。這是modles.FileField的定義。

因此,由於兩個原因,Django很難「調整」您分配給字段屬性的值。首先,沒有爲models.Field類型定義的值,因爲它是「抽象類」,或者是特定字段類型定義的基類。其次,您不能將「字段定義」分配給某個屬性,並希望將其保存到數據庫中。

我明白你的困惑。你基本上都試圖從數據庫和Django的角度來做不可能的事情。

我想可能有一個解決方案,但您的設計問題。如果你詳細描述你想要達到的目標,有人可能會給你一個提示。

0

爲什麼不這樣做?

class Info(models.Model): 
    info_type = models.ForeignKey('InfoType', blank=False, null=False, default='') 
    info_int = models.IntegerField(null=True, blank=True) 
    info_img = models.ImageField(upload_to='info',null=True, blank=True) 
    info_date = models.DateTimeField(null=True, blank=True) 
    info_text = models.TextField(null=True, blank=True) 
    info_bool = models.BooleanField(null=True, blank=True) 
    info_char = models.CharField(max_length=128,null=True, blank=True) 
    info_dec = models.DecimalField(max_digits=20, decimal_places=12, null=True, blank=True) 
    info_float = models.FloatField(null=True, blank=True) 
    parent_info = models.ForeignKey('self', blank=True, null=True) 
class InfoType(models.Model): 
    type = models.CharField(max_length=64, blank=False, null=False, default='') 
    info_field = models.CharField(max_length=32, blank=False, null=False, default='') 

所以根據我們選擇哪種類型,我們知道在哪個領域,我們可以找到價值

相關問題