2010-09-27 62 views
1

models.py:可能的错误

class root(models.Model): 
     uid_string = models.CharField(max_length=255, unique=True) 

class tree(models.Model): 
     uid_string = models.ForeignKey(root, to_field='uid_string', db_column='uid_string') 

class shrub(models.Model): 
     uid_string = models.ForeignKey(root, to_field='uid_string') 

显然,在shrub列将uid_string_idtree列将蜜蜂uid_string。 _id附录被抑制。

如果我现在在做一个

rootentry = root(uid_string = "text") 
root.save() 

我得到不同的行为,执行以下查询:

>>> shrubentry = shrub(uid_string_id = rootentry.uid_string) 
>>> treeentry = tree(uid_string = rootentry.uid_string)                
Traceback (most recent call last):                     
    File "<console>", line 1, in <module> 
    File "/usr/local/lib/python2.6/site-packages/django/db/models/base.py", line 328, in __init__ 
    setattr(self, field.name, rel_obj) 
    File "/usr/local/lib/python2.6/site-packages/django/db/models/fields/related.py", line 318, in __set__ 
    self.field.name, self.field.rel.to._meta.object_name)) 
ValueError: Cannot assign "'text'": "tree.uid_string" must be a "root" instance. 
>>> 

明显rootentry.uid_stringtext

回答

0

当foreignkeys打交道时,你需要使用对象像下面的实例。

treeentry = tree(uid_string = rootentry) 

顺便说一下,使用CamelCase作为类名称。请阅读http://www.python.org/dev/peps/pep-0008/

2

Django表现得和预期的一样。为了理解为什么我们将着眼于如何在外键关系的情况下将关键字参数传递给模型类的构造函数。

  1. 使用关系的名称(uid_string)。在这种情况下,您必须通过相关型号的实例uid_string = rootentry)。

  2. 使用数据库字段的名称(uid_string_id)。在这里你必须传递一个合适的类型的值。所以如果FK指向一个整数字段,传递一个整数;如果它指向文本,传递文本实例等。

现在让我们看看你的代码。我们将与第一线开始:

shrubentry = shrub(uid_string_id = rootentry.uid_string) 
shrubentry.save() # Succeeds 

您已经创建shrubroot之间的关系,而且还指定了一个自定义to_field链接。由于此列是文本字段,因此您可以通过rootentry.uid_string作为uid_string_id关键字参数(上面列出的机制#2)的值。

还有另外一种方法可以表达你在上面做了什么,而不使用字段名作为关键字参数。这将是使用关系的名称并传递根实例(上面列出的机制#1)。

shrubentry = shrub(uid_string = rootentry) 
shrubentry.save() # Succeeds 

现在让我们来看看第二行

treeentry = tree(uid_string = rootentry.uid_string) # Raises error. 
# ValueError: Cannot assign "'text'": "tree.uid_string" must be a "root" instance. 

此行不同于第一行。您正在使用机制#1(关系名称),因此Django需要root的实例作为关键字参数的值。如果切换到机制#2(字段名称):

treeentry = tree(uid_string_id = rootentry.uid_string) 
treeentry.save() # Succeeds 

现在出现有趣的部分。试试这个:

treeentry = tree(uid_string_id = rootentry.id) # No problem 
treeentry.save() # Blows up 
# IntegrityError: ... 
# DETAIL: Key (uid_string)=(2) is not present in table "app_root". 

上面代码片段的第一行有效。但是,当您尝试保存它时,数据库将在root表的_uid_string_列中查找键“2”(即rootentry.id)。由于它不在那里,save()失败。

+0

谢谢你的回答。据我了解,你使用to_field ='uid_string'来指定关系,并简单地通过db_column =“”来指定列的名称。退出to_field将引用主键(id)。我错了吗? – tpm 2010-09-27 17:46:25

+0

你说得对。退出'to_field'是正确的。我的错。我在编辑我的答案。 – 2010-09-27 17:50:13

+0

谢谢你的努力。但请再看一遍。这两个模型都有一个'to_field'来指定列。除了'db_column'定义的列名外,模型是相同的。 – tpm 2010-09-27 19:04:10