Садржај
1.0 Базе: Увод у базе података
1.1 Базе: SQLite
1.2 Базе: Дизајнирање базе података
2.0 - SQL: Читање података из базе
2.1 SQL: Пројекција и селекција
2.2 SQL: Логички и релацијски оператори
2.3 SQL: Изрази и функције - Додатно
2.4 SQL: Сортирање, уклањање дупликата, ограничавање броја врста
2.5 SQL: Агрегатне функције и груписање
2.6 SQL: Спајање табела
2.7 SQL: Угнежђени упити
2.8 SQL: Сложенији угњеждени упити - Додатно
2.9 SQL: Погледи
3.0 SQL: Промена садржаја базе
3.1 SQL: Уписивање података у табеле
3.2 SQL: Ажурирање података у табелама
3.3 SQL: Брисање података из табела
4.0 Рачунарске мреже
5.0 Серверско веб-програмирање
5.1 Библиотека Flask - основни појмови
5.2 Библиотека Flask - повезивање са базом података
6.0 Библиотека Flask - пројектни задатак
Коришћење база података из Flask апликација¶
На самом почетку нашег рада са базама података, рекли смо да је један од начина интеракције са системом за управљање базама података (СУБП) управо апликативни интерфејс.
Сваки сајт за пуштање музике, свака онлајн продавница, електронски дневник, свака апликација на мобилном уређају путем које се плаћају рачуни и тако даље, користи неку базу података. Да би то било могуће, неопходно је да постоји начин интеракције са СУБП који ће се уградити у апликацију која се креира. Програмери, када из својих програма приступају базама података, користе апликативни програмски интерфејс, АПИ (енгл. application programming interface).
Да би наши програми преко АПИ-ја могли да приступају СУБП-у, обично је потребно да у програм укључимо посебан модул, односно програмску библиотеку која имплементира АПИ за приступ бази.
Када је у питању програмски језик Python, већ у стандардној инсталацији програмског језика долази модул za
SQLite који се зове sqlite3, и то са уграђеним СУБП за SQLite. То значи да, ако програмирате у програмском језику
Python, није потребно ништа додатно да инсталирате да бисте користили SQLite. Модул sqlite3 имплементира стандардну
спецификацију АПИ-ја за приступ бази која се зове DB-API 2.0, што значи да када научите као у Python-у да користите
SQLite, на сличан начин ћете моћи да користите и друге релационе базе.
Унутар Python кôда веб-апликације (код једноставних апликација он се налази у датотеци app.py) вршимо повезивање
са базом података и читање података из базе, смештајући резултат упита у листу, која се затим прослеђује функцији
render_template, при чему се у шаблону налази петља for која чита и приказује један по један податак из те листе
(наравно, ситуација може бити једноставнија, ако је резултат упита само један податак).
Неки од примера који следе су јако обимни. Имајте у виду да, када правите овакве веб-апликације, не морате да пишете комплетан програмски кôд од почетка. Препоручена пракса је да узмете већ припремљене примере програмског кôда и да га прилагодите на начин на који вам је потребно.
Повезивање са базом и постављање упита¶
Као што смо већ нагласили, свака иоле сложенија веб-апликација укључује неколико различитих фајлова (
датотека, докумената), па је логична конвенција да се све оне чувају унутар једног фолдера (директоријума, фасцикле)
намењеног тој веб-апликацији. За први пример веб-апликације која се повезује на базу података направићемо фолдер
под именом 01_database и у њему ћемо креирати фајл app.py са програмским кôдом.
У исти фолдер треба да ставимо и базу података. У овом примеру ћемо користити базу података фиктивне компаније за продају музичких композиција коју смо већ спомињали и коју можете да преузмете овде:
Да би се могло приступити SQLite бази података, потребно је прво повезати се са базом коришћењем функције
sqlite3.connect. Потребно је да наведемо назив базе података (у нашем случају назив је: music.db).
Конекцију је на крају потребно затворити.
import os
import sqlite3
from flask import Flask
app = Flask(__name__)
conn = sqlite3.connect(os.path.join(app.root_path, 'baza.db'))
# ...
conn.close()
Приказаћемо називе првих 10 извођача.
Да би могао да се постави упит, потребно је креирати објекат који се назива курсор.
То се ради тако што се над објектом конекције позове метод cursor(). На пример:
cur = conn.cursor()
Упит затим можемо да извршимо позивом методе execute на креираном курсору. Параметар је ниска која садржи текст упита на језику SQL.
cur.execute("SELECT Name FROM artist LIMIT 10")
Листу у којој се чува цео резултат можемо да добијемо коришћењем метода fetchall над курсором над којим је извршен упит.
artists = cur.fetchall()
Направићемо шаблон templates/artists.html, а унутар шаблона у петљи исписујемо податке из низа artists:
<!DOCTYPE html>
<html>
<head>
<title>Artists</title>
</head>
<body>
<h1>Artists</h1>
<ol>
{% for artist in artists %}
<li>{{ artist[0] }}</li>
{% endfor %}
</ol>
</body>
</html>
Следи комплетан програмски код app.py:
import sqlite3
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/artists')
def artists():
con = sqlite3.connect('music.db')
cur = con.cursor()
cur.execute("SELECT Name FROM artist LIMIT 10")
artists = cur.fetchall()
return render_template("artists.html", artists = artists)
Следeћа слика илуструје фолдер у којем се налази наша веб-апликација.
Да бисмо имали тачну путању до фајла која нам је неопходна да покренемо програм, можемо да употребимо опцију
Copy adress када урадимо десни клик мишем у прозору File Explorer.
Након тога, као што смо и раније радили, у командној линији се постављамо у директоријум у коме смо
креирали датотеку app.py тако што напишемо:
cd naziv_fajla_sa_putanjom
Након покретања Flask апликацију командом flask run, апликацији можемо приступити из прегледача веба:
На слици је приказан изглед апликације када се покрене http://127.0.0.1:5000/artists из прегледача веба:
Уколико је потребно да нешто изменимо у нашој апликацији и да видимо измене, потребно је да урадимо следеће:
- у командној линији у којој смо покренули веб-апликацију помоћу Flask Run прекинути је комбинацијом тастера Ctrl + C;
- поново отворити програмски кôд у едитору текста Notepad тако што отворимо едитор Notepad, изаберемо са менија File/Open, и пронађемо фајл (обавезно изабрати All Files и Encoding/UTF-8);
- унети измене у фајл и сачувати;
- вратити се у командну линију на исту локацију где се налази app.py и поново покренути веб-апликацију помоћу Flask Run;
- отворити одговарајућу адресу (у овом случају http://127.0.0.1:5000/artists) у прегледачу Chrome (или освежити страницу ако је већ била отворена и нисмо је затворили).
Погледајмо још неке начине да различитим програмским кôдовима добијемо исти резултат.
Путања db датотеке може да се одреди и помоћу променљиве app.root_path.
import os
import sqlite3
from flask import Flask
app = Flask(__name__)
conn = sqlite3.connect(os.path.join(app.root_path, 'music.db'))
# ...
conn.close()
Подразумеваћемо убудуће да глобална променљива DATABASE садржи
путању до датотеке у којој се чува SQLite база података.
DATABASE = os.path.join(app.root_path, 'baza.db')
Повезивање је могуће урадити на самом почетку рада апликације, а везу
је могуће затворити на самом крају рада апликације, тако да све
функције које одговарају на захтеве клијената користе ту конекцију са
базом, репрезентовану глобалном променљивом. Мало елегантније решење
је то да се уместо глобалне променљиве conn, веза ка бази
складишти унутар објекта (речника) flask.g, који служи да чува све
глобалне податке у Flask апликацији, тако да им се онда једноставно
може приступити из било ког дела изворног кôда те апликације. Глобални
подаци се чувају тако што се додели вредност произвољном пољу тог
објекта (списак поља није унапред дефинисан и програмер може да
користи која год поља жели). За складиштење конекције ка бази ми ћемо
користити поље које ћемо назвати flask.g._db_conn. Можемо
дефинисати функцију get_db(), која први пут када се позове
успоставља везу са базом (позивом функције sqlite3.connect) и
складишти је у објекат flask.g. У сваком наредном позиву те
функције, враћаће се конекција која је упамћена у flask.g._db_conn
(неће се поново позивати sqlite3.connect). Уместо да корисник
самостално позива функцију за затварање конекције ка бази ка крају
рада апликације, анотацијом @app.teardown_appcontext могуће је
постићи да се то аутоматски догоди.
def get_db():
if not "_db_conn" in g:
g._db_conn = sqlite3.connect(DATABASE)
return g._db_conn
@app.teardown_appcontext
def close_db(exception):
if "_db_conn" in g:
g._db_conn.close()
Са овако дефинисаним функцијама, курсор који се може користити за
постављање упита се може једноставно добити позивом
get_db().cursor(). На пример, на наредни начин можемо приказати
списак првих 10 извођача песама (претпоставићемо да је db датотека
која садржи базу података компаније за продају музичких композиција
налази у кореном директоријуму Flask веб-апликације и да је приликом
дефинисања променљиве DATABASE наведено име db те датотеке):
@app.route("/artists")
def artists():
cur = get_db().cursor()
artists = cur.execute("SELECT naziv FROM izvodjac LIMIT 10").fetchall()
return render_template("artists.html", artists=artists)
Унутар шаблона у петљи исписујемо податке из низа artists
<!DOCTYPE html>
<html>
<head>
<title>Artists</title>
</head>
<body>
<h1>Artists</h1>
<ol>
{% for artist in artists %}
<li>{{ artist[0] }}</li>
{% endfor %}
</ol>
</body>
</html>
На слици је приказан изглед апликације када се покрене из прегледача веба.
Поновно можемо дефинисати и помоћну функцију за постављање упита. Функцији се прослеђује упит, параметри упита и податак о томе да ли се жели само један ред из резултата или цео резултат упита.
def query_db(query, args=(), one=False):
cur = get_db().execute(query, args)
rows = cur.fetchall()
cur.close()
if one:
return rows[0] if rows else None
else:
return rows
Тада је скирпт који чита податке о првих 10 извођача још једноставнији.
@app.route("/artists")
def artists():
artists = query_db("SELECT Name FROM Artist LIMIT 10")
return render_template("artists.html", artists=artists)
База података music.db¶
Приликом креирања веб-апликација које се повезују на базу података, важно је добро се упознати са том базом.
Преузету SQLite базу података music.db можемо да отовримо из програма SQLite Studio командом менија
Database → Add a database. Пронаћи фајл са базом на рачунару под File. У прозору Databases погледати
списак табела, а за сваку табелу и списак колона.
Дефинисати веб-апликацију у којој се приказују називи песама жанра са идентификационим бројем 5. Користити дату базу.
Креирати одговарајући шаблон tracks.html.