2010-07-17 4 views
11

J'essaie d'installer un site Web dans django qui permet à l'utilisateur d'envoyer des requêtes à une base de données contenant des informations sur leurs représentants au Parlement européen. J'ai les données dans un fichier .txt séparées par des virgules avec le format suivant:Remplissage d'une base de données SQLite3 à partir d'un fichier .txt avec 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....

Je veux remplir une base de données SQLite3 avec ces données, mais jusqu'à présent tous les tutoriels que j'ai trouvé que montrer comment faire cela par main. Puisque j'ai 736 observations dans le fichier, je ne veux pas vraiment faire ça.

Je suppose que c'est une question simple, mais je serais très reconnaissant si quelqu'un pouvait me montrer comment faire.

Thomas

Répondre

17

donc en supposant que votre models.py ressemble à quelque chose comme ceci:

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) 

Vous pouvez ensuite exécuter python manage.py shell et exécutez la commande suivante:

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

Et vous avez terminé.

Addendum (modifier) ​​

par la demande de Thomas, voici une explication de ce que **dict(zip(fields,row)) fait:

donc d'abord, fields contient une liste de noms de champs que nous avons défini, et row contient une liste de valeurs qui représente la ligne actuelle dans le fichier CSV.

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

Qu'est-ce que zip() fait est qu'il combine deux listes en une liste de paires d'articles dans les deux listes (comme une fermeture éclair); c'est-à-dire zip(['a','b,'c'], ['A','B','C']) renverra [('a','A'), ('b','B'), ('c','C')]. Dans notre cas:

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

La fonction dict() convertit simplement la liste des paires dans un dictionnaire.

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

Le ** est un moyen de convertir un dictionnaire dans une liste d'arguments mot-clé pour une fonction. Donc function(**{'key': 'value'}) est l'équivalent de function(key='value'). Ainsi, dans l'exemple en appelant create(**dict(zip(field, row))) est l'équivalent de:

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

Hope this efface les choses.

+3

Si vous chargez ceci dans Django, regardez certainement dans la solution d'Aram ici pour l'usage. Il profite des bits ORM de django pour vous, vous n'avez donc pas besoin de jouer directement avec le schéma. Pas grave si vous êtes à l'aise avec le schéma SQL, mais j'ai trouvé que cela facilitait beaucoup les choses. – heckj

+0

+1; c'est beaucoup plus simple! – bernie

+1

Merci pour la réponse Aram.J'apprends encore Python, alors pourriez-vous nous expliquer ce que fait la partie (** dict (zip (...)) de la dernière ligne? –

2

Vous pouvez lire les données à l'aide du module csv. Ensuite, vous pouvez créer une instruction SQL insert et utiliser la méthode executemany:

cursor.executemany(sql, rows) 

ou utilisez add_all si vous utilisez sqlalchemy.

0

Quelque chose comme ce qui suit devrait fonctionner: (non testé)

# 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

Salut Joschua, merci pour la réponse! Cependant, je continue à obtenir cette erreur lorsque vous utilisez votre exemple ci-dessus: > retraçage (le plus récent appel dernier): Fichier « /Users/thomasjensen/Documents/sql_test.py », ligne 13, dans c.execute (« » "insert dans MEP (Parlement, Nom, Pays, Party_Group, Home_Party, Position) valeurs (?,?,?,?,?,?)" "", * i.split (",")) TypeError: fonction prend au plus 2 arguments (162 donnés) –

+1

Il suffit de supprimer l'astérisque de début de '* i.split (", ")'. Cependant, le fait que le message d'erreur indique "162 [arguments] donnés" suggère qu'il y aura plus de problèmes à suivre. Je recommanderais fortement d'utiliser l'une des autres réponses actuellement sur cette page, qui utilisent tous la bibliothèque "csv", plutôt que de s'appuyer sur 'split (", ")', ce qui vous causera beaucoup de peine. –

+0

Ok, merci pour les conseils. –

4

Comme SiggyF dit et seulement un peu différemment que Joschua:

Créez un fichier texte avec votre schéma, par exemple:

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

Création de la table:

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

Utilisez module csv pour lire fichier avec les données à insérer:

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

Insérer des données:

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

Vérifiez que tout allait comme prévu:

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

Modifier:
Et puisque vous avez décodée (à unicode) sur l'entrée, vous devez être sûr coder en sortie.
Par exemple:

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

Salut Adam, merci pour la réponse élaborée! Chaque étape fonctionne, sauf lorsque je tente: c.executemany ("INSERT INTO politiciens VALUES (,,,,,)?????", To_db) Puis-je obtenir l'erreur suivante: ProgrammingError : Vous ne devez pas utiliser d'octets 8 bits sauf si vous utilisez un text_factory capable d'interpréter des octets 8 bits (comme text_factory = str). Il est fortement recommandé de simplement passer votre application aux chaînes Unicode. J'ai enregistré le fichier texte avec un encodage utf8, donc je n'ai aucune idée de ce qui se passe ici ... –

+0

@Thomas: De rien. J'ai mis à jour l'exemple pour gérer le décodage depuis utf-8, et j'ai aussi montré comment encoder en utf-8 en sortie. Bonne chance à vous. – bernie

+0

Merci Adam, pour un débutant, toute cette activité d'encodage peut être assez déroutante. –

2

Vous avez demandé ce que la ligne créer (** dict (zip (champs, ligne))) ont fait.

Je ne sais pas comment répondre directement à votre commentaire, je vais donc essayer de répondre ici.

zip prend plusieurs listes en tant qu'args et renvoie une liste de leurs éléments correspondants sous forme de tuples.

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

dict prend une liste de tuples à 2 éléments et retourne un dictionnaire qui met en correspondance le premier élément de chaque tuple (clé) avec son deuxième élément (valeur).

create est une fonction qui prend des arguments de mots-clés. Vous pouvez utiliser ** some_dictionary pour transmettre ce dictionnaire dans une fonction en tant qu'argument mot-clé.

créer (** { 'name': 'john', 'âge': 5}) => créer (name = 'john', age = 5)

+0

Merci pour l'explication Steve. –

Questions connexes