2010-07-17 25 views
11

Estoy intentando configurar un sitio web en django que permita al usuario enviar consultas a una base de datos que contenga información sobre sus representantes en el Parlamento Europeo. Tengo los datos en una coma separó archivo .txt con el siguiente formato:Rellenar una base de datos SQLite3 desde un archivo .txt con Python

Parliament, Name, Country, Party_Group, National_Party, Position

7, Marta Andreasen, United Kingdom, Europe of freedom and democracy Group, United Kingdom Independence Party, Member

etc....

Quiero llenar una base de datos SQLite3 con estos datos, pero hasta ahora todos los tutoriales que he encontrado sólo muestran cómo hacer esto mano. Como tengo 736 observaciones en el archivo, realmente no quiero hacer esto.

Sospecho que este es un asunto simple, pero estaría muy agradecido si alguien pudiera mostrarme cómo hacerlo.

Thomas

Respuesta

17

Así que asumiendo que su models.py se ve algo como esto:

class Representative(models.Model): 
    parliament = models.CharField(max_length=128) 
    name = models.CharField(max_length=128) 
    country = models.CharField(max_length=128) 
    party_group = models.CharField(max_length=128) 
    national_party = models.CharField(max_length=128) 
    position = models.CharField(max_length=128) 

continuación, puede ejecutar python manage.py shell y ejecute el siguiente:

import csv 
from your_app.models import Representative 
# If you're using different field names, change this list accordingly. 
# The order must also match the column order in the CSV file. 
fields = ['parliament', 'name', 'country', 'party_group', 'national_party', 'position'] 
for row in csv.reader(open('your_file.csv')): 
    Representative.objects.create(**dict(zip(fields, row))) 

Y listo.

Adición (editar)

solicitud

de Per Thomas, aquí es una explicación de lo **dict(zip(fields,row)) hace:

Así que al principio, fields contiene una lista de nombres de campo que hemos definido, y row contiene una lista de valores que representa la fila actual en el archivo CSV.

fields = ['parliament', 'name', 'country', ...] 
row = ['7', 'Marta Andreasen', 'United Kingdom', ...] 

Lo zip() hace es que combina dos listas en una lista de pares de elementos de ambas listas (como una cremallera); es decir, zip(['a','b,'c'], ['A','B','C']) devolverá [('a','A'), ('b','B'), ('c','C')]. Por lo que en nuestro caso:

>>> zip(fields, row) 
[('parliament', '7'), ('name', 'Marta Andreasen'), ('country', 'United Kingdom'), ...] 

La función dict() simplemente convierte la lista de pares en un diccionario.

>>> dict(zip(fields, row)) 
{'parliament': '7', 'name': 'Marta Andreasen', 'country': 'United Kingdom', ...} 

El ** es una manera de convertir un diccionario en una lista de argumentos de palabra clave para una función. Entonces, function(**{'key': 'value'}) es el equivalente a function(key='value'). Así en el ejemplo fuera, llamando create(**dict(zip(field, row))) es el equivalente a:

create(parliament='7', name='Marta Andreasen', country='United Kingdom', ...) 

Espero que esto aclare las cosas.

+3

Si está cargando esto en Django, definitivamente mire la solución de Aram aquí para usarla. Se está aprovechando de los bits de ORM de django para ti, por lo que no es necesario que te metas con el esquema directamente. No es gran cosa si te sientes cómodo con el esquema de SQL, pero descubrí que hizo las cosas mucho más fáciles. – heckj

+0

+1; esto es mucho mas simple! – bernie

+1

Gracias por la respuesta Aram.Todavía estoy aprendiendo Python, ¿podrías explicar lo que hace la parte (** dict (zip (...)) de la última línea? –

2

Usted puede leer los datos utilizando el módulo csv. A continuación, puede crear una instrucción SQL de inserción y utilizar el método executemany:

cursor.executemany(sql, rows) 

o utilizar add_all si utiliza sqlalchemy.

0

algo como lo siguiente debería funcionar: (no probado)

# Open database (will be created if not exists) 
conn = sqlite3.connect('/path/to/your_file.db') 

c = conn.cursor() 

# Create table 
c.execute('''create table representatives 
(parliament text, name text, country text, party_group text, national_party text, position text)''') 

f = open("thefile.txt") 
for i in f.readlines(): 
    # Insert a row of data 
    c.execute("""insert into representatives 
       values (?,?,?,?,?,?)""", *i.split(", ")) # *i.split(", ") does unpack the list as arguments 

# Save (commit) the changes 
conn.commit() 

# We can also close the cursor if we are done with it 
c.close() 
+0

Hola Joschua, gracias por la respuesta! Sin embargo me siguen dando este error cuando se utiliza el ejemplo anterior: > Rastreo (llamada más reciente pasado): Archivo "/Users/thomasjensen/Documents/sql_test.py", línea 13, en c.execute ("" "insertar en valores MEP (Parlamento, Nombre, País, Party_Group, Home_Party, Posición) (?,?,?,?,?,?)" "", * i.split (",")) TypeError: la función toma como máximo 2 argumentos (162 proporcionados) –

+1

Simplemente elimine el asterisco inicial de '* i.split (", ")'. Sin embargo, el hecho de que el mensaje de error diga "162 [argumentos] dados" sugiere que habrá más problemas a seguir. También recomendaría encarecidamente utilizar cualquiera de las otras respuestas actualmente en esta página, que usan la biblioteca "csv", en lugar de depender de "split" (",") ', lo que le causará mucha pena. –

+0

Ok, gracias por el consejo. –

4

Como dice SiggyF y sólo ligeramente diferente que Joschua:

Crear un archivo de texto con su esquema, por ejemplo:

 
CREATE TABLE politicians (
    Parliament text, 
    Name text, 
    Country text, 
    Party_Group text, 
    National_Party text, 
    Position text 
); 

Crear una tabla:

>>> import csv, sqlite3 
>>> conn = sqlite3.connect('my.db') 
>>> c = conn.cursor() 
>>> with open('myschema.sql') as f:   # read in schema file 
... schema = f.read() 
... 
>>> c.execute(schema)       # create table per schema 
<sqlite3.Cursor object at 0x1392f50> 
>>> conn.commit()        # commit table creation 

Uso módulo csv para leer archivo con datos a insertar:

>>> csv_reader = csv.reader(open('myfile.txt'), skipinitialspace=True) 
>>> csv_reader.next()       # skip the first line in the file 
['Parliament', 'Name', 'Country', ... 

# put all data in a tuple 
# edit: decoding from utf-8 file to unicode 
>>> to_db = tuple([i.decode('utf-8') for i in line] for line in csv_reader) 
>>> to_db          # this will be inserted into table 
[(u'7', u'Marta Andreasen', u'United Kingdom', ... 
datos

Insertar:

>>> c.executemany("INSERT INTO politicians VALUES (?,?,?,?,?,?);", to_db) 
<sqlite3.Cursor object at 0x1392f50> 
>>> conn.commit() 

Compruebe que todo ha ido como se esperaba:

>>> c.execute('SELECT * FROM politicians').fetchall() 
[(u'7', u'Marta Andreasen', u'United Kingdom', ... 

Editar:
Y puesto que ya has descodificada (a Unicode) en la entrada, tiene que estar seguro para codificar en la salida.
Por ejemplo:

with open('encoded_output.txt', 'w') as f: 
    for row in c.execute('SELECT * FROM politicians').fetchall(): 
    for col in row: 
     f.write(col.encode('utf-8')) 
     f.write('\n') 
+0

Hola Adam, gracias por la respuesta elaborada! Cada paso funciona, excepto cuando intento: c.executemany ("INSERT INTO VALORES políticos (,,,,,);??????", To_db) Entonces me sale el siguiente error: ProgrammingError : No debe usar cadenas de bytes de 8 bits a menos que use text_factory que pueda interpretar cadenas de bytes de 8 bits (como text_factory = str). Es muy recomendable que simplemente cambie su aplicación a cadenas Unicode. He guardado el archivo de texto con una codificación utf8, así que no tengo idea de lo que está sucediendo aquí ... –

+0

@Thomas: De nada. Actualicé el ejemplo para manejar la decodificación de utf-8, y también se mostró cómo codificar de vuelta a utf-8 en la salida. La mejor de las suertes para ti. – bernie

+0

Gracias Adam, para un principiante todo este negocio de codificación puede ser bastante confuso. –

2

Se preguntó lo que hizo el (** dict ((campos, fila)) zip) línea de crear.

No sé cómo responder directamente a su comentario, así que intentaré responderlo aquí.

zip toma múltiples listas como args y devuelve una lista de sus elementos correspondientes como tuplas.

zip (lista1, list2) => [(lista1 [0], list2 [0]), (lista1 [1], list2 [1]), ....]

dict toma una lista de tuplas de 2 elementos y devuelve un diccionario que correlaciona el primer elemento (clave) de cada tupla con su segundo elemento (valor).

crear es una función que toma argumentos de palabra clave. Puede usar ** some_dictionary para pasar ese diccionario a una función como argumentos de palabra clave.

crear (** { 'nombre': 'John', 'edad': 5}) => crear (name = 'John', edad = 5)

+0

Gracias por la explicación Steve. –

Cuestiones relacionadas