Redis / STDNet数据模型回溯



我正在试验stdnet,我遇到了一个相对简单的案例的挑战。

如果我填充我的模型(见下面的<hr>(而不指定主键的值,我会得到:

stdnet.utils.exceptions.FieldValueError: {"author_id": "'main.book'需要字段'author_id'。

    author1 = models[Author](name='Jeff Doyle')

但是,为 id 添加一个值会使代码正常工作...

    author1 = models[Author](name='Jeff Doyle', id=1)

Author.idodm.AutoIdField().由于这是一个分层数据模型,我可能能够理解手动向模型添加id = odm.AutoIdField()的要求。 但是,文档说 odm。AutoIdField 自动生成主键的值。

我的问题:为什么在填充模型时需要手动指定id值?

我在Python 2.6.6

和Debian 6.0(内核2.6.32-5-amd64(上运行stdnet 0.8.2 w/Cython。


工作示例:

from stdnet import odm
class Author(odm.StdModel):
    id = odm.AutoIdField(primary_key=True, unique=True)
    name = odm.SymbolField()
    def __unicode__(self):
        return self.name
class Book(odm.StdModel):
    id = odm.AutoIdField(primary_key=True, unique=True)
    title = odm.CharField()
    author = odm.ForeignKey(Author, related_name='books')
    def __unicode__(self):
        return "<Book '%s' by %s>" % (self.title, self.author)
if __name__=='__main__':
    models = odm.Router('redis://localhost:6379?db=0')
    models.register(Author)
    models.register(Book)
    session = models.session()
    session.begin()
    author1 = models[Author](name='Jeff Doyle', id=1)
    session.add(author1)
    book1 = models[Book](title='Routing TCP/IP, Volume 1', id=2, author=author1)
    session.add(book1)
    session.commit()

追踪:

Traceback (most recent call last):
  File "stdnet_example.py", line 31, in <module>
    session.commit()
...
stdnet.utils.exceptions.FieldValueError: {"author_id": "Field 'author_id' is required for '__main__.book'."}

我相信问题是您试图在同一会话中同时插入书籍和作者。因此,在提交时,作者尚未保存到数据库中,因此没有可以在外键中引用的书籍的 ID。

我认为如果您在尝试添加书籍之前提交作者,它应该可以工作。像这样:

session.begin()
author1 = models[Author](name='Jeff Doyle')
session.add(author1)
session.commit()
session.begin()
book1 = models[Book](title='Routing TCP/IP, Volume 1', author=author1)
session.add(book1)
session.commit()

我看到有人在 GitHub 上提出了一个与您有类似问题的问题,并且 stdnet 作者的评论中有回应。我认为他基本上和我说的是同样的话,但你可以自己阅读。

最好(最有效(的方法是按如下方式编码:

with models.session().begin() as t1:
    for author in ['Leo Tolstoy', 'unknown ghostwriter']:
        t1.add(models.author(name=author))
    publisher = t1.add(models.publisher(name='Penguin Books'))

此时,将保存作者和发布者,此外,还可以从事务saved属性中检索作者:

authors = t1.saved['author']

您现在可以创建书籍:

with models.session().begin() as t2:
    for title in ['Anna Karenina', 'War and Peace']:
        t2.add(models.book(name=title, publisher=publisher))

现在,您可以通过最后一个事务添加作者:

books = t2.saved['book']
with models.session().begin() as t3:
    for book in books:
        # add the book to the transaction
        t3.add(book)
        for author in authors:
             book.authors.push_back(author)

上面的所有代码都假定你使用的是以下模型定义:

import sys
from stdnet import odm
class Publisher(odm.StdModel):
    name = odm.SymbolField()
    def __unicode__(self):
        return self.name
class Author(odm.StdModel):
    name = odm.SymbolField()
    def __unicode__(self):
        return self.name
class Book(odm.StdModel):
    name = odm.CharField()
    authors = odm.ListField(model=Author)
    publisher = odm.ForeignKey(Publisher, related_name='publishers')

    def __unicode__(self):
        return "<Book '%s' by %s>" % (self.name, self.authors)
首先我不知道

库(我实际上一直在寻找这个,所以谢谢:)(。我认为models.register不仅会在您的程序中注册模型,还会在 Redis 服务器上注册模型。因此,如果可以的话,您要么必须清除数据库,要么找到某种方法来更改模型。

希望对你有帮助

我最终使用了与James Holderness推荐的语法不同的语法;他的回答很有帮助,但我在原始问题中使用的语法似乎不适用于复杂的odm.ForeignKey模型。 我最终切换到了不同的语法,我在这里记录这些语法,因为python-stdnet 0.8文档有点令人困惑。

构建数据库:

if __name__=='__main__':
    ## assuming we have a test redis db at localhost:6379
    models = odm.Router('redis://localhost:6379?db=0')
    models.register(Publisher)
    models.register(Author)
    models.register(Book)
    session = models.session()
    session.begin()  # Start a redis session
    authors = list()
    for author in ['Leo Tolstoy', 'unknown ghostwriter']:
        authors.append(models.author.new(name=author))
    publisher = models.publisher.new(name='Penguin Books')
    session.commit()
    for title in ['Anna Karenina', 'War and Peace']:
        print "Writing", title
        book = models.book.new(name=title, publisher=publisher)
        for author in authors:
            book.authors.push_back(author)  # push_back() appends to odm.ListField
    session.commit()  # Write to the redis db

查询数据库:

    ## assuming we have a test redis db at localhost:6379
    models = odm.Router('redis://localhost:6379?db=0')
    models.register(Publisher)
    models.register(Author)
    models.register(Book)
    session = models.session()
    qs = models.book.filter(name__contains='War and Peace') # search Book.name
    print "You found", list(qs)

模型定义(用于生成和查询(:

import sys
from stdnet import odm
class Publisher(odm.StdModel):
    name = odm.SymbolField()
    def __unicode__(self):
        return self.name
class Author(odm.StdModel):
    name = odm.SymbolField()
    def __unicode__(self):
        return self.name
class Book(odm.StdModel):
    name = odm.CharField()
    authors = odm.ListField(model=Author)
    publisher = odm.ForeignKey(Publisher, related_name='publishers')

    def __unicode__(self):
        return "<Book '%s' by %s>" % (self.name, self.authors)

最新更新