[Tutor] How is database creation normally handled?
Peter Otten
__peter__ at web.de
Sun Sep 10 05:28:37 EDT 2017
boB Stepp wrote:
> While reading about SQL, SQLite and the Python module sqlite3, it
> appears that I could (1) have a program check for the existence of the
> program's database, and if not found, create it, make the tables,
> etc.; or,
I'm only a casual user of sqlite, and therefore I prefer to have the table
definitions in the script. It's as easy writing
create table if not exists foo ...
instead of
create table foo ...
This also allows you to easily add tables later on.
> (2) create the database separately and include it with the
> program. What are the pros and cons of each approach? (1) to me
> looks only helpful if I wish to write a program that might want to
> allow the user to have multiple databases.
Even if the user needs only a single db you should make that configurable to
allow for testing.
> But this sounds like a lot
> of extra coding and checking to make it work well.
I don't think so. You need the database schema, and once you have that it
doesn't matter if you build one or 1000 databases from it.
> But if I only wish
> to have a single database, then (2) sounds like the approach to use.
> I would create the database, populate it with the needed empty tables
> with the desired fields, making it ready to use by the program's user.
>
> Not having any experience in the database arena, I'm not even sure I
> know how to properly think about this.
Here's a little demo script to get you going. There's only a single table,
but the principle works with any number of tables and indices.
$ ls
sqlitedemo.py
$ cat sqlitedemo.py
#!/usr/bin/env python3
import sqlite3
from itertools import chain
from contextlib import closing
def ensure_db(filename):
db = sqlite3.connect(filename)
with closing(db.cursor()) as cursor:
cursor.execute(
"create table if not exists addresses (name, email);"
)
return db
def insert_action(args, parser):
with ensure_db(args.database) as db:
with closing(db.cursor()) as cursor:
cursor.execute(
"insert into addresses values (?, ?);",
(args.name, args.email)
)
def fix_none(row):
return [
"NULL"if value is None else value
for value in row
]
def show_action(args, parser):
with ensure_db(args.database) as db:
with closing(db.cursor()) as cursor:
cursor.execute("select * from addresses order by name")
fieldnames = [
column_desc[0]
for column_desc in cursor.description
]
template = " | ".join(("{:20}",)*len(fieldnames))
separator = ["-" * 20] * len(fieldnames)
for row in chain([fieldnames, separator], cursor):
print(template.format(*fix_none(row)))
def main():
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-d", "--database", default="default.sqlite")
sub = parser.add_subparsers()
insert = sub.add_parser("insert")
insert.add_argument("name")
insert.add_argument("email")
insert.set_defaults(func=insert_action)
show = sub.add_parser("show")
show.set_defaults(func=show_action)
args = parser.parse_args()
args.func(args, parser)
if __name__ == "__main__":
main()
$ ./sqlitedemo.py show
name | email
-------------------- | --------------------
$ ls
default.sqlite sqlitedemo.py
$ ./sqlitedemo.py insert jim jim at example.com
$ ./sqlitedemo.py insert sue sue at elsewhere.org
$ ./sqlitedemo.py show
name | email
-------------------- | --------------------
jim | jim at example.com
sue | sue at elsewhere.org
$ ./sqlitedemo.py -d otherdb insert peter peter at uknowwhere
$ ls
default.sqlite otherdb sqlitedemo.py
$ ./sqlitedemo.py -d otherdb show
name | email
-------------------- | --------------------
peter | peter at uknowwhere
PS: I don't know if it makes sense to close the cursors, I just thought it
looked clean when I added it to ensure_db() and ended up adding it
everywhere.
More information about the Tutor
mailing list