возможная ошибка в моделях Django - PullRequest
1 голос
/ 27 сентября 2010

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_id, тогда как столбец в tree будет 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_string это text

Ответы [ 2 ]

2 голосов
/ 27 сентября 2010

Джанго ведет себя так, как ожидалось. Чтобы понять, почему мы начнем с рассмотрения способов передачи аргументов ключевых слов в конструктор класса модели в случае связи с внешним ключом.

  1. Используйте имя отношения (uid_string). В этом случае вы должны передать экземпляр связанной модели (uid_string = rootentry).

  2. Использовать имя поля базы данных (uid_string_id). Здесь вы должны передать значение соответствующего типа . Поэтому, если FK указывает на целочисленное поле, передайте целое число; если он указывает на текст, передайте текстовый экземпляр и т. д.

Теперь давайте посмотрим на ваш код. Мы начнем с первой строки :

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

Вы создали отношение между shrub и root, но также указали пользовательский to_field для ссылки. Поскольку этот столбец является текстовым полем, вы можете передать rootentry.uid_string в качестве значения аргумента ключевого слова uid_string_id (механизм # 2 указан выше).

Существует другой способ выразить то, что вы сделали выше, без использования имени поля в качестве аргумента ключевого слова. Это будет использовать имя отношения и передать экземпляр root (механизм # 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".

Первая строка приведенного выше фрагмента работает. Но когда вы пытаетесь сохранить его, база данных ищет ключ «2» (т.е. rootentry.id) в столбце _uid_string_ таблицы root. Так как его там нет, save() терпит неудачу.

0 голосов
/ 27 сентября 2010

При работе с иностранными ключами вам нужно использовать экземпляр объекта, как показано ниже.

treeentry = tree(uid_string = rootentry)

Кстати, используйте CamelCase для имен классов.Пожалуйста, прочитайте http://www.python.org/dev/peps/pep-0008/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...