sqlalchemy: добавление отношения «многие ко многим» не выполняется в представлениях, но работает в оболочке - PullRequest
0 голосов
/ 19 сентября 2019

Вот небольшая часть моего кода (я включил не все таблицы, а только те, которые вызывают ошибку).У меня есть отношение «многие ко многим» между таблицами Article и Keyword, материализованными в таблице ArticleKeyword, которая имеет дополнительный атрибут «textrank_score».Я использую association_proxy с пользовательским создателем в Article и обратными ссылками в ArticleKeyword, как объяснено здесь .На мой взгляд, я добавляю элементы в пример, используя стиль словаря: article.keywords[keyword]=score, где article и keyword - это экземпляры Article и Keyword соответственно.Это дает мне ошибку атрибута, потому что sqlalchemy считает score объектом ORM (та же ошибка, что и здесь ).Однако когда я делаю то же самое в оболочке Python, это удается.

# models.py

from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.orm.collections import attribute_mapped_collection
from .api import db

class Keyword(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    value = db.Column(db.String(80), unique=True)

    def __init__(self, value):
        self.value = value

class Article(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(200))
    url = db.Column(db.String(200))
    author = db.Column(db.String(200))
    description = db.Column(db.Text())
    image_url = db.Column(db.String(200))
    publication_date = db.Column(db.DateTime)
    source_id = db.Column(db.ForeignKey('source.id'))
    category_name = db.Column(db.String(80))

    source = db.relationship("Source", backref="article_source")

    keywords = association_proxy(
        'article_keywords', 'keyword', 
        creator=lambda k, v: ArticleKeyword(keyword=k, textrank_score=v)
    )

    __table_args__ = (
        db.ForeignKeyConstraint([source_id, category_name], [Category.source_id, Category.name]), 
        {}
    )

    def __init__(self, title=None, url=None, author=None, 
                description=None, image_url=None, publication_date=None, 
                source=None, category_name=None):

        self.title = title
        self.url = url
        self.author = author
        self.description = description
        self.image_url = image_url
        self.publication_date = publication_date
        self.source = source
        self.category_name = category_name

class ArticleKeyword(db.Model):
    article_id = db.Column('article_id', db.Integer, db.ForeignKey('article.id'), primary_key=True)
    keyword_id = db.Column('keyword_id', db.Integer, db.ForeignKey('keyword.id'), primary_key=True)
    textrank_score = db.Column('textrank_score', db.Float)

    keyword = db.relationship(Keyword)

    article = db.relationship(
        Article, 
        backref=db.backref('article_keywords', 
                        cascade='all, delete-orphan', 
                        collection_class=attribute_mapped_collection("keyword"))
    )

    def __init__(self, article=None, keyword=None, textrank_score=None):
        self.article = article
        self.keyword = keyword
        self.textrank_score = textrank_score
# views.py

class DataFetcher(Resource):

    def post(self):
        json_data = request.get_json(force=True)
        sources = self.sources_schema.load(json_data["sources"])

        for keywords, article_dict in fetch_articles(sources):
            # keywords = [{"keyword": "Hello", "score": 0.5}, ...]
            # article_dict = {"title": "Hello World", ...}

            article = Article(**article_dict)
            db.session.add(article)

            for kw_dict in keywords:
                kw_val, score = kw_dict['keyword'], kw_dict['score']
                keyword = Keyword(value=kw_val)
                db.session.add(keyword)
                article.keywords[keyword] = score
                # Previous line throws an AttributeError: 
                # 'float' object has no attribute '_sa_instance_state'

        db.session.commit()

        return jsonify({"message": "Success"})

Но работает следующее:

$ flask shell
Python 3.6.9 (default, Aug 14 2019, 13:09:32) 
[GCC 6.3.0 20170516] on linux
App: api.api [production]
Instance: /instance
>>> from api.models import *
>>> kwd = Keyword("asterix")
>>> article = Article(title="asterix le gaulois")
>>> article.keywords[kwd] = 0.8
>>> db.session.add(article)
>>> db.session.commit()
>>> db.session.query(ArticleKeyword).all()
[<ArticleKeyword 1137, 5344>]
>>> kwda, = db.session.query(ArticleKeyword).all()
>>> kwda.textrank_score
0.8

Есть идеи, что не так?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...