3

我正在尝试使用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)上运行带有 Cython 的stdnet 0.8.2。


工作示例:

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'."}
4

4 回答 4

3

我认为问题在于您试图在同一个会话中插入这本书和作者。所以在提交的时候,作者还没有被保存到数据库中,因此在外键中没有书的 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 的作者在评论中有回应。我认为他基本上和我说的一样,但是您可以自己阅读。

于 2013-07-31T12:28:13.247 回答
1

最好(最有效)的方法是编写如下代码:

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)
于 2013-08-06T10:56:12.617 回答
0

我最终使用了与 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)
于 2013-08-01T21:32:52.667 回答
0

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

希望能帮助到你

于 2013-07-31T11:10:38.973 回答