Skip to content

Commit 626ed97

Browse files
authored
Merge pull request #94 from realpython/python-sqlite-sqlalchemy
Adding the example program files that go along with the python-sqlite…
2 parents 0471be2 + 6208619 commit 626ed97

File tree

29 files changed

+1425
-0
lines changed

29 files changed

+1425
-0
lines changed

python-sqlite-sqlalchemy/README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Python / Sqlite /SqlAlchemy article
2+
3+
This repository contains the content and example code
4+
for the python/sqlite/sqlaclchemy article I'm writing
5+
for Real Python.
6+
7+
This project was built using Python 3.8.0
8+
9+
## Installing The Project
10+
11+
From the main folder take the following steps:
12+
13+
* Install a Python virtual environment for this project
14+
* Activate the virtual environment
15+
* Install the project:
16+
17+
```shell script
18+
python -m pip install -e .
19+
```
20+

python-sqlite-sqlalchemy/project/__init__.py

Whitespace-only changes.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# Build Files Used By The Examples
2+
3+
The code in this directory builds the various data files used
4+
by the example programs. There are three build programs:
5+
6+
* build_temp_data_csv.py
7+
* build_temp_data_sqlite.py
8+
* build_author_book_publisher_sqlite.py
9+
10+
## Build the Temperature CSV File
11+
12+
The build_temp_data_csv.py file builds a CSV data file
13+
(temp_data.csv) in the data directory
14+
containing temperature samples taken by students in a class.
15+
The top row contains the labels, the students name followed
16+
by a date value for each Wednesday of the week for a year.
17+
18+
It then creates data for each sample based on a table of
19+
temperature data, +/- 10 to make the data look variable
20+
and reasonable.
21+
22+
## Build the Temperature Database File
23+
24+
The build_temp_data_sqlite.py file builds a Sqlite database
25+
from the previously created temp_data.csv file called
26+
temp_data.db in the data directory.
27+
28+
## Build the Author / Book / Publisher Database File
29+
30+
The build_author_book_publisher_sqlite.py file builds
31+
a database from the data/author_book_publisher.csv file.
32+
This database contains the tables necessary to describe
33+
the data and the relationships between the data necessary
34+
for the examples.
35+
36+
## Directory Structure
37+
38+
The directory structure is set up in such a way the
39+
build programs (as well as the examples) can find the
40+
data files needed for each one.
41+
42+
## Executing the Programs
43+
44+
* Activate your Python virtualenv
45+
* cd into the build/code directory
46+
* python build_temp_data_csv.py - builds the csv data file
47+
* python build_temp_data_sqlite.py - builds the temperature data from the csv file
48+
* python build_author_book_publisher_sqlite.py - builds the author_book_publisher.db database file
49+
50+
51+
52+
53+

python-sqlite-sqlalchemy/project/build_data/__init__.py

Whitespace-only changes.
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
"""
2+
This program builds the author_book_publisher Sqlite database from the
3+
author_book_publisher.csv file.
4+
"""
5+
6+
import os
7+
import csv
8+
from pkg_resources import resource_filename
9+
from sqlalchemy import create_engine
10+
from sqlalchemy.orm import sessionmaker
11+
from project.modules.models import Base
12+
from project.modules.models import Author
13+
from project.modules.models import Book
14+
from project.modules.models import Publisher
15+
16+
17+
def get_author_book_publisher_data(filepath):
18+
"""
19+
This function gets the data from the csv file
20+
"""
21+
with open(filepath) as csvfile:
22+
csv_reader = csv.DictReader(csvfile)
23+
data = [row for row in csv_reader]
24+
return data
25+
26+
27+
def populate_database(session, author_book_publisher_data):
28+
# insert the data
29+
for row in author_book_publisher_data:
30+
31+
author = (
32+
session.query(Author)
33+
.filter(Author.lname == row["lname"])
34+
.one_or_none()
35+
)
36+
if author is None:
37+
author = Author(fname=row["fname"], lname=row["lname"])
38+
session.add(author)
39+
40+
book = (
41+
session.query(Book)
42+
.filter(Book.title == row["title"])
43+
.one_or_none()
44+
)
45+
if book is None:
46+
book = Book(title=row["title"])
47+
session.add(book)
48+
49+
publisher = (
50+
session.query(Publisher)
51+
.filter(Publisher.name == row["publisher"])
52+
.one_or_none()
53+
)
54+
if publisher is None:
55+
publisher = Publisher(name=row["publisher"])
56+
session.add(publisher)
57+
58+
# add the items to the relationships
59+
author.books.append(book)
60+
author.publishers.append(publisher)
61+
publisher.authors.append(author)
62+
publisher.books.append(book)
63+
session.commit()
64+
65+
session.close()
66+
67+
68+
def main():
69+
print("starting")
70+
71+
# get the author/book/publisher data into a dictionary structure
72+
csv_filepath = resource_filename(
73+
"project.data", "author_book_publisher.csv"
74+
)
75+
author_book_publisher_data = get_author_book_publisher_data(csv_filepath)
76+
77+
# get the filepath to the database file
78+
sqlite_filepath = resource_filename(
79+
"project.data", "author_book_publisher.db"
80+
)
81+
82+
# does the database exist?
83+
if os.path.exists(sqlite_filepath):
84+
os.remove(sqlite_filepath)
85+
86+
# create the database
87+
engine = create_engine(f"sqlite:///{sqlite_filepath}")
88+
Base.metadata.create_all(engine)
89+
Session = sessionmaker()
90+
Session.configure(bind=engine)
91+
session = Session()
92+
populate_database(session, author_book_publisher_data)
93+
94+
print("finished")
95+
96+
97+
if __name__ == "__main__":
98+
main()
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import csv
2+
import datetime
3+
from random import randint
4+
from pkg_resources import resource_filename
5+
6+
7+
start_date = datetime.datetime.strptime("2019-01-02", "%Y-%m-%d")
8+
9+
students = [
10+
"John",
11+
"Mary",
12+
"Susan",
13+
"Doug",
14+
"Andrew",
15+
"George",
16+
"Martha",
17+
"Paul",
18+
"Helen",
19+
]
20+
21+
temperature_data = [
22+
10,
23+
12,
24+
16,
25+
23,
26+
13,
27+
12,
28+
14,
29+
22,
30+
25,
31+
28,
32+
32,
33+
33,
34+
37,
35+
36,
36+
35,
37+
40,
38+
44,
39+
45,
40+
50,
41+
52,
42+
58,
43+
60,
44+
66,
45+
70,
46+
70,
47+
72,
48+
78,
49+
80,
50+
81,
51+
82,
52+
85,
53+
88,
54+
90,
55+
87,
56+
90,
57+
85,
58+
82,
59+
81,
60+
78,
61+
75,
62+
72,
63+
72,
64+
70,
65+
63,
66+
65,
67+
62,
68+
60,
69+
45,
70+
40,
71+
37,
72+
30,
73+
28,
74+
]
75+
76+
77+
def offset_temp(temperature):
78+
"""
79+
This function modifies the temperature +/- a random
80+
amount up to 10
81+
:param temperature: temperature to modify
82+
:return: modified temperature
83+
"""
84+
return temperature + randint(-10, 10)
85+
86+
87+
def main():
88+
# create the CSV file
89+
csv_filepath = resource_filename("project.data", "temp_data.csv")
90+
91+
with open(csv_filepath, "w") as data_fh:
92+
93+
# create the writer
94+
csv_writer = csv.writer(data_fh)
95+
96+
# write the header
97+
header = ["name"]
98+
for week in range(0, 52):
99+
current_date = start_date + datetime.timedelta(days=week * 7)
100+
header.append(current_date.strftime("%Y-%m-%d"))
101+
csv_writer.writerow(header)
102+
103+
# iterate through the students and write their data
104+
for student in students:
105+
data = [student]
106+
# iterate through the weeks
107+
for week in range(0, 52):
108+
data.append(offset_temp(temperature_data[week]))
109+
110+
csv_writer.writerow(data)
111+
112+
113+
if __name__ == "__main__":
114+
main()
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
"""
2+
This program gathers information from the temp_data.db file about temperature
3+
"""
4+
5+
import os
6+
import csv
7+
from pkg_resources import resource_filename
8+
from datetime import datetime
9+
from sqlalchemy import create_engine
10+
from sqlalchemy import Column, Integer, String, Date, Float
11+
from sqlalchemy.orm import sessionmaker
12+
from sqlalchemy.ext.declarative import declarative_base
13+
14+
15+
Base = declarative_base()
16+
17+
18+
class TemperatureData(Base):
19+
__tablename__ = "temperature_data"
20+
temperature_data_id = Column(Integer, primary_key=True)
21+
name = Column(String, nullable=False)
22+
date = Column(Date, nullable=False)
23+
value = Column(Float, nullable=False)
24+
25+
26+
def get_temperature_data(filepath):
27+
"""
28+
This function gets the temperature data from the csv file
29+
"""
30+
with open(filepath) as csvfile:
31+
csv_reader = csv.DictReader(csvfile)
32+
data = {row["name"]: row for row in csv_reader}
33+
for value in data.values():
34+
value.pop("name")
35+
return data
36+
37+
38+
def populate_database(session, temperature_data):
39+
# insert the data
40+
for student, data in temperature_data.items():
41+
for date, value in data.items():
42+
temp_data = TemperatureData(
43+
name=student,
44+
date=datetime.strptime(date, "%Y-%m-%d").date(),
45+
value=value,
46+
)
47+
session.add(temp_data)
48+
session.commit()
49+
session.close()
50+
51+
52+
def main():
53+
print("starting")
54+
55+
# get the temperature data into a dictionary structure
56+
csv_filepath = resource_filename("project.data", "temp_data.csv")
57+
temperature_data = get_temperature_data(csv_filepath)
58+
59+
# get the filepath to the database file
60+
sqlite_filepath = resource_filename("project.data", "temp_data.db")
61+
62+
# does the database exist?
63+
if os.path.exists(sqlite_filepath):
64+
os.remove(sqlite_filepath)
65+
66+
# create and populate the sqlite database
67+
engine = create_engine(f"sqlite:///{sqlite_filepath}")
68+
Base.metadata.create_all(engine)
69+
Session = sessionmaker()
70+
Session.configure(bind=engine)
71+
session = Session()
72+
populate_database(session, temperature_data)
73+
74+
print("finished")
75+
76+
77+
if __name__ == "__main__":
78+
main()

python-sqlite-sqlalchemy/project/data/__init__.py

Whitespace-only changes.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
fname,lname,title,publisher
2+
Issac,Asimov,Foundation,Random House
3+
Pearl,Buck,The Good Earth,Random House
4+
Pearl,Buck,The Good Earth,Simon & Schuster
5+
Tom,Clancy,The Hunt For Red October,Berkley
6+
Tom,Clancy,Patriot Games,Simon & Schuster
7+
Stephen,King,It,Random House
8+
Stephen,King,It,Penguin Random House
9+
Stephen,King,Dead Zone,Random House
10+
Stephen,King,The Shinning,Penguin Random House
11+
John,Le Carre,"Tinker, Tailor, Solider, Spy: A George Smiley Novel",Berkley
12+
Alex,Michaelides,The Silent Patient,Simon & Schuster
13+
Carol,Shaben,Into The Abyss,Simon & Schuster
Binary file not shown.

0 commit comments

Comments
 (0)