【问题标题】:flask-sqlalchemy insert is not mappedflask-sqlalchemy 插入未映射
【发布时间】:2013-06-20 21:13:17
【问题描述】:

我在 flask-sqlalchemy 中正确实现多对多关系时遇到了很多麻烦。它从重复的标签开始,现在,很多天后是一个映射问题。公平的警告,在这些问题出现之前,我的代码要漂亮得多。我还添加了一个 addproduct.py 文件以加快测试速度。就是这样。

models.py

1 from app import app, db                                                                                                                                     
2 
3 product_tags = db.Table('association',
4         db.Column('product_id', db.Integer, db.ForeignKey('product.id')),
5         db.Column('tag_name', db.Integer, db.ForeignKey('tag.name'))
6 )
7 
8 class Product(db.Model):                                                                                                                                    
9     id = db.Column(db.Integer, primary_key=True)
10     title = db.Column(db.String(128))                                                                                                                       
11     description = db.Column(db.Text)
12     image = db.Column(db.String(64))
13     link = db.Column(db.String(256))
14     price = db.Column(db.Float())
15     timestamp = db.Column(db.DateTime)                                                                                                                      
16     expiration = db.Column(db.String(6))
17     tags = db.relationship('Tag', secondary=product_tags,                                                                                                   
18             backref=db.backref('product', lazy='dynamic'))
19 
20     def __init__(self, title, description, image, link, price, timestamp, expiration,    tags):                                                                
21         self.title = title                                                                                                                                  
22         self.description = description                                                                                                                      
23         self.image = image                                                                                                                                  
24         self.link = link                                                                                                                                    
25         self.price = price                                                                                                                                  
26         self.timestamp = timestamp
27         self.expiration = expiration                                                                                                                        
28         self.tags = tags                                                                                                                                    
29         print self.title                                                                                                                                    
30 
31     def __repr__(self):                                                                                                                                     
32         return '<Title %r, Description %r, Image %r, Link %r, Price %r, Timestamp %r,    Expires %r, Tags %r>' % (self.title, self.description, self.image, sel
33 
34 class Tag(db.Model):                                                                                                                                        
35     name = db.Column(db.String(32), primary_key=True)
36 
37     def __init__(self, name):
38         self.name = name                                                                                                                                    
39 
40     def __repr__(self):                                                                                                                                     
41         return '<Tag %r>' % self.name

addproduct.py

1 from app import db                                                                                                                                          
2 from app.models import Product, Tag, product_tags
3 from datetime import datetime                                                                                                                               
4 
5 imagefolder = 'static/img/'
6 
7 title = 'product'
8 description = 'description'
9 image = 'image.jpg'
10 link = 'http://link.com'
11 price = 2000.00
12 expiration = ''
13 tags = ['tag1','tag2']                                                                                                                              
14 
15 newtags = []                                                                                                                                                
16 
17 def create_product(title, description, image, link, price, expiration, tags):                                                                               
18     image = imagefolder + image                                                                                                                             
19     tag_assoc = []
20     for tag in tags:                                                                                                                                        
21         tagcheck = Tag.query.filter_by(name=tag).first()                                                                                                    
22         if tagcheck == None:                                                                                                                                
23             tag_assoc.append(Tag(tag))                                                                                                                      
24         else:                                                                                                                                               
25             newtags.append(tag)                                                                                                                             
26 
27     product = Product(title, description, image, link, price, datetime.utcnow(),    expiration, tag_assoc)                                                     
28     create_assoc(newtags)                                                                                                                                   
29     return product                                                                                                                                          
30 
31 def create_assoc(newtags):                                                                                                                                  
32     title_search = Product.query.filter_by(title=title).first()                                                                                             
33     for tag in newtags:
34         assoc = product_tags.insert().values(product_id=title_search.id,    tag_name=tag)
35         db.session.add(assoc)                                                                                                                               
36     db.session.commit()
37 
38 if __name__ == '__main__':
39     product = create_product(title, description, image, link, price, expiration,    tags)
40     db.session.add(product)                                                                                                                                 
41     db.session.commit()                                                                                                                                     
42     create_assoc(newtags) 

我得到的错误信息是:

11:11 ~/shop $ python addproduct.py
product
Traceback (most recent call last):
File "addproduct.py", line 39, in <module>
product = create_product(title, description, image, link, price, expiration, tags)
File "addproduct.py", line 28, in create_product
create_assoc(newtags)
File "addproduct.py", line 35, in create_assoc
db.session.add(assoc)
File "/home/username/.local/lib/python2.7/site-packages/sqlalchemy/orm/scoping.py", line 114, in do
return getattr(self.registry(), name)(*args, **kwargs)
File "/home/username/.local/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 1358, in add
raise exc.UnmappedInstanceError(instance)
sqlalchemy.orm.exc.UnmappedInstanceError: Class 'sqlalchemy.sql.expression.Insert' is not mapped

这是我的第一个网络应用程序,不是直接来自教程,我完全迷路了。请帮忙!

【问题讨论】:

    标签: python database sqlalchemy flask flask-sqlalchemy


    【解决方案1】:

    我可以在您的模型中看到的第一个错误——您的关联正确地有两个外键,但标签的外键是 Integer,但您的 Tag 类中的主键是 String - 他们应该匹配。除此之外,模型看起来不错。

    您还应该能够简化您的 create_product 函数:

    def create_product(title, description, image, link, price, expiration, tags):
        image = imagefolder + image
        tag_list = []
        for tag in tags:
            tagcheck = Tag.query.filter_by(name=tag).first()
            if tagcheck is None:
                tag_list.append(Tag(tag))
            else:
                tag_list.append(tagcheck)
        product = Product(title, description, image, link, price, datetime.utcnow(), expiration, tag_list)
        return product
    

    这可以很容易地在你的 __init___ 构造函数中移动。在您的示例中,您直接处理关联表,但您根本不需要 - 只需相信 ORM 会做正确的事情,这就是 SQLAlchemy 的美妙之处。

    以下是您的产品模型的示例:

    class Product(db.Model):
        id = db.Column(db.Integer, primary_key=True)
        title = db.Column(db.String(128))
        description = db.Column(db.Text)
        image = db.Column(db.String(64))
        link = db.Column(db.String(256))
        price = db.Column(db.Float())
        timestamp = db.Column(db.DateTime)
        expiration = db.Column(db.String(6))
        tags = db.relationship('Tag', secondary=product_tags,
                backref=db.backref('products', lazy='dynamic'))
    
        def __init__(self, title, description, image, link, price, timestamp, expiration, tags):
            self.title = title
            self.description = description
            self.image = image
            self.link = link
            self.price = price
            self.timestamp = timestamp
            self.expiration = expiration
    
            for tag in tags:
                tagcheck = Tag.query.filter_by(name=tag).first()
                if tagcheck is None:
                    self.tags.append(Tag(tag))
                else:
                    self.tags.append(tagcheck)
    
        def __repr__(self):
            return '<{}, {}>'.format(self.title, ":".join([x.name for x in self.tags]))
    

    为了测试它,首先让我们在系统中添加几个标签:

    ta = Tag('cat')
    tb = Tag('dog')
    db.session.add_all([ta, tb])
    db.session.commit()
    
    >>> Tag.query.all()
    [<Tag u'cat'>, <Tag u'dog'>]
    

    现在让我们添加一个使用这些标签的产品,以及一个新标签。

    p = Product(
        'title',
        'description',
        'image',
        'link',
        0.0,
        datetime.now(),
        'expiry',
        ['dog','cat','horse']
    )
    db.session.add(p)
    db.session.commit()
    

    当我们创建该产品时,构造函数获取这三个字符串标签中的每一个,并说“嘿,这个名称的标签是否已经存在?”如果是,它会使用它,如果不是,它会使用该名称创建一个新标签。 SQLAlchemy 足够聪明,知道将新标签添加到会话中,并在提交产品时提交它。

    >>> Tag.query.all()
    [<Tag u'cat'>, <Tag u'dog'>, <Tag u'horse'>]
    

    现在让我们查找所有带有狗标签的产品(假设添加了更多产品)。

    >>> tag = Tag.query.get('dog')
    >>> products = tag.products
    >>> [x.title for x in products]
    ['title','other','examples']
    

    再一次,我根本没有接触关联表,没有必要。 SQLAlchemy 为我们节省了工作量。

    【讨论】:

    • 如果我把它放在标签 init 中,无论如何都会创建标签吗?如果它是我不想创建的重复标签,我只想创建关联。另外,感谢您指出整数/字符串问题。
    • 我尝试了您建议的更改,但出现错误 AttributeError: 'Table' object has no attribute 'append'。它参考了 product_tags.append。
    • 我的意思是将它添加到产品初始化中,您将产品需要的标签作为字符串传递,然后产品初始化决定是否需要创建它们,或者是否可以重用数据库中现有的标签。另外我相信我已经修复了附加错误,我的示例中存在变量冲突。
    • 好的,我将相关函数移至models.py,但如果标签已经存在,我仍然无法创建关系。 Here 是指向 pastebin 中新 models.py 的链接。此外,当我刚刚附加 tagcheck 时,它抛出了一个错误。再次感谢!
    • 您仍然无缘无故地直接访问关联表——相信 ORM! :) 我会在答案的底部添加我认为您的产品模型应该是什么样的。
    猜你喜欢
    • 2020-01-30
    • 1970-01-01
    • 1970-01-01
    • 2017-05-04
    • 2014-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多