Recently, I read a book called "Make with Nuxt.js and Python! Introduction to slimy AI application development", and the book is a fairly new python web site. Since the framework responder is introduced, I would like to make a simple website after studying various things with interest.
The target site this time is a site where you can connect to a SQL database to view, add, update, and delete data.
The database uses sqlite3, which is the simplest.
Besides the book, I read many articles about how to use responder and sqlite3.
responder -Simple chat app with Responder + WebSocket -Build a web application with Python + Responder. -First Responder (Python's next-generation web framework) -About the cool Python Web Framework "responder" for humans, and the author Kenneth Reitz
sqlite3 -SQLite in Python
These articles have been very helpful, so I'll omit the basic usage here.
The database should be SQLite for simplicity.
SQLite is not very suitable when creating an actual site, but unlike MySQL and PostgreSQL, SQLite does not need to be installed and is convenient because it is included from the beginning.
The only python modules used are mainly responder and sqlite3.
sqlite3 is a standard python module, so you only need to install responder.
Responder official website says to use pipenv, but you can easily install it with ordinary pip.
pip install responder
Create a simple website like this.
--Only one python file controls the site --Each page is made into a jinja2 template through responder --Only 3 pages ---- Index page where you can view and download all data ---- Page where you can edit the data ---- Page when an error occurs --The style sheet is also a simple css file, but prepare it for the time being --Input and edit data with forms and input --javascript doesn't come into play --A table with only two columns in the database
Column name | Data type | |
---|---|---|
name | namae | text |
level | lv | integer |
My goal this time is just to make sure I can connect to the database and interact with it, so for the sake of simplicity I'll make it a table with only two columns.
If this table is SQL code
create table kyara (namae text,lv integer, primary key (namae))
The site is all just made up of these 5 files.
The .html file is a jinja2 template. I've never used jinja2 before, but it's a bit like a django template.
By the way, as you can see, the name of the file is " [A Certain Magical Index](https://ja.wikipedia.org/wiki/ A Certain Magical Index) ".
│- majutsu.py server executable code
│─ index.html index page
│- toaru.html data display and editing page
│- no.html Page that appears when something wrong happens
└─ librorum
└─prohibitorum.css stylesheet
I think that there is not much problem even if the OS and the version of python and responder are different, but I will write the environment when I tried this time.
--Mac OS 10.15.4 [Catalina](https://ja.wikipedia.org/wiki/ I have reincarnated as a villain daughter who has only the ruin flag of the maiden game ...)
Next is a description of the code in each file.
html file of jinja2 template
index.html
First, the index page.
<head>
<meta charset="utf-8">
<title>INDEX of a certain site</title>
<link rel="stylesheet" href="/librorum/prohibitorum.css" type="text/css" media="all">
</head>
<body>
<h3>A certain sqlite3 responder</h3>
<ul>
{% for k in kyara %}
<li>
<a href="/toaru/{{ k[0] }}">{{ k[0] }}</a> lv {{ k[1] }}
</li>
{% endfor %}
</ul>
<form action="/insert" method="post">
<div>name<input type="text" name="namae"></div>
<div>level<input type="text" name="lv"><br></div>
<div><input type="submit" value="add to"></div>
</form>
<a href="/download">download</a>
</body>
The composition is --Data enumeration --Form to add new data- --There is a link to download the data.
toaru.html
Next is a page to display and edit the data of a certain character.
<head>
<meta charset="utf-8">
<title>a{{ namae }}page of</title>
<link rel="stylesheet" href="/librorum/prohibitorum.css" type="text/css" media="all">
</head>
<body>
<form action="/update/{{ namae }}" method="post">
<div>name: <input type="text" name="namae" value="{{ namae }}"></div>
<div>level: <input type="text" name="lv" value="{{ lv }}"></div>
<input type="submit" value="update">
</form>
<form action="/delete/{{ namae }}" method="delete">
<input type="submit" value="Delete">
</form>
<div><a href="/">Return</a></div>
</body>
The composition is --Editable character data form --Delete data button --Link back to index
no.html
And the page that appears when something goes wrong. There is only a link back to the index.
<head>
<meta charset="utf-8">
</head>
<body>
<h1>NO!!</h1>
The sky is so blue but the tip is pitch black<br><br>
<a href="/">~-Return-~</a>
</body>
python
* A file that uses magic to control everything on the * </ s> site.
If it is a large site, it may be necessary to decompose it into various files, but this time it is a small site, so it is not necessary to separate it into one file.
The controllers for all routes and all the code that connects to the database can be found here.
majutsu.py
import responder,sqlite3,urllib,os
#File to save data
dbfile = 'dedicatus545.db'
#API object
api = responder.API(templates_dir='.', #Template folder
static_dir='librorum', #Static file folder
static_route='/librorum') #Static file root
#Index page
@api.route('/')
def index(req,resp):
with sqlite3.connect(dbfile) as conn:
sql_select = '''
select * from kyara
''' #Display data of all characters
kyara = conn.execute(sql_select).fetchall()
resp.html = api.template('index.html',kyara=kyara)
#Each data display and editing page
@api.route('/toaru/{namae}')
def select(req,resp,*,namae):
with sqlite3.connect(dbfile) as conn:
sql_select = '''
select * from kyara where namae==?
''' #Take the data of the character with that name
kyara = conn.execute(sql_select,[namae]).fetchone()
if(kyara):
resp.html = api.template('toaru.html',namae=kyara[0],lv=kyara[1])
else:
print('This page does not exist')
api.redirect(resp,'/no') #If a name that does not exist is entered, go to the error page
#Page if something goes wrong
@api.route('/no')
def no(req,resp):
resp.html = api.template('no.html')
#After adding data
@api.route('/insert')
async def insert(req,resp):
try:
with sqlite3.connect(dbfile) as conn:
param = await req.media() #Get data from form
namae = param['namae']
lv = param['lv']
sql_insert = '''
insert into kyara (namae,lv)
values (?,?)
''' #Add new data
conn.execute(sql_insert,(namae,lv))
api.redirect(resp,'/') #Return to index page
except Exception as err:
print(f'Error: {type(err)} {err}')
api.redirect(resp,'/no') #If something goes wrong
#After updating the data
@api.route('/update/{namae0}')
async def update(req,resp,*,namae0):
try:
with sqlite3.connect(dbfile) as conn:
param = await req.media() #Get data from form
namae = param['namae']
lv = param['lv']
sql_update = '''
update kyara set namae=?,lv=? where namae==?
''' #Data update
conn.execute(sql_update,(namae,lv,namae0))
#Return to data display page**If you do not escape the name here, you may get an error, so urllib.parse.need quote
api.redirect(resp,f'/toaru/{urllib.parse.quote(namae)}')
except Exception as err:
print(f'Error: {type(err)} {err}')
api.redirect(resp,'/no') #If there is something wrong
#After deleting the data
@api.route('/delete/{namae}')
def delete(req,resp,*,namae):
try:
with sqlite3.connect(dbfile) as conn:
sql_delete = '''
delete from kyara where namae==?
''' #Data deletion
conn.execute(sql_delete,[namae])
api.redirect(resp,'/') #Return to index page
except Exception as err:
print(f'Error: {type(err)} {err}')
api.redirect(resp,'/no') #If something goes wrong
#Load data
@api.route('/download')
def download(req,resp):
with sqlite3.connect(dbfile) as conn:
#Data to json file
data = conn.execute('select * from kyara').fetchall()
resp.media = [{'namae': d[0], 'lv': d[1]} for d in data]
#Specify in the header to make it a page for downloading files
resp.headers['Content-Disposition'] = 'attachment; filename=data.json'
if(__name__=='__main__'):
#Create a new table when you run it for the first time
if(not os.path.exists(dbfile)):
with sqlite3.connect(dbfile) as conn:
sql_create = '''
create table kyara (
namae text,
lv integer,
primary key (namae)
)
'''
conn.execute(sql_create)
#Server start
api.run()
There are 7 routes, but I actually use the template
Only three.
In addition to it
They interact with the database and redirect to other pages.
The pages **'/ insert' ** and **'/ update / {namae0}' ** are async functions because they need to receive data from the form and await is used.
I just learned about python's async and await recently. I read various qiita articles and it was helpful, so I will introduce it here
-Python asyncio to understand with sushi -Asynchronous processing in Python: asyncio reverse lookup reference
When using responder, even if we don't write async and await directly, it is very useful to understand asynchronous processing because there are many functions that work with async and await in responder in the first place.
Finally, **'/ download' ** is a page to save all the data in the database to a json file.
The database is created the first time you run the server. After that, a file containing the database (here named dedicatus545.db) will appear.
The responder.API object is set like this
templates_dir = '.'
static_dir = 'librorum'
static_route = '/librorum'
templates_dir is the folder with the templates. By default, it is in a folder called templates, but this time we will not use the folder, so specify it as'.'.
static_dir is the folder that contains the static files. The default folder is static, but here it is'librorum'.
static_route is the root of the static file, which defaults to'/ static', but should be'/ librorum' as well.
css
Website decoration is not the main purpose of this time, so css suitable enough to be a spectacle
librorum/prohibitorum.css
div,li,h3 {
padding: 2px;
font-size: 20px;
}
input {
border: solid #194 2px;
font-size: 19px;
}
form {
margin: 3;
}
Once the code is ready, it's time to run the server .py code.
python majutsu.py
Then access http://127.0.0.1:5042/ with your browser.
Here we will go with firefox.
If there are no mistakes, you should see a page like this.
There is no data yet, so let's add it first.
Enter the name and level and click the Add button to add the data. Add another one to try.
If you click the "Download" link, the data will be downloaded as a json file.
However, if you use this method, the kanji will be Unicode like this when converting to json.
[{"namae": "\u4e0a\u6761\u5f53\u9ebb", "lv": 0}, {"namae": "\u5fa1\u5742\u7f8e\u7434", "lv": 5}]
How to avoid this is described in this article https://qiita.com/nassy20/items/adc59c4b7abd202dda26
However, even so, when I looked it up in firefox, it returned to kanji properly, so I think it's okay this time.
Next, if you try clicking the Add button without filling in the form, an error will occur and you will be taken to this page.
The cause of the error is that when using req.media () because the name is not entered, calling param ['namae'] without the'namae' key will result in an error.
It's better to use .get () to avoid errors, but this time it doesn't have to be empty in the first place, so you can leave it as it is here.
Go back to the index, click one name and enter the link to go to the data edit page.
When I try to empty the level and click the update button, an error occurs and I go to the no page again.
If you go back to this page again, enter the new data properly this time, and click the button, the data will be updated.
When you return to the index, you can confirm that the data has been updated properly.
Finally, when you enter the edit page again and click the delete button
That data will disappear.
This completes the test of all functions.
This is how the website was created with responder and sqlite3.
It may just be a simple and unusable website, but I think it can be used as a basic practice for creating a full-fledged site.
An example of adding javascript etc. to make SPA is written in the next article >> https://qiita.com/phyblas/items/f3f40df76f85d61d5286
Recommended Posts