簡體   English   中英

SQLAlchemy:創建多對多並填充關聯

[英]SQLAlchemy: create many-to-many and populate association

我的想法如下:

  • 有一個主表( Documents ),其中包含一些文本,例如博客文章。 每個文檔都有一個唯一的 id text_id
  • 有一個輔助表 ( Links ) 存儲出現在這些帖子中的唯一 url。 每個 url 都有一個唯一的 id url_id
  • 這些由關聯表 ( Association ) 綁定,關聯表將文本的 id 映射到域的 id。

我希望能夠獲取帖子,從中收集網址,然后:

  • Documents中創建新記錄
  • 如果它包含新的 url - 將它們添加到Links並通過Association與文檔相關
  • 如果文檔包含已經存在的 url - 僅在新文檔和那些之間創建關聯。

對於初學者,我創建了三個類,如下所示

class Association(Base):
    __tablename__ = 'association'
    text_id = Column('text_id', Integer, ForeignKey('left.text_id'), primary_key=True)
    url_id = Column('url_id', Integer, ForeignKey('right.url_id'), primary_key = True)
    child = relationship("Links", back_populates='parents')
    parent = relationship("Documents", back_populates='children')

class Documents(Base):
    __tablename__ = 'left'
    text_id = Column(Integer, primary_key=True, unique=True)
    text = Column(Text)
    children = relationship("Association", back_populates='parent')

class Links(Base):
    __tablename__ = 'right'
    url_id = Column(Integer, primary_key=True, autoincrement=True, unique=True)
    url = Column(Text, unique=True)
    parents = relationship('Association', back_populates = 'child')

Base.metadata.create_all(engine)

然后我試圖加載數據:

data = [
    {'id':1, 'text':'sometext', 'url':'facebook.com'},
    {'id':2, 'text':'sometext', 'url':'twitter.com'},
    {'id':3, 'text':'sometext', 'url':'twitter.com'}
]

for row in data:
    d = Document(text_id = row['id'])
    a = Association()
    a.child = Links(url = row['url'])
    d.children.append(a)
    session.add(d)
session.commit()

這會導致錯誤:

Traceback (most recent call last):
  File "/home/user/.pyenv/versions/3.7.12/envs/myenv/lib/python3.7/site-packages/IPython/core/interactiveshell.py", line 3444, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-13-325b1cd57576>", line 5, in <module>
    p.children.append(a)
  File "/home/user/.pyenv/versions/3.7.12/envs/myenv/lib/python3.7/site-packages/sqlalchemy/util/langhelpers.py", line 1240, in __getattr__
    return self._fallback_getattr(key)
  File "/home/user/.pyenv/versions/3.7.12/envs/myenv/lib/python3.7/site-packages/sqlalchemy/util/langhelpers.py", line 1214, in _fallback_getattr
    raise AttributeError(key)
AttributeError: append

我真的不明白為什么,因為似乎我已經按照官方文檔的建議做了所有事情。

另一方面,即使這樣可行,我懷疑通過p.children.append(a)附加已經存在的 url 可能會導致錯誤,因為它實際上會嘗試創建副本,而Links不允許這樣做。

如果這很重要,我正在使用 mySQL 和 MariaDB。

也許我為這項工作選擇了錯誤的工具 - 如果您能提出替代方案,我將不勝感激。

UPD:我無法插入,因為我使用automap_base()而不是declarative_base()實例化了一個基礎。 現在我可以 append,但是,重復的條目確實是一個問題:

sqlalchemy.exc.IntegrityError: (pymysql.err.IntegrityError) (1062, "Duplicate entry 'twitter.com' for key 'url'")
[SQL: INSERT INTO `right` (url) VALUES (%(url)s)]
[parameters: {'url': 'twitter.com'}]
(Background on this error at: https://sqlalche.me/e/14/gkpj)

首先,如果您使用正確的域名而不是: right , left , child , children會更容易調試。 我知道這是文檔的副本,但是文檔是通用的,而您的案例是特定的。 您的代碼將更具可讀性。

為避免重復,您應該在插入該記錄之前檢查已經存在( Documents具有唯一的text_idLinks具有唯一的url )。

for row in data:
    d = session.query(Document).filter_by(text_id=row['id']).first()
    if not d:
        d = Document(text_id=row['id'])
    link = session.query(Links).filter_by(url=row['url']).first():
    if not link:
        link = Links(url=row['url'])
    a = Association(child=link)
    d.children.append(a)
    session.add(d)
    session.flush()
session.commit()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM