2013-06-24 5 views
3

flask-sqlalchemy에서 많은 관계를 올바르게 구현하는 데 많은 어려움이있었습니다. 그것은 중복 된 태그로 시작했고 지금은 며칠 후 매핑 문제입니다. 공정한 경고, 내 코드는 훨씬 더 예리했다. 또한 테스트 속도를 높이기 위해 addproduct.py 파일을 추가했습니다. 그래서 여기 있습니다. 이것은 내 첫 번째 웹 애플리케이션은 튜토리얼에서 직접적으로 flask-sqlalchemy 삽입이 매핑되지 않았습니다.

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 

이다

, 그리고 :

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) 

내가 오류 메시지는 나는 완전히 잃어버린다. 도와주세요!

답변

4

귀하의 모델에 두 개의 외래 키가 올바르게 있지만 태그의 외래 키가 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___ 생성자 내에서 이동할 수 있습니다. 귀하의 예제에서 당신은 직접 association 테이블을 다루지 만, 전혀 할 필요는 없습니다. ORM이 올바른 것을하기를 신뢰하십시오, 그것은 SQLAlchemy의 아름다움입니다. 여기

은 제품 모델과 같이 수 있는지의 예 :

ta = Tag('cat') 
tb = Tag('dog') 
db.session.add_all([ta, tb]) 
db.session.commit() 

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

이제 추가 할 수 있습니다 :

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])) 

그리고 그것을 테스트하기 위해, 먼저 시스템에 태그의 몇 가지를 추가 할 수 있습니다 그 태그를 사용하는 제품, 새로운 태그. 우리가 제품을 만들 때

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는 우리를 저축하고 있습니다.

+0

태그를 __init__에 넣으면 태그가 무엇이든 상관없이 생성됩니까? 만약 내가 그것을 만들고 싶지 않은 중복 태그라면, 나는 단지 연관성을 만들길 원한다. 또한 정수/문자열 문제를 지적 해 주셔서 감사합니다. – BradleyMoore

+0

제안한 변경 사항을 시도했지만 AttributeError 오류가 발생했습니다 : '테이블'개체에 'append'속성이 없습니다. product_tags.append를 참조합니다. – BradleyMoore

+1

제품 init에 제품을 추가하고, 제품에 필요한 태그를 문자열로 전달한 다음 제품 init이 제품을 작성해야하는지 또는 데이터베이스에서 기존 제품을 재사용 할 수 있는지를 결정합니다. 또한 나는 추가 오류를 고쳤다 고 믿는다. 필자의 경우 변수가 다르다. – Doobeh

관련 문제