19 Otsingumootori loomine Flaskiga
Järgneva kahe peatüki läbimiseks on soovitatav eelnevalt läbi töötada Tarkvaraarenduse õpiku 2. trüki teema Veebirakenduse loomine. Flask. Seda seetõttu, et projekti peatükid on mõeldud seal õpitud Flaski teadmiste ning siin moodulis õpitud päringute teadmiste kinnistamiseks. Projekti peatükke saab läbida ka ilma Flaski õppematerjali uurimata, kuid sellisel juhul tuleb tõenäoliselt iseseisvalt ja jooksvalt lisainfot otsida.
Oleme praeguseks omandanud piisavalt teadmisi andmebaaside ja neist pärimise kohta. Seega, saame neid ka ühe elulise projekti – otsingumoori loomise – tarbeks rakendada.
Loodav otsingumootori on mõeldud Netflixi andmebaasist teoste mugavaks otsimiseks. Projekt on sobiv on viis päringute reaalsete kasutusalade tutvustamiseks, kuna pea kõik internetist leitavad otsingumootorid (sh igasugused väiksed otsinguväljad) kasutavad tegelikkuses oma tööks andmebaasi päringuid.
Kui me varasemates peatükkides kasutasime 5 faili jaotatud ning eeltöödeldud andmeid Netflixi teoste kohta, siis selle projekti raames kasutame lihtsuse nimel vaid algandmeid. Neid laeme alla aga hiljem.
Tarkvara installimine ja moodulite paigaldamine
Esmalt on soovitatav installida arenduskeskkond Thonny. Soovi korral leiab selleks juhendeid Programmeerimise õpiku peatüki Sissejuhatus alampeatükist Programm.
Pärast Thonny installimist on tarvis paigaldada kaks moodulit – Flask ja Flask-SQLAlchemy.
Flask-i mooduli paigaldamiseks tuleb kõigepealt valida Thonny menüüst Tools → Manage Packages. Seejärel tuleb otsinguaknasse kirjutada Flask ning klikata nupule Search on PyPi. Pärast seda tuleb vajutada valikule Flask ning seejärel nupule Install.
Mooduli Flask-SQLAlchemy installimine käib identselt.
Mooduliga Flask-SQLAlchemy tuleb automaatselt kaasa ka moodul SQLAlchemy. Käesoleva õppematerjali koostamise ajal oli selle värskeim (ametlikult) stabiilne versioon 1.4.1. Selle versiooniga esineb andmebaasiga ühendust luues probleeme. Seega tuleb mooduli SQLAlchemy versiooni langetada.
Mooduli versiooni langetamiseks tuleb Manage Packages vaatest esmalt moodul SQLAlchemy vasakult listist üles otsida ning seejärel sellele klikata. Avanenud vaates tuleb vajutada nupule ‘…’, nii nagu alloleval pildil.
Seejärel tuleb valida soovitud versioon, milleks on viimane kindlalt töötav versioon 1.3.23 ning lõpuks tuleb klikata nupul Install.
Pärast seda avaneb laadimisribaga aken ning laadimise lõppedes on mooduli versioon langetatud. Võimalik, et lõpus näidatakse õigustega seotud veateadet, kuid see ei ole siinkohal üldjuhul tähenduslik ning versiooni langetamine peaks siiski töötama.
Nüüd ongi tarkvara edukalt installitud ning vajalikud moodulid paigaldatud.
Algse programmi loomine
Alustuseks tuleks meeldivasse asukohta luua kaust, kuhu hakkame omakorda projektiga seotud faile looma.
Alustame sellega, et loome oma Flaski programmi aluse, mis renderdab aadressile 127.0.0.1:5000/teosed faili teosed.html
sisu. Faili teosed.html
veel ei eksisteeri, kuid ka selle loome peatselt.
Paneme meie programmi alusfaili nimeks app.py
ning olgu selle sisu järgnev:
from flask import Flask, render_template app = Flask(__name__) @app.route('/teosed') def teosed(): return render_template('teosed.html', teosed=[]) if __name__ == "__main__": app.run()
Selleks, et me loodud faili ka jooksutada saaks, tuleks nüüd luua fail teosed.html
ning selle baasfail baas.html
. Failid teosed.html
ja baas.html
tuleks paigutada projekti kausta alamkausta templates
, mis tuleb samuti siinkohal luua.
Projekti kaust peaks hetkeseisuga välja nägema selline:
Loome esimesena faili baas.html, kuna fail teosed.html põhineb osaliselt sellel. Olgu faili baas.html
sisu järgnev:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> {% block head %} <title>Otsingumootor</title> {% endblock %} </head> <body> {% block body %} {% endblock %} </body> </html>
Loodud fail täpsustab hetkel peamiselt seda, et kõigi muude .html
failide pealkiri olgu Otsingumootor juhul, kui seda pole neis failides üle kirjutatud.
Nüüd saame luua ka faili teosed.html
, mille sisu olgu järgnev:
{% extends 'baas.html' %} {% block body %} <h1>Teosed</h1> <table> <tr> <th>Pealkiri</th> <th>Tüüp</th> <th>Riigid</th> <th>Aasta</th> <th>Žanrid</th> <th>Näitlejad</th> <th>Kirjeldus</th> </tr> {% for teos in teosed %} <tr> <td>{{ teos.pealkiri }}</td> <td>{{ teos.tuup }}</td> <td>{{ teos.riigid }}</td> <td>{{ teos.valjalaske_aasta }}</td> <td>{{ teos.zanrid }}</td> <td>{{ teos.naitlejad }}</td> <td>{{ teos.kirjeldus }}</td> </tr> {% endfor %} </table> {% endblock %}
Failis teosed.html
täpsustame esmalt seda, et viitame failile baas.html
. Seejärel alustame body
plokiga, mille sisse loome teoste tabeli. Tabeli veergude pealkirjad määrame käsitsi, kuid tabelis kuvatavad andmeread tulevad argumendist teosed
. Mäletatavasti andsime failis app.py
failile teosed.html
hetkel ette tühja listi, seega on tabel tühi.
Projekti kausta alamkausta templates
sisu peaks hetkeseisuga välja nägema selline:
Kui kõik failid on loodud, võib jooksutada faili app.py
. Seni valminud programmi tulemust saab brauseri abil vaadata aadressil 127.0.0.1:5000/teosed või localhost:5000/teosed.
Andmebaasi ja selle tabeli loomine ning andmetega täitmine
Selleks, et loodud tabelis andmeid kuvada saaks, tuleb luua andmebaas ning selle sisse Netflixi teoste andmeid hoiustav tabel. Esmalt tuleb hakata täiendama faili app.py
.
Lisame importide hulka järgneva rea, mille abil impordime andmebaasiga suhtlemiseks kasutatava mooduli SQLAlchemy:
from flask_sqlalchemy import SQLAlchemy
Seejärel tuleks pärast rida app = Flask(__name__)
lisada kolm andmebaasi loomise ja seadistamisega seotud koodirida:
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///teosed.db' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False db = SQLAlchemy(app)
Esimese reaga määrame andmebaasi faili salvestamise asukoha. Kasutatud kirjapilt tähendab seda, et fail teosed.db
luuakse failiga app.py
samasse kausta. Teise reaga määrame, et ei soovi muudatusi jälgida ning kolmanda reaga loomegi andmebaasi.
Esimeses reas võis märgata sõna sqlite. See viitab sellele, et me kasutame andmebaasi juhtimissüsteemina SQLite’i, mitte PostgreSQL’i, nagu oleme teinud siiani. SQLite on tõenäoliselt enim kasutatud andmebaasi juhtimissüsteem maailmas, kuna see on mahult väike, lihtne ning väga paljudesse programmidesse sisse ehitatud. Seega sobib ta hästi ka meie väikese projekti jaoks. Soovi korral võib SQLite’i kohta juurde lugeda selle kodulehelt.
Kuna me kasutame andmebaasiga suhtlemiseks niikuinii moodulit SQLAlchemy ei mõjuta meid eriti see, milline andmebaasi juhtimissüsteem selle taga on. Seega võiksime kasutada endiselt PostgreSQL’i, kuid see teeks seadistamise mõnevõrra keerukamaks.
Järgmise sammuna tuleks loodud andmebaasi luua tabel Teosed, milles hakkame hoiustama kõiki teostega seotud andmeid. Enne seda tuleks aga tutvuda meie algandmetega, mis on pärit siit. Varasemates peatükkides kasutasime töödeldud versiooni samadest andmetest.
Nüüd tuleks andmed ka alla laadida. Seda võib teha ka andmete algallikast, kuid vigade vältimiseks on seda soovitatav teha siit. Andmetega töötame täpsemalt edasi pärast tabeli loomist.
Selleks, et tabel Teosed luua, täiendame taaskord faili app.py
. Järgnevad read tuleks lisada faili pärast andmebaasi loomise osa:
class Teosed(db.Model): id = db.Column(db.String(10000), primary_key=True) tuup = db.Column(db.String(7), nullable=False) pealkiri = db.Column(db.String(150), nullable=False) lavastajad = db.Column(db.Text) naitlejad = db.Column(db.Text) riigid = db.Column(db.Text) lisamise_kuupaev = db.Column(db.String(100)) valjalaske_aasta = db.Column(db.Integer, nullable=False) vanusepiirang = db.Column(db.String(20)) kestus = db.Column(db.String(20), nullable=False) zanrid = db.Column(db.Text, nullable=False) kirjeldus = db.Column(db.String(500), nullable=False) def __repr__(self): return 'Teos: ' + str(self.pealkiri)
Esimese reaga täpsustame tabeli nime ning selle, millise andmebaasiga see seotud on.
Järgmised 12 rida tähistavad tabeli veerge ehk tunnuseid. Nagu näha, siis tuleb primaarvõtme täpsustamiseks kirjutada primary_key=True
ning selleks, et mitte lubada väärtusi NULL
, tuleb kirjutada nullable=False
.
Andmetüüpidena kasutame siinkohal String
’i, Text
’i ja Integer'
i. Seega erinevad need mõnevõrra seni kasutatust. Kui me PostgreSQL‘s kasutasime sõne tüüpi väärtuste jaoks andmetüüpi VARCHAR
, siis nüüd tuleb kasutada andmetüüpi String
. Pikkuse täpsustamine käib aga identselt. Andmetüüp Text
tähistab teadmata pikkusega sõnesid ning Integer
tähistab täisarve, nagu ikka.
Viimase kahe koodireaga täpsustame seda, kuidas käsurealt selle tabeli andmeid pärides igat andmerida päringu tulemuses kujutatakse. Kasutatud kirjapilt tähendab seda, et pika andmerea asemel kuvatakse lihtsalt näiteks ‘Teosed: The Queen’s Gambit’.
Nüüd on meil võimalik andmebaas ning selle sees olev tabel Teosed päriselt mingisse faili luua. Selleks kasutame Thonny käsurida. Kui käsurida pole juba nähtaval, vali ülevalt menüüst View → Shell, pärast mida peaks käsurida koodivaate all avanema.
Käivita fail app.py
, kui sa pole seda juba teinud. Soovi korral uuri veebilehte 127.0.0.1:5000/teosed ning seejärel peata fail.
Andmebaasi ja tabeli loomiseks kirjuta käsuritta järjest (kuid väikese vahega) järgnevad käsud:
from app import db
db.create_all()
Nüüd saame kontrollida, kas projekti kausta tekkis andmebaasi fail teosed.db
. Kui jah, on kõik hästi. Kui ei, vaata hoolikalt üle senised sammud ja proovi need uuesti läbi teha.
Kuna andmebaas ja teoste tabel on nüüd loodud, saame andmeid tabelisse lisama hakata. Kui andmed pole juba alla laetud, tuleks seda nüüd teha. Seejärel tuleb allalaetud kokkupakitud andmed lahti pakkida ning projekti kausta tõsta. Lõpuks tuleb luua ka uus koodifail abi.py
. Nii andmefail kui ka koodifail peaksid paiknema samal tasandil mis app.py
.
Faili abi.py
paneme koodi, mille abil lisatakse failis netflix_titles.csv
olevad andmed andmebaasi faili teosed.db
.
Olgu faili abi.py
sisu järgnev:
import csv, sqlite3 con = sqlite3.connect("C:/Users/Kasutaja/Desktop/Lõputöö/Otsingumootor_jooksev/teosed.db") cur = con.cursor() with open('netflix_titles.csv','r', encoding='utf8') as f: dr = csv.DictReader(f) andmeread = [(i['show_id'], i['type'], i['title'], i['director'], i['cast'], i['country'], i['date_added'], i['release_year'], i['rating'], i['duration'], i['listed_in'], i['description']) for i in dr] cur.executemany("INSERT INTO Teosed (id, tuup, pealkiri, lavastajad, naitlejad, riigid, lisamise_kuupaev, valjalaske_aasta, vanusepiirang, kestus, zanrid, kirjeldus) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);", andmeread) con.commit() con.close()
Muuda enne jätkamist koodireas con = sqlite3.connect("C:/Users/Kasutaja/Desktop/Lõputöö/Otsingumootor_jooksev/teosed.db")
näidatud failitee enda projektile vastavaks!
Kuna tegemist on vaid abifailiga, ei keskendu me siinkohal selle tööpõhimõtetele. Soovi korral saab aga sqlite3 dokumentatsioonist uurida näiteks seda, mida tähendavad koodis kasutatud Connection ja Cursor.
Jooksuta nüüd faili abi.py
, mille tulemusena lisatakse kõik .csv
failis olevad andmed meie andmebaasi!
Viimaks, et meie andmebaasis olevaid andmeid ka aadressil 127.0.0.1:5000/teosed kuvataks, tuleb faili app.py
meetodit teosed()
veidi kohandada. Muuda see järgnevaks:
@app.route('/teosed') def teosed(): koik_teosed = Teosed.query.all() return render_template('teosed.html', teosed=koik_teosed)
Selle tulemusena päritakse muutujasse koik_teosed
tabeli Teosed kogu sisu. Muutja koik_teosed
väärtuse anname omakorda edasi failile teosed.html
. Mäletatavasti kasutati failis teosed.html
argumendi teosed väärtust tabeli andmetega täitmiseks.
Jooksuta nüüd uuesti faili app.py
ning peaksid aadressil 127.0.0.1:5000/teosed nägema kõigi teoste andmeid. Kuigi andmebaasi tabelis oli veerge 12, on veebilehel neid kõigest 7. See on nii, kuna me täpsustasime failis teosed.html
vaid 7 veeru nimed, mille väärtuseid me näha soovime.
Järgmises peatükis kujundame oma projekti välimust ning lisame erinevaid otsingufunktsionaalsusi.