Python、SQLALchemy、Sqliteを使用した多対多データベースのセットアップ/挿入
-
05-07-2019 - |
質問
私はPythonを学んでおり、最初のプロジェクトとしてTwitterのRSSフィードを取得し、データを解析して、sqliteデータベースにデータを挿入しています。各フィードエントリを content 変数(例:"低価格で購入する必要があります...")、 url 変数(例: u ' http://bit.ly/HbFwL ')、およびハッシュタグリスト(例:#stocks'、u '#stockmarket'、u '#finance'、u '#money'、u '#mkt'])。また、これら3つの情報をsqliteの「RSSEntries」の3つの個別の列に挿入することに成功しています。テーブル。各行は異なるrssエントリ/ツイートです。
ただし、個々のrssフィードエントリ(つまり、個々のツイート)と各エントリに関連付けられているハッシュタグとの間に多対多の関係があるデータベースをセットアップしたいと思います。そこで、sqlalchemyを使用して次のテーブルを設定しました(最初のテーブルには、ダウンロードして解析したいTwitterのrssフィードURLが含まれています):
RSSFeeds = schema.Table('feeds', metadata,
schema.Column('id', types.Integer,
schema.Sequence('feeds_seq_id', optional=True), primary_key=True),
schema.Column('url', types.VARCHAR(1000), default=u''),
)
RSSEntries = schema.Table('entries', metadata,
schema.Column('id', types.Integer,
schema.Sequence('entries_seq_id', optional=True), primary_key=True),
schema.Column('feed_id', types.Integer, schema.ForeignKey('feeds.id')),
schema.Column('short_url', types.VARCHAR(1000), default=u''),
schema.Column('content', types.Text(), nullable=False),
schema.Column('hashtags', types.Unicode(255)),
)
tag_table = schema.Table('tag', metadata,
schema.Column('id', types.Integer,
schema.Sequence('tag_seq_id', optional=True), primary_key=True),
schema.Column('tagname', types.Unicode(20), nullable=False, unique=True)
)
entrytag_table = schema.Table('entrytag', metadata,
schema.Column('id', types.Integer,
schema.Sequence('entrytag_seq_id', optional=True), primary_key=True),
schema.Column('entryid', types.Integer, schema.ForeignKey('entries.id')),
schema.Column('tagid', types.Integer, schema.ForeignKey('tag.id')),
)
これまでのところ、次のコードを使用してRSSEntriesテーブルに3つの主要な情報だけを正常に入力することができました(where ...の略)
engine = create_engine('sqlite:///test.sqlite', echo=True)
conn = engine.connect()
.........
conn.execute('INSERT INTO entries (feed_id, short_url, content, hashtags) VALUES
(?,?,?,?)', (id, tinyurl, content, hashtags))
今、ここに大きな質問があります。 feedtag および tagname テーブルにデータを挿入するにはどうすればよいですか? hasthag 変数を開始することは現在リストであり、各フィードエントリには0〜6個のハッシュタグが含まれる可能性があるため、これは私にとって本当のこだわりです。リスト全体を単一の列に挿入する方法は知っていますが、リストの要素だけを別の列(またはこの例では行)に挿入する方法は知っていません。より大きなこだわりは、タグ名をさまざまなフィードエントリで使用できる場合に、個々のハッシュタグをタグ名テーブルに挿入する方法と、「アソシエーション」を持つ方法の一般的な問題です。 feedtag テーブルに適切に表示されます。
簡単に言えば、すべてのテーブルが完了したときに各テーブルがどのように見えるかを正確に知っていますが、データを tagname および feedtag テーブル。 「多対多」全体セットアップは私にとって新しいものです。
これについてあなたの助けを本当に使うことができます。提案を事前に感謝します。
-Greg
PS -編集-Ants Aasmaの優れた提案のおかげで、すべての機能をほぼ取得できました。具体的には、1番目と2番目に提案されたコードブロックは正常に動作しますが、3番目のコードブロックの実装に問題があります。次のエラーが表示されます:
Traceback (most recent call last):
File "RSS_sqlalchemy.py", line 242, in <module>
store_feed_items(id, entries)
File "RSS_sqlalchemy.py", line 196, in store_feed_items
[{'feedid': entry_id, 'tagid': tag_ids[tag]} for tag in hashtags2])
NameError: global name 'entry_id' is not defined
その後、Ants Aasmaが&quot; entry_id&quot;を取得した場所がわからなかったため、一部から、これを&quot; entries.id&quot;に置き換えてみました。これにより&quot; id&quot; 「エントリ」から表。ただし、その場合、次のエラーが表示されます。
Traceback (most recent call last):
File "RSS_sqlalchemy.py", line 242, in <module>
store_feed_items(id, entries)
File "RSS_sqlalchemy.py", line 196, in store_feed_items
[{'feedid': entries.id, 'tagid': tag_ids[tag]} for tag in hashtags2])
AttributeError: 'list' object has no attribute 'id'
問題の場所がよくわかりません。&quot; entry_id&quot;がどこにあるのか本当にわかりません。一部が収まるので、関連するすべての「挿入」を以下に貼り付けました。コード。誰かが私に何が間違っているのかを助けてくれますか?また、最後のテーブル&quot; feedtag_table&quot;を誤って呼び出していたことにも注意してください。 &quot; entrytag_table&quot;の代わりにこれは、フィードをハッシュタグに関連付けるのではなく、個々のフィードエントリをハッシュタグに関連付けるという当初述べた目標とは一致しませんでした。その後、上記のコードを修正しました。
feeds = conn.execute('SELECT id, url FROM feeds').fetchall()
def store_feed_items(id, items):
""" Takes a feed_id and a list of items and stored them in the DB """
for entry in items:
conn.execute('SELECT id from entries WHERE short_url=?', (entry.link,))
s = unicode(entry.summary)
test = s.split()
tinyurl2 = [i for i in test if i.startswith('http://')]
hashtags2 = [i for i in s.split() if i.startswith('#')]
content2 = ' '.join(i for i in s.split() if i not in tinyurl2+hashtags2)
content = unicode(content2)
tinyurl = unicode(tinyurl2)
hashtags = unicode (hashtags2)
date = strftime("%Y-%m-%d %H:%M:%S",entry.updated_parsed)
conn.execute(RSSEntries.insert(), {'feed_id': id, 'short_url': tinyurl,
'content': content, 'hashtags': hashtags, 'date': date})
tags = tag_table
tag_id_query = select([tags.c.tagname, tags.c.id], tags.c.tagname.in_(hashtags))
tag_ids = dict(conn.execute(tag_id_query).fetchall())
for tag in hashtags:
if tag not in tag_ids:
result = conn.execute(tags.insert(), {'tagname': tag})
tag_ids[tag] = result.last_inserted_ids()[0]
conn.execute(entrytag_table.insert(),
[{'feedid': id, 'tagid': tag_ids[tag]} for tag in hashtags2])
解決
最初に、挿入にSQLAlchemy SQLビルダーを使用して、SQLAlcehemyが実行していることについてより多くの洞察を得る必要があります。
result = conn.execute(RSSEntries.insert(), {'feed_id': id, 'short_url': tinyurl,
'content': content, 'hashtags': hashtags, 'date': date})
entry_id = result.last_insert_ids()[0]
タグの関連付けをスキーマに挿入するには、最初にタグ識別子を検索し、存在しないものを作成する必要があります。
tags = tag_table
tag_id_query = select([tags.c.tagname, tags.c.id], tags.c.tagname.in_(hashtags))
tag_ids = dict(conn.execute(tag_id_query).fetchall())
for tag in hashtags:
if tag not in tag_ids:
result = conn.execute(tags.insert(), {'tagname': tag})
tag_ids[tag] = result.last_inserted_ids()[0]
次に、関連付けられたIDを feedtag_table
に挿入します。 dictのリストをexecuteメソッドに渡すことで、executemanyサポートを使用できます。
conn.execute(feedtag_table.insert(),
[{'feedid': entry_id, 'tagid': tag_ids[tag]} for tag in hashtags])