【问题标题】:Can you explain strange behaviour with Django ManyToManyField?你能解释一下 Django ManyToManyField 的奇怪行为吗?
【发布时间】:2011-08-22 06:30:03
【问题描述】:

我有几个相关的模型,看起来有点像这样:

class Book(models.Model):
    title = models.TextField()

class Author(models.Model):
    """
    >>> b = Book(title='some title')
    >>> b.save()
    >>> a = Author(name='some name')
    >>> a.save()
    >>> a.books.add(b)
    >>> b in a.books.all()
    True
    """
    name = models.TextField()
    books = models.ManyToManyField(Book)

此版本是我的生产应用程序的简化版本,但生产中的相同测试失败 - a.books.all() 返回空列表,即使在我执行 a.books.add(b) 之后也是如此。

我查看了数据库(sqlite),并且肯定在连接表 book_author 中创建了一个新条目。我还尝试调用 transaction.commit() 和 connection.close() 来尝试刷新数据库的视图。没有喜悦。任何关于什么样的事情可能导致生产中的奇怪行为的指针都将不胜感激。

我的一个想法是它与第三个相关模型有关,为此我手动指定了一个直通表,如下所示:

class Genre(models.Model): 
    desc = models.TextField() 
    books = models.ManyToManyField(Book, through='BookGenres') 

class BookGenres(models.Model): 
    book = models.ForeignKey(Book) 
    genre = models.ForeignKey(Genre)

但是,将它添加到测试应用程序并不会破坏事情......我还应该寻找什么?

[edit 11/5] 更奇怪的行为,听从 Daniel the cmets 的建议(感谢您的尝试!:-)

更奇怪的行为:

>>>a.books.all()
[]
>>>a.books.filter(pk=b.id)
[]
>>>a.books.filter(pk=b.id).count()
1
>>>len(a.books.filter(pk=b.id))
0

正如我所说,我的“真实”模型更复杂,我无法在简化测试中复制这种行为,但我们将不胜感激任何关于查看内容的想法。

【问题讨论】:

    标签: django sqlite django-models transactions many-to-many


    【解决方案1】:

    我不确定in 运算符是否一定适用于查询集中。不要忘记 Django 模型实例没有标识,因此在两个单独的操作中从 db 加载的两个对象可以具有不同的内部 ID,即使它们具有相同的 pk。

    我会明确查询您期望的项目:

    >>> a.books.add(b)
    >>> a.books.filter(pk=b.pk).count()
    1
    

    我还要补充一点,我看不出这个测试的意义。 Django 的模型操作被它自己的测试套件很好地覆盖了——你应该为你自己的业务逻辑保留你的单元/文档测试。

    【讨论】:

    • 同意 - 表示相同数据库项的对象可能具有不同的 python 内部 ID,但确实比较相等,因为 eq 用于比较 pk 的
    • 而且,如果 django 的低级模型操作按照应有的方式运行,我不会为它们编写测试!
    猜你喜欢
    • 1970-01-01
    • 2011-07-28
    • 1970-01-01
    • 2012-03-23
    • 2011-06-03
    • 1970-01-01
    • 2010-09-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多