2009-09-10 12 views
7

Estoy aprendiendo Python, y como primer proyecto estoy tomando Twitter RSS, analizando los datos e insertando los datos en una base de datos sqlite. He sido capaz de analizar correctamente cada entrada de alimentación en un contenido variable (por ejemplo, "Usted debe comprar barato ..."), una variable deURL (por ejemplo, u 'http://bit.ly/HbFwL'), y una hashtag lista (por ejemplo, #stocks ', u' # stockmarket ', u' # finance ', u' # money ', u' # mkt ']). También he tenido éxito al insertar estas tres piezas de información en tres columnas separadas en una tabla sqlite "RSSEntries", donde cada fila es una entrada/tweet rss diferente.Configuración/Inserción en la base de datos Many-to-Many con Python, SQLALchemy, Sqlite

Sin embargo, deseo configurar una base de datos donde haya una relación muchos a muchos entre las entradas individuales de rss feed (es decir, tweets individuales) y los hashtags que están asociados con cada entrada. Por lo tanto, he creado las siguientes tablas usando sqlalchemy (la primera mesa sólo incluye las direcciones URL de los tuiteros rss feed que desea descargar y analizar):

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

Hasta ahora, he sido capaz de entrar con éxito solo las tres piezas principales de información en la tabla RSSEntries usando el siguiente código (abreviado donde ...)

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

Ahora, aquí está la gran pregunta. ¿Cómo inserto los datos en el feedtag y tagname tables? Este es un verdadero punto de fricción para mí, ya que para iniciar la variable hasthag se encuentra actualmente una lista, y cada entrada de feed podría contener entre 0 y, por ejemplo, 6 hashtags. Sé cómo insertar toda la lista en una sola columna, pero no cómo insertar solo los elementos de la lista en columnas separadas (o, en este ejemplo, filas). Un punto de fricción más grande es la cuestión general de cómo insertar los hashtags individuales en la tabla del nombre de tag cuando un nombre de etiqueta se puede usar en numerosas entradas de alimentación diferentes y cómo tener las "asociaciones" correctamente en la tabla feedtag .

En resumen, sé exactamente cómo cada una de las mesas debe buscar cuando están todas hechas, pero no tengo ni idea de cómo escribir el código para obtener los datos en el tagname y feedtag tablas. Toda la configuración de "muchos a muchos" es nueva para mí.

Realmente podría utilizar su ayuda en esto. Gracias de antemano por cualquier sugerencia.

-Greg

P.S. - Editar - Gracias a las excelentes sugerencias de Ants Aasma, he podido casi hacer que todo funcione. Específicamente, los bloques de código sugeridos primero y segundo ahora funcionan bien, pero tengo un problema al implementar el tercer bloque de código. Estoy consiguiendo el error siguiente:

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 

Entonces, porque no podía decir donde las hormigas Aasma obtuvo el papel "entrada_id" de, He intentado reemplazarlo con "entries.id", pensando que esto podría insertar el " id "de la tabla" entries ".Sin embargo, en ese caso, me sale este error:

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' 

No estoy muy seguro de dónde está el problema, y ​​no entiendo realmente donde la parte "entrada_id" encaja, por lo que he pegado en debajo de todo mi código de "inserción" relevante. ¿Alguien puede ayudarme a ver qué pasa? Tenga en cuenta que también me di cuenta de que estaba llamando incorrectamente a mi última tabla "feedtag_table" en lugar de "entrytag_table" Esto no coincidía con mi objetivo inicialmente establecido de relacionar las entradas individuales entradas con hashtags, en lugar de con feeds a hashtags. Desde entonces, he corregido el código anterior.

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

Respuesta

4

En primer lugar, se debe utilizar el constructor SQLAlchemy SQL para los insertos para dar SQLAlcehemy visión más clara de lo que está haciendo.

result = conn.execute(RSSEntries.insert(), {'feed_id': id, 'short_url': tinyurl, 
     'content': content, 'hashtags': hashtags, 'date': date}) 
entry_id = result.last_insert_ids()[0] 

Para insertar asociaciones de etiquetas a su esquema necesita al puño buscar sus identificadores de etiquetas y crear ninguna que no existen:

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] 

A continuación, basta con insertar los identificadores asociados a la feedtag_table. Puede usar el soporte executemany pasando una lista de dicts al método de ejecución.

conn.execute(feedtag_table.insert(), 
    [{'feedid': entry_id, 'tagid': tag_ids[tag]} for tag in hashtags]) 
+0

Gracias - eso es genial! He agregado correctamente en el primer bit, pero estoy teniendo un error de "nombre global 'seleccione' no está definido" cuando agrego el segundo bit. Supongo que es debido a dónde estoy poniendo el código. Intentaré editar mi pregunta anterior para mostrarte lo que he hecho hasta ahora, ¿así que quizás puedas detectar mi error? –

+0

Bien, descubrí el problema con el segundo bloque de código: ¡no había importado "seleccionar" desde sqlalchemy! Ahora, eso funciona genial. Solo estoy trabajando en ajustar el tercer bloque de código, algo funciona bastante bien. –

+0

Re: último comentario. Quise decir que algo NO está funcionando del todo bien. :) Entiendo la parte 'tagid' pero no de dónde viene la parte 'entry_id'? Esperaba que pudieras explicar eso? Pegaré en la sección correspondiente de "inserción" de mi código anterior. –

Cuestiones relacionadas