使用Python,SQLALchemy,Sqlite设置/插入多对多数据库

Gre*_*ton 7 python sqlite many-to-many sqlalchemy insert

我正在学习Python,作为第一个项目,我正在使用Twitter RSS提要,解析数据,并将数据插入到sqlite数据库中.我已经能够成功地将每个feed条目解析为内容变量(例如,"你应该买低......"),一个url变量(例如,你' http://bit.ly/HbFwL '),以及标签列表(例如,#stocks',u'#stockmarket',u'#financial',u'#money',u'#mkt']).我也成功地将这三个信息插入到sqlite"RSSEntries"表中的三个单独的列中,其中每一行都是不同的rss条目/推文.

但是,我想建立一个数据库,其中各个RSS订阅源条目(即单个推文)与每个条目关联的主题标签之间存在多对多关系.所以,我使用sqlalchemy设置了下表(第一个表只包含我要下载和解析的Twitterers的RSS源):

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')),
)
Run Code Online (Sandbox Code Playgroud)

到目前为止,我已经能够使用以下代码成功地将三个主要信息输入到RSSEntries表中(缩写为......)

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))
Run Code Online (Sandbox Code Playgroud)

现在,这是一个很大的问题.如何将数据插入到feedtagtagname表中?这对我来说是一个真正的问题,因为启动hasthag变量当前是一个列表,每个feed条目可以包含0到6之间的任何位置,比方说6个hashtags.我知道如何将整个列表插入到单个列中,而不是如何将列表的元素插入到单独的列中(或者,在此示例中为行).一个更大的问题是如何在标记名可用于多个不同的提要条目时如何将单个主题标签插入标记名表,然后如何在" 标签"表中正确显示"关联" .

简而言之,我确切地知道每个表在完成后应该看起来如何,但我不知道如何编写代码以将数据放入标记名feedtag表中.整个"多对多"设置对我来说是新的.

我真的可以帮助你.在此先感谢您的任何建议.

-Greg

PS - 编辑 - 感谢Ants Aasma的出色建议,我几乎可以完成所有工作.具体来说,第一个和第二个建议的代码块现在工作正常,但我在实现第三个代码块时遇到问题.我收到以下错误:

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
Run Code Online (Sandbox Code Playgroud)

然后,因为我无法分辨Ants Aasma从哪里获得"entry_id"部分,我尝试用"entries.id"替换它,认为这可能会从"entries"表中插入"id".但是,在这种情况下,我收到此错误:

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'
Run Code Online (Sandbox Code Playgroud)

我不太确定问题出在哪里,而且我真的不明白"entry_id"部分的位置,所以我粘贴在所有相关的"插入"代码下面.有人可以帮我看看有什么不对吗?请注意,我也注意到我错误地调用了我的最后一个表"feedtag_table"而不是"entrytag_table"这与我最初声明的将各个订阅源条目与主题标签相关联的目标不匹配,而不是与主题标签相关.我已经纠正了上面的代码.

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])
Run Code Online (Sandbox Code Playgroud)

Ant*_*sma 4

首先,您应该使用 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]
Run Code Online (Sandbox Code Playgroud)

要将标签关联插入到您的模式中,您需要首先查找标签标识符并创建任何不存在的标识符:

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]
Run Code Online (Sandbox Code Playgroud)

然后只需将关联的 id 插入到feedtag_table. 您可以通过将字典列表传递给execute方法来使用executemany支持。

conn.execute(feedtag_table.insert(),
    [{'feedid': entry_id, 'tagid': tag_ids[tag]} for tag in hashtags])
Run Code Online (Sandbox Code Playgroud)

  • Entry_id 将是刚刚插入的条目的 if。您可以通过执行插入结果的last_inserted_ids()方法获取它。我更新了答案来表明这一点。 (2认同)