{"id":246,"date":"2021-03-05T15:40:59","date_gmt":"2021-03-05T15:40:59","guid":{"rendered":"https:\/\/web.htk.tlu.ee\/digitaru\/lisamoodulid\/?post_type=chapter&#038;p=246"},"modified":"2021-05-07T12:49:42","modified_gmt":"2021-05-07T12:49:42","slug":"otsingumootori-loomise-jatk","status":"publish","type":"chapter","link":"https:\/\/web.htk.tlu.ee\/digitaru\/lisamoodulid\/chapter\/otsingumootori-loomise-jatk\/","title":{"raw":"Otsingumootori loomise j\u00e4tk","rendered":"Otsingumootori loomise j\u00e4tk"},"content":{"raw":"<h2>Veebilehe kujundamine<\/h2>\r\nHetkel on meie projekti, mis on n\u00e4htav veebiaadressil <a href=\"http:\/\/127.0.0.1:5000\/teosed\">127.0.0.1:5000\/teosed<\/a>, t\u00e4ielikult stiliseerimata. Kujunduse loomine aitab projekti kasutamist mugavamaks teha ning pakub ka silmailu.\r\n\r\nAlustame sellega, et loome projekti kausta sisse uue alamkausta <code>static<\/code>. Kausta <code>static<\/code> sisse loome alamkausta <code>css<\/code> ning selle sisse omakorda faili <code>kujundus.css<\/code>. Kuna tegemist on v\u00e4ikse projektiga, on m\u00f5istlik kasutada \u00fchte kujunduse faili k\u00f5igi vahelehtede jaoks. Hetkel on meil vahelehti k\u00fcll \u00fcks, kuid hiljem loome \u00fche juurde selleks, et n\u00e4idata otsingute tulemusi.\r\n\r\nProjekti kaust peaks hetkeseisuga v\u00e4lja n\u00e4gema selline:\r\n\r\n<img class=\"alignnone size-full wp-image-1171\" src=\"https:\/\/web.htk.tlu.ee\/digitaru\/lisamoodulid\/wp-content\/uploads\/sites\/21\/2021\/03\/kaust3.png\" alt=\"Projekti kausta \u00fclesehitus 2\" width=\"596\" height=\"150\" \/>\r\n\r\nProjekti kausta alamkaust <code>\/static\/css<\/code> peaks v\u00e4lja n\u00e4gema selline:\r\n\r\n<img class=\"alignnone size-full wp-image-1173\" src=\"https:\/\/web.htk.tlu.ee\/digitaru\/lisamoodulid\/wp-content\/uploads\/sites\/21\/2021\/03\/kaust4.png\" alt=\"Projekti kausta alamkaust css\" width=\"596\" height=\"45\" \/>\r\n\r\n\u00dchtse kujunduse kasutamiseks k\u00f5igis failides tuleb kujunduse fail <code>kujundus.css<\/code> \u00fchendada baasfailiga <code>baas.html<\/code>. Selleks lisame faili <code>baas.html<\/code> <code>head<\/code> siltide vahele j\u00e4rgmise rea:\r\n\r\n<code><\/code>\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"html\">&lt;link rel=\"stylesheet\" href=\"static\/css\/kujundus.css\"&gt;<\/pre>\r\n<code><\/code>\r\n\r\nAsumegi kujundust looma. K\u00e4esolevas peat\u00fckis tuuakse jooksvalt n\u00e4iteid, kuidas projekti kujundada v\u00f5iks. Soovitatav on k\u00f5igepealt katsetada, milline n\u00e4idiskujundus v\u00e4lja n\u00e4eb ning seej\u00e4rel v\u00f5ib projekti ka oma maitse ja eelistuste p\u00f5hjal kujundama hakata.\r\n\r\nEsmalt muudame veebilehe v\u00e4rve, m\u00e4\u00e4rame fondi, \u00e4\u00e4riseid ja muud. Selleks lisame faili <code>kujundus.css<\/code> j\u00e4rgnevad read:\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"css\">html {\r\n    background-color: #fdfdfd;\r\n}\r\n\r\nbody {\r\n    background-color: #fafafa;\r\n    width: 1200px;\r\n    font-family: Arial;\r\n    padding: 20px;\r\n    margin: 10px auto 5px auto;\r\n    box-shadow: 0 0 8px #000000;\r\n    border-radius: 10px;\r\n}<\/pre>\r\nKui m\u00f5ni kasutatud stiilielement j\u00e4\u00e4b kas siin v\u00f5i tulevikus segaseks, otsi kindlasti nende kohta internetist infot. \u00dcks soovitatav infoallikas on veebileht <a href=\"https:\/\/www.w3schools.com\/\">w3schools<\/a>.\r\n\r\nKujundame ka teoste tabelit. Lisame sellele piirjooned, m\u00e4\u00e4rame veergude pealkirjade lahtritele teistsuguse taustav\u00e4rvi ning lisame lahtritele t\u00e4idiseid (ingl <em>padding<\/em>). Selleks lisame faili j\u00e4rgnevad read:\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"css\">table, th, td {\r\n    border: 1px solid black;\r\n}\r\n\r\nth, td {\r\n    padding: 5px;\r\n}\r\n\r\ntable {\r\n    border-collapse: collapse;\r\n}\r\n\r\nth {\r\n    background-color: #c9e4eb\r\n}\r\n<\/pre>\r\nSelleks, et hetkel kasutatud pealkirjad ning hiljem lisatavad tekstid oleksid veebilehe keskel, lisame juba praegu ka j\u00e4rgnevad read:\r\n\r\n<code><\/code>\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"css\">h1, h2, p {\r\n    text-align: center;\r\n}<\/pre>\r\n<code><\/code>\r\n\r\nOlemegi n\u00fc\u00fcdseks suure osa kujundamisest \u00e4ra teinud, t\u00e4nu millele on veebilehel kuvatavaid andmeid m\u00e4rksa mugavam vaadelda. J\u00e4tkame n\u00fc\u00fcd funktsionaalsuste lisamisega ning edaspidi t\u00e4iendame kujunduse faili jooksvalt, siis kui selleks vajadus tekib.\r\n\r\nJooksuta enne j\u00e4tkamist uuesti faili <code>app.py<\/code> ning tutvu veebirakenduse uue kujundusega.\r\n<h2>Otsingufunktsiooni lisamine<\/h2>\r\nPraeguseks on veebirakenduses n\u00e4ha kujundatud kujul Netflixi teoste infot. Seega saame keskenduda otsingufunktsioonide lisamisele. Selleks tuleb esmalt t\u00e4iendada faili <code>teosed.html<\/code>. Nimelt tuleb sinna lisada veebivorm koos sisendiv\u00e4ljadega, mille p\u00f5hjal koostatame andmebaasi p\u00e4ringuid.\r\n\r\nLisame faili <code>teosed.html<\/code> ploki <code>body<\/code> algusesse j\u00e4rgnevad read:\r\n\r\n<code><\/code>\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"html\">&lt;h1&gt;Otsingumootor&lt;\/h1&gt;\r\n&lt;form action='\/tulemused' method='POST'&gt;\r\n    &lt;div class=\"sisend\"&gt;\r\n        &lt;label&gt;Pealkiri:&lt;\/label&gt;\r\n        &lt;input type='text' name='o_pealkiri' id='o_pealkiri'&gt;\r\n    &lt;\/div&gt;\r\n    &lt;input type='submit' value='Otsi' class=\"nupp\"&gt;\r\n    &lt;input type='reset' value='T\u00fchjenda' class=\"nupp\"&gt;\r\n&lt;\/form&gt;\r\n&lt;br&gt;<\/pre>\r\n<code><\/code>\r\n\r\nNagu n\u00e4ha, l\u00f5ime HTML-i <code>form<\/code> siltide abil veebivormi, kus on hetkel vaid \u00fcks sisendiv\u00e4li (<code>input<\/code> siltide vahel) otsitava teose pealkirja jaoks. Lisaks on seal nupp <em>T\u00fchjenda<\/em>, millele klikates t\u00fchjendatakse k\u00f5ik veebivormi sisendiv\u00e4ljad ning nupp <em>Ots<\/em><em>i<\/em>, millele vajutamisel suunatakse meid meetodiga <code>POST<\/code> aadressile <a href=\"http:\/\/127.0.0.1:5000\/tulemused\">127.0.0.1:5000\/tulemused<\/a>. Kuna me pole sellist vahelehte veel loonud, tuleb praegu nupule <em>Otsi<\/em> vajutades veateade <em>Not Found<\/em>. Nupp <em>T\u00fchjenda<\/em> juba t\u00f6\u00f6tab.\r\n\r\nKujundame loodud ja tulevasi sisendiv\u00e4lju. Lisame selleks faili <code>kujundus.css<\/code> j\u00e4rgnevad read:\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"css\">input {\r\n    padding: 4px;\r\n}\r\n\r\n.sisend {\r\n    display: inline-block;\r\n}\r\n\r\n.sisend label {\r\n    display: block;\r\n}<\/pre>\r\nLisasime nii sisendiv\u00e4ljadele kui ka nuppudele t\u00e4idised ning m\u00e4\u00e4rasime, et sisendiv\u00e4lja pealkirjad oleksid sisendiv\u00e4ljade kohal. Seda ka siis, kui sisendiv\u00e4lju hiljem juurde lisada. Otsi vajadusel internetist, mida t\u00e4hendavad <code>inline-block<\/code> ja <code>block<\/code>. Nende m\u00f5istmine tuleb kindlasti igasugusel veebiarendusel kasuks.\r\n\r\nJ\u00e4rgmisena t\u00e4iendame faili <code>app.py<\/code>, kuhu kirjutame andmebaasi p\u00e4ringu koostamise loogika.\r\n\r\nAlustuseks tuleb moodulist <em>flask<\/em> importida lisaks varasemale ka <em>request<\/em>. Seega peaks importide osa n\u00fc\u00fcdseks v\u00e4lja n\u00e4gema selline:\r\n\r\n<code><\/code>\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">from flask import Flask, render_template, request\r\nfrom flask_sqlalchemy import SQLAlchemy<\/pre>\r\n<code><\/code>\r\n\r\nSeej\u00e4rel lisame p\u00e4rast meetodit <code>teosed()<\/code> j\u00e4rgnevad koodiread:\r\n\r\n<code><\/code>\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">@app.route('\/tulemused', methods=['GET', 'POST'])\r\ndef tulemused():\r\n    tulemused = []\r\n    o_pealkiri = request.form['o_pealkiri']\r\n    tulemused = Teosed.query.filter(Teosed.pealkiri.like('%'+o_pealkiri+'%')).all()\r\n    return render_template('tulemused.html', tulemused=tulemused)<\/pre>\r\n<code><\/code>\r\n\r\nSellega n\u00e4itame, mis juhtub, kui minna aadressile <a href=\"http:\/\/127.0.0.1:5000\/tulemused\">127.0.0.1:5000\/tulemused<\/a>. Seal aadressil pole endiselt veel midagi, kuna selle sisu renderdatakse faili <code>tulemused.html<\/code> p\u00f5hjal, mida me veel loonud ei ole. Teeme seda peatselt, kuid enne vaatame lisatud koodiread \u00fcle.\r\n\r\nReaga <code><code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">o_pealkiri = request.form['o_pealkiri']<\/code><\/code><code><\/code> v\u00e4\u00e4rtustame me muutuja <code>o_pealkiri<\/code> veebivormist saadud pealkirja sisendiv\u00e4lja v\u00e4\u00e4rtusega. Seej\u00e4rel me loome p\u00e4ringu tabelist Teosed sellise piiranguga, et <code>o_pealkiri<\/code> v\u00e4\u00e4rtus peab esinema teose pealkirja sees. Pane t\u00e4hele koodireas kasutatud m\u00e4rks\u00f5na <code>like<\/code> ning tuleta meelde, kuidas see <em>PostgreSQL'<\/em>s t\u00f6\u00f6tas.\r\n\r\nTasub teada, et siin ei eristata v\u00e4\u00e4rtuste puhul suur- ja v\u00e4iket\u00e4hti. Seega on n\u00e4iteks pealkirja v\u00e4\u00e4rtused 'love' ja 'LoVe' siinkohal v\u00f5rdsed.\r\n\r\n[h5p id=\"54\"]\r\n\r\nMeetodi viimase rea abil renderdame aadressil <a href=\"http:\/\/127.0.0.1:5000\/tulemused\">127.0.0.1:5000\/tulemused<\/a> faili <code>tulemused.html<\/code> ning anname selle faili argumendi <code>tulemused<\/code> v\u00e4\u00e4rtuseks p\u00e4ringust saadud tulemuste listi.\r\n\r\nN\u00fc\u00fcd on j\u00e4\u00e4nud veel luua fail <code>tulemused.html<\/code>, p\u00e4rast mida saamegi pealkirja p\u00f5hjal otsimist katsetada. Faili <code>tulemused.html<\/code> \u00fclesehitus on v\u00e4ga sarnane faili <code>teosed.html<\/code> algse \u00fclesehitusega.\r\n\r\nLisame faili <code>tulemused.html<\/code> j\u00e4rgnevad read:\r\n\r\n<code><\/code><code><\/code>\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"html\">{% extends 'baas.html' %}\r\n{% block head %} &lt;title&gt;Otsingu tulemused&lt;\/title&gt; {% endblock %}\r\n{% block body %}\r\n&lt;h1&gt;Otsingu tulemused&lt;\/h1&gt;\r\n&lt;table&gt;\r\n    &lt;tr&gt;\r\n        &lt;th&gt;Pealkiri&lt;\/th&gt;\r\n        &lt;th&gt;T\u00fc\u00fcp&lt;\/th&gt;\r\n        &lt;th&gt;Riigid&lt;\/th&gt;\r\n        &lt;th&gt;Aasta&lt;\/th&gt;\r\n        &lt;th&gt;\u017danrid&lt;\/th&gt;\r\n        &lt;th&gt;N\u00e4itlejad&lt;\/th&gt;\r\n        &lt;th&gt;Kirjeldus&lt;\/th&gt;\r\n    &lt;\/tr&gt;\r\n    {% for teos in tulemused %}\r\n        &lt;tr&gt;\r\n            &lt;td&gt;{{ teos.pealkiri }}&lt;\/td&gt;\r\n            &lt;td&gt;{{ teos.tuup }}&lt;\/td&gt;\r\n            &lt;td&gt;{{ teos.riigid }}&lt;\/td&gt;\r\n            &lt;td&gt;{{ teos.valjalaske_aasta }}&lt;\/td&gt;\r\n            &lt;td&gt;{{ teos.zanrid }}&lt;\/td&gt;\r\n            &lt;td&gt;{{ teos.naitlejad }}&lt;\/td&gt;\r\n            &lt;td&gt;{{ teos.kirjeldus }}&lt;\/td&gt;\r\n        &lt;\/tr&gt;\r\n    {% endfor %}\r\n&lt;\/table&gt;\r\n{% endblock %}<\/pre>\r\n<code><\/code>\r\n\r\nJooksuta n\u00fc\u00fcd uuesti faili <code>app.py<\/code>. Kirjuta seej\u00e4rel midagi pealkirja sisendiv\u00e4lja ja kliki nupule <em>Ots<\/em><em>i<\/em> ning sind suunatakse \u00fcmber aadressile <a href=\"http:\/\/127.0.0.1:5000\/tulemused\">127.0.0.1:5000\/tulemused<\/a>, kus on n\u00e4ha k\u00f5iki teoseid, mis leiti sisestatud pealkirja v\u00e4\u00e4rtuse p\u00f5hjal. Katseta otsimist erinevate sisendiv\u00e4\u00e4rtustega.\r\n\r\nNagu n\u00e4ha on ka veebirakenduse tulemuste vaheleht kujundatud. Seda m\u00e4letatavasti seet\u00f5ttu, et ka failis <code>tulemused.html<\/code> viitame baasfailile <code>baas.html<\/code>, mis omakorda viitab kujunduse failile <code>kujundus.css<\/code>.\r\n<h3>Mitme parameetri p\u00f5hjal otsing<\/h3>\r\nKuigi pealkirja alusel otsimine t\u00e4itsa t\u00f6\u00f6tab, oleks siiski m\u00f5istlik kasutajatele rohkem otsinguparameetreid pakkuda. N\u00e4iteks ei saa praeguse lahenduse korral otsida teoseid n\u00e4itlejate v\u00f5i riikide p\u00f5hjal.\r\n\r\n\u00d5nneks sarnaneb uute otsinguparameetrite lisamine varasemalt tehtuga. Alustame taaskord sellest, et lisame uued sisendiv\u00e4ljad faili <code>teosed.html<\/code>.\r\n\r\nLisame sisendiv\u00e4ljad t\u00fc\u00fcbi, riikide, aasta, \u017eanrite, n\u00e4itlejate ja kirjelduse jaoks. Selleks kustutame failist <code>teosed.html<\/code> k\u00f5ik <code>form<\/code> siltide vahel olevad koodiread, v\u00e4lja arvatud <em>Otsi<\/em> ja\u00a0<em>T\u00fchjenda<\/em> nuppude osad ning lisame kustutatud ridade asemele j\u00e4rgnevad read:\r\n\r\n<code><\/code><code><\/code>\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"html\">&lt;h2&gt;T\u00e4psete parameetritega otsing&lt;\/h2&gt;\r\n&lt;div class=\"sisend\"&gt;\r\n    &lt;label&gt;Pealkiri:&lt;\/label&gt;\r\n    &lt;input type='text' name='o_pealkiri' id='o_pealkiri'&gt;\r\n&lt;\/div&gt;\r\n&lt;div class=\"sisend\"&gt;\r\n    &lt;label for=\"o_tuup\"&gt;T\u00fc\u00fcp:&lt;\/label&gt;\r\n    &lt;select id=\"o_tuup\" name=\"o_tuup\"&gt;\r\n        &lt;option value=\"\" selected&gt;-&lt;\/option&gt;\r\n        &lt;option value=\"Movie\"&gt;Movie&lt;\/option&gt;\r\n        &lt;option value=\"TV Show\"&gt;TV Show&lt;\/option&gt;\r\n    &lt;\/select&gt;\r\n&lt;\/div&gt;\r\n&lt;div class=\"sisend\"&gt;\r\n    &lt;label&gt;Riigid:&lt;\/label&gt;\r\n    &lt;input type='text' name='o_riigid' id='o_riigid'&gt;\r\n&lt;\/div&gt;\r\n&lt;div class=\"sisend\"&gt;\r\n    &lt;label&gt;Aasta:&lt;\/label&gt;\r\n    &lt;input type='number' name='o_aasta' id='o_aasta'&gt;\r\n&lt;\/div&gt;\r\n&lt;div class=\"sisend\"&gt;\r\n    &lt;label&gt;\u017danrid:&lt;\/label&gt;\r\n    &lt;input type='text' name='o_zanrid' id='o_zanrid'&gt;\r\n&lt;\/div&gt;\r\n&lt;div class=\"sisend\"&gt;\r\n    &lt;label&gt;N\u00e4itlejad:&lt;\/label&gt;\r\n    &lt;input type='text' name='o_naitlejad' id='o_naitlejad'&gt;\r\n&lt;\/div&gt;\r\n&lt;div class=\"sisend\"&gt;\r\n    &lt;label&gt;Kirjeldus:&lt;\/label&gt;\r\n    &lt;input type='text' name='o_kirjeldus' id='o_kirjeldus'&gt;\r\n&lt;\/div&gt;<\/pre>\r\n<code><\/code>\r\n\r\nNagu n\u00e4ha, on enamik sisendiv\u00e4lju \u00fclesehituse poolest pealkirja omaga identsed. Peamiste erinevustena lubame aasta jaoks vaid numbreid ning t\u00fc\u00fcbi valiku lahendasime ripploendiga. Ripploendis pakume v\u00e4\u00e4rtustena v\u00f5imalusi 'Movie', 'TV Show' ja ka vaikev\u00e4\u00e4rtust '-' (mille tegelik v\u00e4\u00e4rtus on t\u00fchi s\u00f5ne).\r\n\r\nSelleks, et ka kasutatud ripploend ning varem lisatud nupud kenamad v\u00e4lja n\u00e4eks, lisame faili <code>kujundus.css<\/code> j\u00e4rgnevad read:\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"css\">select {\r\n    padding: 5px;\r\n}\r\n\r\n.nupp {\r\n    width: 80px;\r\n    text-transform: uppercase;\r\n}<\/pre>\r\nN\u00fc\u00fcd on taaskord tarvis t\u00e4iendada <code>app.py<\/code> loogikat. Kuna meil on sisendiv\u00e4lju mitu, tahame, et otsingu tulemuses oleks vaid sellised teosed, mis vastavad k\u00f5igi sisendiv\u00e4ljade v\u00e4\u00e4rtustele. Seega on sisendiv\u00e4ljade v\u00e4\u00e4rtustel p\u00f5hinevad piirangud vaja omavahel \u00fchendada justkui m\u00e4rks\u00f5naga <code><span style=\"color: #970000\"><strong>AND<\/strong><\/span><\/code>. Siinkohal pole aga m\u00e4rks\u00f5na <code><span style=\"color: #970000\"><strong>AND<\/strong><\/span><\/code> tarvis eraldi v\u00e4lja vaja kirjutada, piisab vaid sellest, kui eraldame piirangud omavahel komadega.\r\n\r\nMuudame seega meetodit <code>tulemused()<\/code> j\u00e4rgnevalt:\r\n\r\n<code><\/code>\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">@app.route('\/tulemused', methods=['GET', 'POST'])\r\ndef tulemused():\r\n    tulemused = []\r\n    o_pealkiri = request.form['o_pealkiri']\r\n    o_tuup = request.form['o_tuup']\r\n    o_riigid = request.form['o_riigid']\r\n    o_aasta = request.form['o_aasta']\r\n    o_zanrid = request.form['o_zanrid']\r\n    o_naitlejad = request.form['o_naitlejad']\r\n    o_kirjeldus = request.form['o_kirjeldus']\r\n    tulemused = Teosed.query.filter(\r\n        Teosed.pealkiri.like('%'+o_pealkiri+'%'),\r\n        Teosed.tuup.like('%'+o_tuup+'%'),\r\n        Teosed.riigid.like('%'+o_riigid+'%'),\r\n        Teosed.valjalaske_aasta.like('%'+o_aasta+'%'),\r\n        Teosed.zanrid.like('%'+o_zanrid+'%'),\r\n        Teosed.naitlejad.like('%'+o_naitlejad+'%'),\r\n        Teosed.kirjeldus.like('%'+o_kirjeldus+'%')\r\n    ).all()\r\n    return render_template('tulemused.html', tulemused=tulemused)<\/pre>\r\n<code><\/code>\r\n\r\nNagu n\u00e4ha, v\u00e4\u00e4rtustasime k\u00f5igepealt k\u00f5igi sisendiv\u00e4ljade p\u00f5hjal neile vastavad muutujad. Seej\u00e4rel kasutasime neid k\u00f5iki ka p\u00e4ringu piiramiseks, eraldades need omavahel komadega.\r\n\r\n[h5p id=\"56\"]\r\n\r\nJooksuta n\u00fc\u00fcd uuesti faili <code>app.py<\/code>, kirjuta midagi erinevatesse sisendiv\u00e4ljadesse ning kliki nupule <em>Ots<\/em><em>i<\/em>. Taaskord suunatakse sind \u00fcmber aadressile <a href=\"http:\/\/127.0.0.1:5000\/tulemused\">127.0.0.1:5000\/tulemused<\/a>, kuid seekord p\u00f5hineb otsingu tulemus k\u00f5igil sisenditel, kuhu mingi v\u00e4\u00e4rtus sisestati. Kui piirangud on liiga kitsad, v\u00f5ib tulemuste tabel ka t\u00fchi olla.\r\n<h3>Laia otsingu lisamine<\/h3>\r\nProovime n\u00fc\u00fcd lisada ka uut Google'ga sarnast otsingut. Selleks lisame \u00fche eraldiseisva suure sisendiv\u00e4lja.\r\n\r\nKui kasutaja kirjutab midagi suurde sisendiv\u00e4lja ning klikib nupule <em>Otsi<\/em>, v\u00f5rreldakse sisendiv\u00e4lja v\u00e4\u00e4rtust erinevate meie valitud tunnustega. Kasutame siinkohal v\u00f5rdluse aluseks tunnuseid pealkiri, \u017eanrid, n\u00e4itlejad ja kirjeldus.\r\n\r\nEsimese sammuna t\u00e4iendame j\u00e4llegi faili <code>teosed.html<\/code>. Lisame <code>form<\/code> siltide vahele, p\u00e4rast nuppe <em>Otsi<\/em> ja <em>T\u00fchjenda<\/em>, j\u00e4rgnevad read:\r\n\r\n<code><\/code>\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"html\">&lt;h2&gt;Lai otsing&lt;\/h2&gt;\r\n&lt;p&gt;Kui kasutad laia otsingut, siis t\u00e4pse otsingu parameetreid arvesse ei v\u00f5eta.&lt;p&gt;\r\n&lt;input type='text' name='o_lai' id='o_lai'&gt;\r\n&lt;input type='submit' value='Otsi' class=\"nupp\"&gt;<\/pre>\r\n<code><\/code>\r\n\r\nTegemist on tavap\u00e4rase sisendiv\u00e4ljaga, mille k\u00f5rval on eraldi otsingunupp. Tegelikkuses on see nupp siiski samav\u00e4\u00e4rne juba varem lisatud otsingunupuga ning funktsionaalsuse poolest ei ole vahet, kummale neist klikata.\r\n\r\nSelleks, et uus sisendiv\u00e4li t\u00f5epoolest suur ja lai oleks, lisame faili <code>kujundus.css<\/code> j\u00e4rgnevad read:\r\n\r\n<code><\/code>\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"css\">#o_lai {\r\n    width: 1100px;\r\n}<\/pre>\r\n<code><\/code>\r\n\r\nSellega on \u00fchtlasi kujundamise osa l\u00e4bi ning siinkohal v\u00f5ib faili <code>kujundus.css<\/code> sulgeda, kui pole just soovi otsingumootori v\u00e4limust ka ise kohandada.\r\n\r\nN\u00fc\u00fcd on j\u00e4\u00e4nud t\u00e4iendada fail <code>app.py<\/code>. Lahendame siinkohal olukorra, kumba otsingut peaks programm <em>Otsi<\/em> nuppudele vajutamisel kasutama, m\u00f5nev\u00f5rra naiivselt. Nimelt, kontrollime, kas laia otsingu sisendiv\u00e4lja on midagi kirjutatud ja kui on, siis kasutame laia otsingu loogikat. Vastasel juhul kasutame t\u00e4psetel parameetritel p\u00f5hineva otsingu loogikat.\r\n\r\nLaia otsingu funktsionaalsuse lisamiseks ning otsingute vahel valimiseks muudame meetodit <code>tulemused()<\/code> j\u00e4rgnevalt:\r\n\r\n<code><\/code>\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">@app.route('\/tulemused', methods=['GET', 'POST'])\r\ndef tulemused():\r\n    tulemused = []\r\n    o_lai = request.form['o_lai']\r\n    if o_lai != \"\":\r\n        tulemused = Teosed.query.filter(\r\n            (Teosed.pealkiri.like('%'+o_lai+'%')) |\r\n            (Teosed.zanrid.like('%'+o_lai+'%')) |\r\n            (Teosed.naitlejad.like('%'+o_lai+'%')) |\r\n            (Teosed.kirjeldus.like('%'+o_lai+'%'))\r\n        ).all()\r\n    else:\r\n        tulemused = []\r\n        o_pealkiri = request.form['o_pealkiri']\r\n        o_tuup = request.form['o_tuup']\r\n        o_riik = request.form['o_riik']\r\n        o_aasta = request.form['o_aasta']\r\n        o_zanrid = request.form['o_zanrid']\r\n        o_naitlejad = request.form['o_naitlejad']\r\n        o_kirjeldus = request.form['o_kirjeldus']\r\n        tulemused = Teosed.query.filter(\r\n            Teosed.pealkiri.like('%'+o_pealkiri+'%'),\r\n            Teosed.tuup.like('%'+o_tuup+'%'),\r\n            Teosed.riigid.like('%'+o_riigid+'%'),\r\n            Teosed.riigid.like('%'+o_aasta+'%'),\r\n            Teosed.zanrid.like('%'+o_zanrid+'%'),\r\n            Teosed.naitlejad.like('%'+o_naitlejad+'%'),\r\n            Teosed.kirjeldus.like('%'+o_kirjeldus+'%')\r\n        ).all()\r\n    return render_template('tulemused.html', tulemused=tulemused)<\/pre>\r\n<code><\/code>\r\n\r\nParameetrite p\u00f5hjal otsingu osa j\u00e4i samaks, kuid n\u00fc\u00fcd on juures ka laia otsingu loogika ning kontroll, kumba otsingut kasutada.\r\n\r\nVaatame t\u00e4psemalt \u00fcle lisatud laia otsingu loogikat. K\u00f5igepealt on n\u00e4ha, et laia otsingu sisendiv\u00e4lja v\u00e4\u00e4rtust v\u00f5rreldakse nii pealkirja, \u017eanrite, n\u00e4itlejate kui ka kirjeldusega. Soovi korral v\u00f5ib v\u00f5rdlemise aluseid ka muuta.\r\n\r\nKuna me soovime laia otsingu abil leida k\u00f5igi piirangute p\u00f5hjal leitud tulemuste \u00fchendit, oleks meil piirangute vahel vaja kasutada justkui m\u00e4rks\u00f5na <span style=\"color: #970000\"><strong>OR<\/strong><\/span>. <em>Flask-SQLAlchemy<\/em> p\u00e4ringutes paneme selle jaoks iga \u00fcksiku piirangu \u00fcmber sulud ning eraldame need omavahel s\u00fcmboliga '|'.\r\n\r\nTasub teada, et enamustes programmeerimiskeeles (kuid mitte Python'is) kasutatakse loogilise operaatori <code>or<\/code> t\u00e4histamiseks s\u00fcmbolit '|' v\u00f5i s\u00fcmboleid '||'.\r\n\r\n[h5p id=\"55\"]\r\n\r\nJooksuta n\u00fc\u00fcd uuesti faili <code>app.py<\/code>, kirjuta midagi laia otsingu sisendiv\u00e4lja ja kliki nupul <em>Otsi<\/em>. Seej\u00e4rel peaksid n\u00e4gema teoseid, mida leiti nii pealkirja, \u017eanrite, n\u00e4itlejate kui ka kirjelduse alusel. Katseta erinevaid v\u00e4\u00e4rtusi ning veendu, et kirjutades midagi laia otsingu sisendiv\u00e4lja, kasutatakse just laia otsingu loogikat, mitte t\u00e4psete parameetritega otsingu oma.\r\n\r\nSellega on otsingumootori projekt valmis, kuigi t\u00e4iendusi, mis aitavad \u00f5pitut veelgi enam kinnistada, on alati v\u00f5imalik teha.\r\n\r\n\u00dchtlasi oleme j\u00f5udnud valikmooduli \"Andmebaasi p\u00e4ringud\" l\u00f5ppu. Siiski, j\u00e4\u00e4nud on veel lisalugemise peat\u00fckk vaadete kohta, mis aitab paremini m\u00f5ista, kuidas suurtes andmebaasides ning mitmetes tabelites hoiustatavaid andmeid internetis huvitaval kujul kuvatakse.","rendered":"<h2>Veebilehe kujundamine<\/h2>\n<p>Hetkel on meie projekti, mis on n\u00e4htav veebiaadressil <a href=\"http:\/\/127.0.0.1:5000\/teosed\">127.0.0.1:5000\/teosed<\/a>, t\u00e4ielikult stiliseerimata. Kujunduse loomine aitab projekti kasutamist mugavamaks teha ning pakub ka silmailu.<\/p>\n<p>Alustame sellega, et loome projekti kausta sisse uue alamkausta <code>static<\/code>. Kausta <code>static<\/code> sisse loome alamkausta <code>css<\/code> ning selle sisse omakorda faili <code>kujundus.css<\/code>. Kuna tegemist on v\u00e4ikse projektiga, on m\u00f5istlik kasutada \u00fchte kujunduse faili k\u00f5igi vahelehtede jaoks. Hetkel on meil vahelehti k\u00fcll \u00fcks, kuid hiljem loome \u00fche juurde selleks, et n\u00e4idata otsingute tulemusi.<\/p>\n<p>Projekti kaust peaks hetkeseisuga v\u00e4lja n\u00e4gema selline:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1171\" src=\"https:\/\/web.htk.tlu.ee\/digitaru\/lisamoodulid\/wp-content\/uploads\/sites\/21\/2021\/03\/kaust3.png\" alt=\"Projekti kausta \u00fclesehitus 2\" width=\"596\" height=\"150\" srcset=\"https:\/\/web.htk.tlu.ee\/digitaru\/lisamoodulid\/wp-content\/uploads\/sites\/21\/2021\/03\/kaust3.png 596w, https:\/\/web.htk.tlu.ee\/digitaru\/lisamoodulid\/wp-content\/uploads\/sites\/21\/2021\/03\/kaust3-300x76.png 300w, https:\/\/web.htk.tlu.ee\/digitaru\/lisamoodulid\/wp-content\/uploads\/sites\/21\/2021\/03\/kaust3-65x16.png 65w, https:\/\/web.htk.tlu.ee\/digitaru\/lisamoodulid\/wp-content\/uploads\/sites\/21\/2021\/03\/kaust3-225x57.png 225w, https:\/\/web.htk.tlu.ee\/digitaru\/lisamoodulid\/wp-content\/uploads\/sites\/21\/2021\/03\/kaust3-350x88.png 350w\" sizes=\"auto, (max-width: 596px) 100vw, 596px\" \/><\/p>\n<p>Projekti kausta alamkaust <code>\/static\/css<\/code> peaks v\u00e4lja n\u00e4gema selline:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1173\" src=\"https:\/\/web.htk.tlu.ee\/digitaru\/lisamoodulid\/wp-content\/uploads\/sites\/21\/2021\/03\/kaust4.png\" alt=\"Projekti kausta alamkaust css\" width=\"596\" height=\"45\" srcset=\"https:\/\/web.htk.tlu.ee\/digitaru\/lisamoodulid\/wp-content\/uploads\/sites\/21\/2021\/03\/kaust4.png 596w, https:\/\/web.htk.tlu.ee\/digitaru\/lisamoodulid\/wp-content\/uploads\/sites\/21\/2021\/03\/kaust4-300x23.png 300w, https:\/\/web.htk.tlu.ee\/digitaru\/lisamoodulid\/wp-content\/uploads\/sites\/21\/2021\/03\/kaust4-65x5.png 65w, https:\/\/web.htk.tlu.ee\/digitaru\/lisamoodulid\/wp-content\/uploads\/sites\/21\/2021\/03\/kaust4-225x17.png 225w, https:\/\/web.htk.tlu.ee\/digitaru\/lisamoodulid\/wp-content\/uploads\/sites\/21\/2021\/03\/kaust4-350x26.png 350w\" sizes=\"auto, (max-width: 596px) 100vw, 596px\" \/><\/p>\n<p>\u00dchtse kujunduse kasutamiseks k\u00f5igis failides tuleb kujunduse fail <code>kujundus.css<\/code> \u00fchendada baasfailiga <code>baas.html<\/code>. Selleks lisame faili <code>baas.html<\/code> <code>head<\/code> siltide vahele j\u00e4rgmise rea:<\/p>\n<p><code><\/code><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"html\">&lt;link rel=\"stylesheet\" href=\"static\/css\/kujundus.css\"&gt;<\/pre>\n<p><code><\/code><\/p>\n<p>Asumegi kujundust looma. K\u00e4esolevas peat\u00fckis tuuakse jooksvalt n\u00e4iteid, kuidas projekti kujundada v\u00f5iks. Soovitatav on k\u00f5igepealt katsetada, milline n\u00e4idiskujundus v\u00e4lja n\u00e4eb ning seej\u00e4rel v\u00f5ib projekti ka oma maitse ja eelistuste p\u00f5hjal kujundama hakata.<\/p>\n<p>Esmalt muudame veebilehe v\u00e4rve, m\u00e4\u00e4rame fondi, \u00e4\u00e4riseid ja muud. Selleks lisame faili <code>kujundus.css<\/code> j\u00e4rgnevad read:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"css\">html {\r\n    background-color: #fdfdfd;\r\n}\r\n\r\nbody {\r\n    background-color: #fafafa;\r\n    width: 1200px;\r\n    font-family: Arial;\r\n    padding: 20px;\r\n    margin: 10px auto 5px auto;\r\n    box-shadow: 0 0 8px #000000;\r\n    border-radius: 10px;\r\n}<\/pre>\n<p>Kui m\u00f5ni kasutatud stiilielement j\u00e4\u00e4b kas siin v\u00f5i tulevikus segaseks, otsi kindlasti nende kohta internetist infot. \u00dcks soovitatav infoallikas on veebileht <a href=\"https:\/\/www.w3schools.com\/\">w3schools<\/a>.<\/p>\n<p>Kujundame ka teoste tabelit. Lisame sellele piirjooned, m\u00e4\u00e4rame veergude pealkirjade lahtritele teistsuguse taustav\u00e4rvi ning lisame lahtritele t\u00e4idiseid (ingl <em>padding<\/em>). Selleks lisame faili j\u00e4rgnevad read:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"css\">table, th, td {\r\n    border: 1px solid black;\r\n}\r\n\r\nth, td {\r\n    padding: 5px;\r\n}\r\n\r\ntable {\r\n    border-collapse: collapse;\r\n}\r\n\r\nth {\r\n    background-color: #c9e4eb\r\n}\r\n<\/pre>\n<p>Selleks, et hetkel kasutatud pealkirjad ning hiljem lisatavad tekstid oleksid veebilehe keskel, lisame juba praegu ka j\u00e4rgnevad read:<\/p>\n<p><code><\/code><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"css\">h1, h2, p {\r\n    text-align: center;\r\n}<\/pre>\n<p><code><\/code><\/p>\n<p>Olemegi n\u00fc\u00fcdseks suure osa kujundamisest \u00e4ra teinud, t\u00e4nu millele on veebilehel kuvatavaid andmeid m\u00e4rksa mugavam vaadelda. J\u00e4tkame n\u00fc\u00fcd funktsionaalsuste lisamisega ning edaspidi t\u00e4iendame kujunduse faili jooksvalt, siis kui selleks vajadus tekib.<\/p>\n<p>Jooksuta enne j\u00e4tkamist uuesti faili <code>app.py<\/code> ning tutvu veebirakenduse uue kujundusega.<\/p>\n<h2>Otsingufunktsiooni lisamine<\/h2>\n<p>Praeguseks on veebirakenduses n\u00e4ha kujundatud kujul Netflixi teoste infot. Seega saame keskenduda otsingufunktsioonide lisamisele. Selleks tuleb esmalt t\u00e4iendada faili <code>teosed.html<\/code>. Nimelt tuleb sinna lisada veebivorm koos sisendiv\u00e4ljadega, mille p\u00f5hjal koostatame andmebaasi p\u00e4ringuid.<\/p>\n<p>Lisame faili <code>teosed.html<\/code> ploki <code>body<\/code> algusesse j\u00e4rgnevad read:<\/p>\n<p><code><\/code><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"html\">&lt;h1&gt;Otsingumootor&lt;\/h1&gt;\r\n&lt;form action='\/tulemused' method='POST'&gt;\r\n    &lt;div class=\"sisend\"&gt;\r\n        &lt;label&gt;Pealkiri:&lt;\/label&gt;\r\n        &lt;input type='text' name='o_pealkiri' id='o_pealkiri'&gt;\r\n    &lt;\/div&gt;\r\n    &lt;input type='submit' value='Otsi' class=\"nupp\"&gt;\r\n    &lt;input type='reset' value='T\u00fchjenda' class=\"nupp\"&gt;\r\n&lt;\/form&gt;\r\n&lt;br&gt;<\/pre>\n<p><code><\/code><\/p>\n<p>Nagu n\u00e4ha, l\u00f5ime HTML-i <code>form<\/code> siltide abil veebivormi, kus on hetkel vaid \u00fcks sisendiv\u00e4li (<code>input<\/code> siltide vahel) otsitava teose pealkirja jaoks. Lisaks on seal nupp <em>T\u00fchjenda<\/em>, millele klikates t\u00fchjendatakse k\u00f5ik veebivormi sisendiv\u00e4ljad ning nupp <em>Ots<\/em><em>i<\/em>, millele vajutamisel suunatakse meid meetodiga <code>POST<\/code> aadressile <a href=\"http:\/\/127.0.0.1:5000\/tulemused\">127.0.0.1:5000\/tulemused<\/a>. Kuna me pole sellist vahelehte veel loonud, tuleb praegu nupule <em>Otsi<\/em> vajutades veateade <em>Not Found<\/em>. Nupp <em>T\u00fchjenda<\/em> juba t\u00f6\u00f6tab.<\/p>\n<p>Kujundame loodud ja tulevasi sisendiv\u00e4lju. Lisame selleks faili <code>kujundus.css<\/code> j\u00e4rgnevad read:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"css\">input {\r\n    padding: 4px;\r\n}\r\n\r\n.sisend {\r\n    display: inline-block;\r\n}\r\n\r\n.sisend label {\r\n    display: block;\r\n}<\/pre>\n<p>Lisasime nii sisendiv\u00e4ljadele kui ka nuppudele t\u00e4idised ning m\u00e4\u00e4rasime, et sisendiv\u00e4lja pealkirjad oleksid sisendiv\u00e4ljade kohal. Seda ka siis, kui sisendiv\u00e4lju hiljem juurde lisada. Otsi vajadusel internetist, mida t\u00e4hendavad <code>inline-block<\/code> ja <code>block<\/code>. Nende m\u00f5istmine tuleb kindlasti igasugusel veebiarendusel kasuks.<\/p>\n<p>J\u00e4rgmisena t\u00e4iendame faili <code>app.py<\/code>, kuhu kirjutame andmebaasi p\u00e4ringu koostamise loogika.<\/p>\n<p>Alustuseks tuleb moodulist <em>flask<\/em> importida lisaks varasemale ka <em>request<\/em>. Seega peaks importide osa n\u00fc\u00fcdseks v\u00e4lja n\u00e4gema selline:<\/p>\n<p><code><\/code><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">from flask import Flask, render_template, request\r\nfrom flask_sqlalchemy import SQLAlchemy<\/pre>\n<p><code><\/code><\/p>\n<p>Seej\u00e4rel lisame p\u00e4rast meetodit <code>teosed()<\/code> j\u00e4rgnevad koodiread:<\/p>\n<p><code><\/code><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">@app.route('\/tulemused', methods=['GET', 'POST'])\r\ndef tulemused():\r\n    tulemused = []\r\n    o_pealkiri = request.form['o_pealkiri']\r\n    tulemused = Teosed.query.filter(Teosed.pealkiri.like('%'+o_pealkiri+'%')).all()\r\n    return render_template('tulemused.html', tulemused=tulemused)<\/pre>\n<p><code><\/code><\/p>\n<p>Sellega n\u00e4itame, mis juhtub, kui minna aadressile <a href=\"http:\/\/127.0.0.1:5000\/tulemused\">127.0.0.1:5000\/tulemused<\/a>. Seal aadressil pole endiselt veel midagi, kuna selle sisu renderdatakse faili <code>tulemused.html<\/code> p\u00f5hjal, mida me veel loonud ei ole. Teeme seda peatselt, kuid enne vaatame lisatud koodiread \u00fcle.<\/p>\n<p>Reaga <code><code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">o_pealkiri = request.form['o_pealkiri']<\/code><\/code><code><\/code> v\u00e4\u00e4rtustame me muutuja <code>o_pealkiri<\/code> veebivormist saadud pealkirja sisendiv\u00e4lja v\u00e4\u00e4rtusega. Seej\u00e4rel me loome p\u00e4ringu tabelist Teosed sellise piiranguga, et <code>o_pealkiri<\/code> v\u00e4\u00e4rtus peab esinema teose pealkirja sees. Pane t\u00e4hele koodireas kasutatud m\u00e4rks\u00f5na <code>like<\/code> ning tuleta meelde, kuidas see <em>PostgreSQL&#8217;<\/em>s t\u00f6\u00f6tas.<\/p>\n<p>Tasub teada, et siin ei eristata v\u00e4\u00e4rtuste puhul suur- ja v\u00e4iket\u00e4hti. Seega on n\u00e4iteks pealkirja v\u00e4\u00e4rtused &#8216;love&#8217; ja &#8216;LoVe&#8217; siinkohal v\u00f5rdsed.<\/p>\n<div id=\"h5p-54\">\n<div class=\"h5p-iframe-wrapper\"><iframe id=\"h5p-iframe-54\" class=\"h5p-iframe\" data-content-id=\"54\" style=\"height:1px\" src=\"about:blank\" frameBorder=\"0\" scrolling=\"no\" title=\"AP_21_kontrollk\u00fcsimus_1\"><\/iframe><\/div>\n<\/div>\n<p>Meetodi viimase rea abil renderdame aadressil <a href=\"http:\/\/127.0.0.1:5000\/tulemused\">127.0.0.1:5000\/tulemused<\/a> faili <code>tulemused.html<\/code> ning anname selle faili argumendi <code>tulemused<\/code> v\u00e4\u00e4rtuseks p\u00e4ringust saadud tulemuste listi.<\/p>\n<p>N\u00fc\u00fcd on j\u00e4\u00e4nud veel luua fail <code>tulemused.html<\/code>, p\u00e4rast mida saamegi pealkirja p\u00f5hjal otsimist katsetada. Faili <code>tulemused.html<\/code> \u00fclesehitus on v\u00e4ga sarnane faili <code>teosed.html<\/code> algse \u00fclesehitusega.<\/p>\n<p>Lisame faili <code>tulemused.html<\/code> j\u00e4rgnevad read:<\/p>\n<p><code><\/code><code><\/code><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"html\">{% extends 'baas.html' %}\r\n{% block head %} &lt;title&gt;Otsingu tulemused&lt;\/title&gt; {% endblock %}\r\n{% block body %}\r\n&lt;h1&gt;Otsingu tulemused&lt;\/h1&gt;\r\n&lt;table&gt;\r\n    &lt;tr&gt;\r\n        &lt;th&gt;Pealkiri&lt;\/th&gt;\r\n        &lt;th&gt;T\u00fc\u00fcp&lt;\/th&gt;\r\n        &lt;th&gt;Riigid&lt;\/th&gt;\r\n        &lt;th&gt;Aasta&lt;\/th&gt;\r\n        &lt;th&gt;\u017danrid&lt;\/th&gt;\r\n        &lt;th&gt;N\u00e4itlejad&lt;\/th&gt;\r\n        &lt;th&gt;Kirjeldus&lt;\/th&gt;\r\n    &lt;\/tr&gt;\r\n    {% for teos in tulemused %}\r\n        &lt;tr&gt;\r\n            &lt;td&gt;{{ teos.pealkiri }}&lt;\/td&gt;\r\n            &lt;td&gt;{{ teos.tuup }}&lt;\/td&gt;\r\n            &lt;td&gt;{{ teos.riigid }}&lt;\/td&gt;\r\n            &lt;td&gt;{{ teos.valjalaske_aasta }}&lt;\/td&gt;\r\n            &lt;td&gt;{{ teos.zanrid }}&lt;\/td&gt;\r\n            &lt;td&gt;{{ teos.naitlejad }}&lt;\/td&gt;\r\n            &lt;td&gt;{{ teos.kirjeldus }}&lt;\/td&gt;\r\n        &lt;\/tr&gt;\r\n    {% endfor %}\r\n&lt;\/table&gt;\r\n{% endblock %}<\/pre>\n<p><code><\/code><\/p>\n<p>Jooksuta n\u00fc\u00fcd uuesti faili <code>app.py<\/code>. Kirjuta seej\u00e4rel midagi pealkirja sisendiv\u00e4lja ja kliki nupule <em>Ots<\/em><em>i<\/em> ning sind suunatakse \u00fcmber aadressile <a href=\"http:\/\/127.0.0.1:5000\/tulemused\">127.0.0.1:5000\/tulemused<\/a>, kus on n\u00e4ha k\u00f5iki teoseid, mis leiti sisestatud pealkirja v\u00e4\u00e4rtuse p\u00f5hjal. Katseta otsimist erinevate sisendiv\u00e4\u00e4rtustega.<\/p>\n<p>Nagu n\u00e4ha on ka veebirakenduse tulemuste vaheleht kujundatud. Seda m\u00e4letatavasti seet\u00f5ttu, et ka failis <code>tulemused.html<\/code> viitame baasfailile <code>baas.html<\/code>, mis omakorda viitab kujunduse failile <code>kujundus.css<\/code>.<\/p>\n<h3>Mitme parameetri p\u00f5hjal otsing<\/h3>\n<p>Kuigi pealkirja alusel otsimine t\u00e4itsa t\u00f6\u00f6tab, oleks siiski m\u00f5istlik kasutajatele rohkem otsinguparameetreid pakkuda. N\u00e4iteks ei saa praeguse lahenduse korral otsida teoseid n\u00e4itlejate v\u00f5i riikide p\u00f5hjal.<\/p>\n<p>\u00d5nneks sarnaneb uute otsinguparameetrite lisamine varasemalt tehtuga. Alustame taaskord sellest, et lisame uued sisendiv\u00e4ljad faili <code>teosed.html<\/code>.<\/p>\n<p>Lisame sisendiv\u00e4ljad t\u00fc\u00fcbi, riikide, aasta, \u017eanrite, n\u00e4itlejate ja kirjelduse jaoks. Selleks kustutame failist <code>teosed.html<\/code> k\u00f5ik <code>form<\/code> siltide vahel olevad koodiread, v\u00e4lja arvatud <em>Otsi<\/em> ja\u00a0<em>T\u00fchjenda<\/em> nuppude osad ning lisame kustutatud ridade asemele j\u00e4rgnevad read:<\/p>\n<p><code><\/code><code><\/code><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"html\">&lt;h2&gt;T\u00e4psete parameetritega otsing&lt;\/h2&gt;\r\n&lt;div class=\"sisend\"&gt;\r\n    &lt;label&gt;Pealkiri:&lt;\/label&gt;\r\n    &lt;input type='text' name='o_pealkiri' id='o_pealkiri'&gt;\r\n&lt;\/div&gt;\r\n&lt;div class=\"sisend\"&gt;\r\n    &lt;label for=\"o_tuup\"&gt;T\u00fc\u00fcp:&lt;\/label&gt;\r\n    &lt;select id=\"o_tuup\" name=\"o_tuup\"&gt;\r\n        &lt;option value=\"\" selected&gt;-&lt;\/option&gt;\r\n        &lt;option value=\"Movie\"&gt;Movie&lt;\/option&gt;\r\n        &lt;option value=\"TV Show\"&gt;TV Show&lt;\/option&gt;\r\n    &lt;\/select&gt;\r\n&lt;\/div&gt;\r\n&lt;div class=\"sisend\"&gt;\r\n    &lt;label&gt;Riigid:&lt;\/label&gt;\r\n    &lt;input type='text' name='o_riigid' id='o_riigid'&gt;\r\n&lt;\/div&gt;\r\n&lt;div class=\"sisend\"&gt;\r\n    &lt;label&gt;Aasta:&lt;\/label&gt;\r\n    &lt;input type='number' name='o_aasta' id='o_aasta'&gt;\r\n&lt;\/div&gt;\r\n&lt;div class=\"sisend\"&gt;\r\n    &lt;label&gt;\u017danrid:&lt;\/label&gt;\r\n    &lt;input type='text' name='o_zanrid' id='o_zanrid'&gt;\r\n&lt;\/div&gt;\r\n&lt;div class=\"sisend\"&gt;\r\n    &lt;label&gt;N\u00e4itlejad:&lt;\/label&gt;\r\n    &lt;input type='text' name='o_naitlejad' id='o_naitlejad'&gt;\r\n&lt;\/div&gt;\r\n&lt;div class=\"sisend\"&gt;\r\n    &lt;label&gt;Kirjeldus:&lt;\/label&gt;\r\n    &lt;input type='text' name='o_kirjeldus' id='o_kirjeldus'&gt;\r\n&lt;\/div&gt;<\/pre>\n<p><code><\/code><\/p>\n<p>Nagu n\u00e4ha, on enamik sisendiv\u00e4lju \u00fclesehituse poolest pealkirja omaga identsed. Peamiste erinevustena lubame aasta jaoks vaid numbreid ning t\u00fc\u00fcbi valiku lahendasime ripploendiga. Ripploendis pakume v\u00e4\u00e4rtustena v\u00f5imalusi &#8216;Movie&#8217;, &#8216;TV Show&#8217; ja ka vaikev\u00e4\u00e4rtust &#8216;-&#8216; (mille tegelik v\u00e4\u00e4rtus on t\u00fchi s\u00f5ne).<\/p>\n<p>Selleks, et ka kasutatud ripploend ning varem lisatud nupud kenamad v\u00e4lja n\u00e4eks, lisame faili <code>kujundus.css<\/code> j\u00e4rgnevad read:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"css\">select {\r\n    padding: 5px;\r\n}\r\n\r\n.nupp {\r\n    width: 80px;\r\n    text-transform: uppercase;\r\n}<\/pre>\n<p>N\u00fc\u00fcd on taaskord tarvis t\u00e4iendada <code>app.py<\/code> loogikat. Kuna meil on sisendiv\u00e4lju mitu, tahame, et otsingu tulemuses oleks vaid sellised teosed, mis vastavad k\u00f5igi sisendiv\u00e4ljade v\u00e4\u00e4rtustele. Seega on sisendiv\u00e4ljade v\u00e4\u00e4rtustel p\u00f5hinevad piirangud vaja omavahel \u00fchendada justkui m\u00e4rks\u00f5naga <code><span style=\"color: #970000\"><strong>AND<\/strong><\/span><\/code>. Siinkohal pole aga m\u00e4rks\u00f5na <code><span style=\"color: #970000\"><strong>AND<\/strong><\/span><\/code> tarvis eraldi v\u00e4lja vaja kirjutada, piisab vaid sellest, kui eraldame piirangud omavahel komadega.<\/p>\n<p>Muudame seega meetodit <code>tulemused()<\/code> j\u00e4rgnevalt:<\/p>\n<p><code><\/code><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">@app.route('\/tulemused', methods=['GET', 'POST'])\r\ndef tulemused():\r\n    tulemused = []\r\n    o_pealkiri = request.form['o_pealkiri']\r\n    o_tuup = request.form['o_tuup']\r\n    o_riigid = request.form['o_riigid']\r\n    o_aasta = request.form['o_aasta']\r\n    o_zanrid = request.form['o_zanrid']\r\n    o_naitlejad = request.form['o_naitlejad']\r\n    o_kirjeldus = request.form['o_kirjeldus']\r\n    tulemused = Teosed.query.filter(\r\n        Teosed.pealkiri.like('%'+o_pealkiri+'%'),\r\n        Teosed.tuup.like('%'+o_tuup+'%'),\r\n        Teosed.riigid.like('%'+o_riigid+'%'),\r\n        Teosed.valjalaske_aasta.like('%'+o_aasta+'%'),\r\n        Teosed.zanrid.like('%'+o_zanrid+'%'),\r\n        Teosed.naitlejad.like('%'+o_naitlejad+'%'),\r\n        Teosed.kirjeldus.like('%'+o_kirjeldus+'%')\r\n    ).all()\r\n    return render_template('tulemused.html', tulemused=tulemused)<\/pre>\n<p><code><\/code><\/p>\n<p>Nagu n\u00e4ha, v\u00e4\u00e4rtustasime k\u00f5igepealt k\u00f5igi sisendiv\u00e4ljade p\u00f5hjal neile vastavad muutujad. Seej\u00e4rel kasutasime neid k\u00f5iki ka p\u00e4ringu piiramiseks, eraldades need omavahel komadega.<\/p>\n<div id=\"h5p-56\">\n<div class=\"h5p-iframe-wrapper\"><iframe id=\"h5p-iframe-56\" class=\"h5p-iframe\" data-content-id=\"56\" style=\"height:1px\" src=\"about:blank\" frameBorder=\"0\" scrolling=\"no\" title=\"AP_21_kontrollk\u00fcsimus_3\"><\/iframe><\/div>\n<\/div>\n<p>Jooksuta n\u00fc\u00fcd uuesti faili <code>app.py<\/code>, kirjuta midagi erinevatesse sisendiv\u00e4ljadesse ning kliki nupule <em>Ots<\/em><em>i<\/em>. Taaskord suunatakse sind \u00fcmber aadressile <a href=\"http:\/\/127.0.0.1:5000\/tulemused\">127.0.0.1:5000\/tulemused<\/a>, kuid seekord p\u00f5hineb otsingu tulemus k\u00f5igil sisenditel, kuhu mingi v\u00e4\u00e4rtus sisestati. Kui piirangud on liiga kitsad, v\u00f5ib tulemuste tabel ka t\u00fchi olla.<\/p>\n<h3>Laia otsingu lisamine<\/h3>\n<p>Proovime n\u00fc\u00fcd lisada ka uut Google&#8217;ga sarnast otsingut. Selleks lisame \u00fche eraldiseisva suure sisendiv\u00e4lja.<\/p>\n<p>Kui kasutaja kirjutab midagi suurde sisendiv\u00e4lja ning klikib nupule <em>Otsi<\/em>, v\u00f5rreldakse sisendiv\u00e4lja v\u00e4\u00e4rtust erinevate meie valitud tunnustega. Kasutame siinkohal v\u00f5rdluse aluseks tunnuseid pealkiri, \u017eanrid, n\u00e4itlejad ja kirjeldus.<\/p>\n<p>Esimese sammuna t\u00e4iendame j\u00e4llegi faili <code>teosed.html<\/code>. Lisame <code>form<\/code> siltide vahele, p\u00e4rast nuppe <em>Otsi<\/em> ja <em>T\u00fchjenda<\/em>, j\u00e4rgnevad read:<\/p>\n<p><code><\/code><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"html\">&lt;h2&gt;Lai otsing&lt;\/h2&gt;\r\n&lt;p&gt;Kui kasutad laia otsingut, siis t\u00e4pse otsingu parameetreid arvesse ei v\u00f5eta.&lt;p&gt;\r\n&lt;input type='text' name='o_lai' id='o_lai'&gt;\r\n&lt;input type='submit' value='Otsi' class=\"nupp\"&gt;<\/pre>\n<p><code><\/code><\/p>\n<p>Tegemist on tavap\u00e4rase sisendiv\u00e4ljaga, mille k\u00f5rval on eraldi otsingunupp. Tegelikkuses on see nupp siiski samav\u00e4\u00e4rne juba varem lisatud otsingunupuga ning funktsionaalsuse poolest ei ole vahet, kummale neist klikata.<\/p>\n<p>Selleks, et uus sisendiv\u00e4li t\u00f5epoolest suur ja lai oleks, lisame faili <code>kujundus.css<\/code> j\u00e4rgnevad read:<\/p>\n<p><code><\/code><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"css\">#o_lai {\r\n    width: 1100px;\r\n}<\/pre>\n<p><code><\/code><\/p>\n<p>Sellega on \u00fchtlasi kujundamise osa l\u00e4bi ning siinkohal v\u00f5ib faili <code>kujundus.css<\/code> sulgeda, kui pole just soovi otsingumootori v\u00e4limust ka ise kohandada.<\/p>\n<p>N\u00fc\u00fcd on j\u00e4\u00e4nud t\u00e4iendada fail <code>app.py<\/code>. Lahendame siinkohal olukorra, kumba otsingut peaks programm <em>Otsi<\/em> nuppudele vajutamisel kasutama, m\u00f5nev\u00f5rra naiivselt. Nimelt, kontrollime, kas laia otsingu sisendiv\u00e4lja on midagi kirjutatud ja kui on, siis kasutame laia otsingu loogikat. Vastasel juhul kasutame t\u00e4psetel parameetritel p\u00f5hineva otsingu loogikat.<\/p>\n<p>Laia otsingu funktsionaalsuse lisamiseks ning otsingute vahel valimiseks muudame meetodit <code>tulemused()<\/code> j\u00e4rgnevalt:<\/p>\n<p><code><\/code><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">@app.route('\/tulemused', methods=['GET', 'POST'])\r\ndef tulemused():\r\n    tulemused = []\r\n    o_lai = request.form['o_lai']\r\n    if o_lai != \"\":\r\n        tulemused = Teosed.query.filter(\r\n            (Teosed.pealkiri.like('%'+o_lai+'%')) |\r\n            (Teosed.zanrid.like('%'+o_lai+'%')) |\r\n            (Teosed.naitlejad.like('%'+o_lai+'%')) |\r\n            (Teosed.kirjeldus.like('%'+o_lai+'%'))\r\n        ).all()\r\n    else:\r\n        tulemused = []\r\n        o_pealkiri = request.form['o_pealkiri']\r\n        o_tuup = request.form['o_tuup']\r\n        o_riik = request.form['o_riik']\r\n        o_aasta = request.form['o_aasta']\r\n        o_zanrid = request.form['o_zanrid']\r\n        o_naitlejad = request.form['o_naitlejad']\r\n        o_kirjeldus = request.form['o_kirjeldus']\r\n        tulemused = Teosed.query.filter(\r\n            Teosed.pealkiri.like('%'+o_pealkiri+'%'),\r\n            Teosed.tuup.like('%'+o_tuup+'%'),\r\n            Teosed.riigid.like('%'+o_riigid+'%'),\r\n            Teosed.riigid.like('%'+o_aasta+'%'),\r\n            Teosed.zanrid.like('%'+o_zanrid+'%'),\r\n            Teosed.naitlejad.like('%'+o_naitlejad+'%'),\r\n            Teosed.kirjeldus.like('%'+o_kirjeldus+'%')\r\n        ).all()\r\n    return render_template('tulemused.html', tulemused=tulemused)<\/pre>\n<p><code><\/code><\/p>\n<p>Parameetrite p\u00f5hjal otsingu osa j\u00e4i samaks, kuid n\u00fc\u00fcd on juures ka laia otsingu loogika ning kontroll, kumba otsingut kasutada.<\/p>\n<p>Vaatame t\u00e4psemalt \u00fcle lisatud laia otsingu loogikat. K\u00f5igepealt on n\u00e4ha, et laia otsingu sisendiv\u00e4lja v\u00e4\u00e4rtust v\u00f5rreldakse nii pealkirja, \u017eanrite, n\u00e4itlejate kui ka kirjeldusega. Soovi korral v\u00f5ib v\u00f5rdlemise aluseid ka muuta.<\/p>\n<p>Kuna me soovime laia otsingu abil leida k\u00f5igi piirangute p\u00f5hjal leitud tulemuste \u00fchendit, oleks meil piirangute vahel vaja kasutada justkui m\u00e4rks\u00f5na <span style=\"color: #970000\"><strong>OR<\/strong><\/span>. <em>Flask-SQLAlchemy<\/em> p\u00e4ringutes paneme selle jaoks iga \u00fcksiku piirangu \u00fcmber sulud ning eraldame need omavahel s\u00fcmboliga &#8216;|&#8217;.<\/p>\n<p>Tasub teada, et enamustes programmeerimiskeeles (kuid mitte Python&#8217;is) kasutatakse loogilise operaatori <code>or<\/code> t\u00e4histamiseks s\u00fcmbolit &#8216;|&#8217; v\u00f5i s\u00fcmboleid &#8216;||&#8217;.<\/p>\n<div id=\"h5p-55\">\n<div class=\"h5p-iframe-wrapper\"><iframe id=\"h5p-iframe-55\" class=\"h5p-iframe\" data-content-id=\"55\" style=\"height:1px\" src=\"about:blank\" frameBorder=\"0\" scrolling=\"no\" title=\"AP_21_kontrollk\u00fcsimus_2\"><\/iframe><\/div>\n<\/div>\n<p>Jooksuta n\u00fc\u00fcd uuesti faili <code>app.py<\/code>, kirjuta midagi laia otsingu sisendiv\u00e4lja ja kliki nupul <em>Otsi<\/em>. Seej\u00e4rel peaksid n\u00e4gema teoseid, mida leiti nii pealkirja, \u017eanrite, n\u00e4itlejate kui ka kirjelduse alusel. Katseta erinevaid v\u00e4\u00e4rtusi ning veendu, et kirjutades midagi laia otsingu sisendiv\u00e4lja, kasutatakse just laia otsingu loogikat, mitte t\u00e4psete parameetritega otsingu oma.<\/p>\n<p>Sellega on otsingumootori projekt valmis, kuigi t\u00e4iendusi, mis aitavad \u00f5pitut veelgi enam kinnistada, on alati v\u00f5imalik teha.<\/p>\n<p>\u00dchtlasi oleme j\u00f5udnud valikmooduli &#8220;Andmebaasi p\u00e4ringud&#8221; l\u00f5ppu. Siiski, j\u00e4\u00e4nud on veel lisalugemise peat\u00fckk vaadete kohta, mis aitab paremini m\u00f5ista, kuidas suurtes andmebaasides ning mitmetes tabelites hoiustatavaid andmeid internetis huvitaval kujul kuvatakse.<\/p>\n","protected":false},"author":32,"menu_order":10,"template":"","meta":{"pb_show_title":"on","pb_short_title":"","pb_subtitle":"","pb_authors":[],"pb_section_license":""},"chapter-type":[],"contributor":[],"license":[],"class_list":["post-246","chapter","type-chapter","status-publish","hentry"],"part":31,"_links":{"self":[{"href":"https:\/\/web.htk.tlu.ee\/digitaru\/lisamoodulid\/wp-json\/pressbooks\/v2\/chapters\/246","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/web.htk.tlu.ee\/digitaru\/lisamoodulid\/wp-json\/pressbooks\/v2\/chapters"}],"about":[{"href":"https:\/\/web.htk.tlu.ee\/digitaru\/lisamoodulid\/wp-json\/wp\/v2\/types\/chapter"}],"author":[{"embeddable":true,"href":"https:\/\/web.htk.tlu.ee\/digitaru\/lisamoodulid\/wp-json\/wp\/v2\/users\/32"}],"version-history":[{"count":69,"href":"https:\/\/web.htk.tlu.ee\/digitaru\/lisamoodulid\/wp-json\/pressbooks\/v2\/chapters\/246\/revisions"}],"predecessor-version":[{"id":1396,"href":"https:\/\/web.htk.tlu.ee\/digitaru\/lisamoodulid\/wp-json\/pressbooks\/v2\/chapters\/246\/revisions\/1396"}],"part":[{"href":"https:\/\/web.htk.tlu.ee\/digitaru\/lisamoodulid\/wp-json\/pressbooks\/v2\/parts\/31"}],"metadata":[{"href":"https:\/\/web.htk.tlu.ee\/digitaru\/lisamoodulid\/wp-json\/pressbooks\/v2\/chapters\/246\/metadata\/"}],"wp:attachment":[{"href":"https:\/\/web.htk.tlu.ee\/digitaru\/lisamoodulid\/wp-json\/wp\/v2\/media?parent=246"}],"wp:term":[{"taxonomy":"chapter-type","embeddable":true,"href":"https:\/\/web.htk.tlu.ee\/digitaru\/lisamoodulid\/wp-json\/pressbooks\/v2\/chapter-type?post=246"},{"taxonomy":"contributor","embeddable":true,"href":"https:\/\/web.htk.tlu.ee\/digitaru\/lisamoodulid\/wp-json\/wp\/v2\/contributor?post=246"},{"taxonomy":"license","embeddable":true,"href":"https:\/\/web.htk.tlu.ee\/digitaru\/lisamoodulid\/wp-json\/wp\/v2\/license?post=246"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}