Настройка / вставка в базу данных "Многие ко многим" с помощью Python, SQLAlchemy, Sqlite

StackOverflow https://stackoverflow.com/questions/1403084

Вопрос

Я изучаю Python, и в качестве первого проекта беру RSS-каналы Twitter, анализирую данные и вставляю их в базу данных sqlite.Мне удалось успешно проанализировать каждую запись канала в Содержание переменная (например, "Вы должны покупать дешево ..."), a url - адрес переменная (например, u'http://bit.ly/HbFwL'), и a хэштег список (например, #акции', u'#фондовый рынок', u'#финансы', u'#деньги', u'#mkt']).Мне также удалось вставить эти три фрагмента информации в три отдельных столбца в таблице sqlite "RSSEntries", где каждая строка представляет собой отдельную rss-запись / твит.

Однако я хочу настроить базу данных, в которой существует отношение "многие ко многим" между отдельными записями rss-канала (т. Е. отдельными твитами) и хэштегами, которые связаны с каждой записью.Итак, я настроил следующие таблицы, используя sqlalchemy (первая таблица просто включает URL-адреса rss-каналов Twitterers, которые я хочу загрузить и проанализировать):

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, используя следующий код (сокращенно где ...)

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

Теперь, вот главный вопрос.Как мне вставить данные в метка подачи и название тега столы?Это настоящий камень преткновения для меня, поскольку для начала хастхаг переменная в настоящее время представляет собой список, и каждая запись ленты может содержать от 0 до, скажем, 6 хэштегов.Я знаю, как вставить весь список в один столбец, но не знаю, как вставить только элементы списка в отдельные столбцы (или, в данном примере, строки).Еще большим камнем преткновения является общий вопрос о том, как вставить отдельные хэштеги в название тега таблицу, когда имя тега может использоваться во множестве различных записей ленты, а затем как правильно отобразить "ассоциации" в метка подачи таблица.

Короче говоря, я точно знаю, как должна выглядеть каждая из таблиц, когда все они будут готовы, но я понятия не имею, как написать код для получения данных в название тега и метка подачи таблицы.Вся система "многие ко многим" для меня в новинку.

Мне действительно понадобилась бы ваша помощь в этом.Заранее благодарю за любые предложения.

-Грег

P.S.- Редактировать - Благодаря замечательным предложениям Антса Аасмы я смог почти заставьте все это сработать.В частности, 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 взял часть "entry_id", я попытался заменить ее на "entries.id", думая, что это может вставить "id" из таблицы "entries".Однако в этом случае я получаю эту ошибку:

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'

Я не совсем уверен, в чем проблема, и я действительно не понимаю, куда вписывается часть "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])
Это было полезно?

Решение

Во-первых, вы должны использовать SQLAlchemy SQL builder для вставок, чтобы дать 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]

Затем просто вставьте соответствующий идентификатор в feedtag_table.Вы можете использовать поддержку executemany, передав список dicts методу execute.

conn.execute(feedtag_table.insert(),
    [{'feedid': entry_id, 'tagid': tag_ids[tag]} for tag in hashtags])
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top