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.

Mooduli versiooni langetamise esimene samm

Seejärel tuleb valida soovitud versioon, milleks on viimane kindlalt töötav versioon 1.3.23 ning lõpuks tuleb klikata nupul Install.

Mooduli versiooni langetamise teine samm

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:

Projekti kausta ülesehitus 1

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:

Projekti kausta templates ülesehitus

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:

  1. from app import db
  2. 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.

Litsents

Icon for the Creative Commons Attribution 4.0 International License

Lisamoodulid on loodud Aveli Klaos, Siim Tanel Laisaar, Piret Luik, Tauno Palts, ja Eero Ääremaa poolt Creative Commons Attribution 4.0 International License litsentsi alusel, kui pole teisiti märgitud.

Jaga seda raamatut