Viikon 1 etapit
  • Olet asentanut kurssilla tarvittavat työvälineet.
  • Olet lukenut materiaalissa olevan lyhyen Python-oppaan ja kokeillut siinä olevia esimerkkejä.
  • Olet tutustunut web-sovellusten toimintaan ja toteuttanut tämän sivun ohjeistusta noudattaen ensimmäisen Flaskia käyttävän web-sovelluksesi.
  • Olet valinnut harjoitustyöllesi aiheen.
  • Olet luonut harjoitustyölle github-repositoryn, jossa on lyhyt kuvaus harjoitustyön aiheesta.
  • Olet luonut tämän sivun ohjeistusta noudattaen projektillesi sivun Herokuun.

Web-sovellusten perusteet

Web-sovellukset koostuvat selain- ja palvelinpuolesta. Käyttäjä käyttää selainohjelmistoa (esim. Chrome, kännykän selain, pädin selain, Kindlen selain, ...), joka tekee käyttäjän toimien perusteella pyyntöjä verkossa sijaitsevalle palvelimelle. Kun palvelin vastaanottaa pyynnön, se käsittelee pyynnön ja rakentaa vastauksen. Vastaus voi sisältää esimerkiksi web-sivun HTML-koodia tai jossain muussa muodossa olevaa tietoa.

Palvelin on kone aivan samalla tavalla kuin kännykkä, kannettava tietokone, pädi ym on kone. Kumpikin on kiinni verkossa, ja kummallakin on (ainakin välillisesti) koneen tunnistava IP-osoite. Kun käyttäjä tekee selainohjelmistolla pyynnön, pyyntö ohjautuu käyttäjän koneen verkkoyhteyden kautta palvelimen koneelle, jossa palvelinohjelmisto vastanottaa pyynnön ja käsittelee sen. Vaikka käyttäjä hakee tyypillisesti tekstimuotoisia osoitteita kuten https://www.helsinki.fi/fi, ei koneet näistä ymmärrä -- verkossa on erilliset palvelut tekstimuotoisten osoitteiden muuntamiseksi IP-osoitteiksi.

Selaimen tekemät pyynnöt noudattavat HTTP-protokollaa, joka on määritelty standardi pyyntöjen tekemiseen sekä niiden käsittelyyn. Resurssien -- eli tietyn osoitteen polkujen -- hakeminen tapahtuu HTTP-protokollan GET-tyyppisillä pyynnöillä, kun taas tiedon lähettäminen tapahtuu HTTP-protokollan POST-tyyppisillä pyynnöillä.

Selaimet tarjoavat tyypillisesti mahdollisuuden haettavien resurssien tarkasteluun. Esimerkiksi Google Chromessa selaintyövälineet saa auki painamalla näppäinyhdistelmää Ctrl+Shift+I tai valitsemalla Chromen valikosta Developer Tools. Selaimen työvälineet näyttävät seuraavalta.

 

Kun selaimeen kirjoittaa osoitteen -- alla olevassa esimerkissä https://www.helsinki.fi/fi -- tekee selain GET-tyyppisen pyynnön osoitteeseen eli hakee osoitteessa olevalta palvelimelta polun osoittamaa resurssia.

Kun palvelin palauttaa resurssin, tyypillisesti HTML-kielisen sivun, voi resurssissa olla linkkejä myös toisiin resursseihin. Selaimet on ohjelmointu siten, että esimerkiksi HTML-kielisen sivun resurssit haetaan automaattisesti. Yhtä sivua haettaessa saatetaan noutaakin todellisuudessa kymmeniä ellei satoja resursseja.

 

Yllä olevassa kuvassa osoitteessa https://www.helsinki.fi/fi olevan sivun lataus on vielä kesken. Sivua rakennettaessa on tehty 101 pyyntöä, ja tietoa on siirretty 1.6 megatavua.

Web-sovellusten kehitys on tapana jakaa selainohjelmistojen kehitykseen ja palvelinohjelmistojen kehitykseen, vaikkakin nykyään molemmat kattava fullstack-kehitys on yhä suositumpaa.

Selainohjelmistoja ja käyttöliittymää kehitettäessä painotetaan rakenteen, ulkoasun ja toiminnallisuuden erottamista toisistaan. Karkeasti voidaan sanoa, että selaimessa näkyvän sivun sisältö ja rakenne määritellään HTML-tiedostoilla, ulkoasu CSS-tiedostoilla ja toiminnallisuus JavaScript-tiedostoilla.

Palvelinpuolen toiminnallisuutta toteutettaessa keskitytään tyypillisesti selainohjelmiston tarvitsevan "APIn" suunnitteluun ja toteutukseen, sivujen muodostamiseen selainohjelmistoa varten, datan tallentamiseen ja käsittelyyn, sekä sellaisten laskentaoperaatioiden toteuttamiseen, joita selainohjelmistossa ei kannata tai voida tehdä.

Web-kehitys Flask-kirjastolla

Harjoitustyössä käytetään Pythonin Flask-kirjastoa web-sovelluksen toiminnallisuuden toteuttamiseen. Tutustutaan lyhyesti pienen Flask-sovelluksen toteuttamiseen.

Virtuaaliympäristön luominen

Luodaan ensin hakemisto sovellustamme varten ja luodaan sen sisälle Python-virtuaaliympäristö komennolla python3 -m venv venv. Kutsutaan sovellusta nimellä demo.

$ ls
$ mkdir demo
$ ls
demo
$ cd demo
~/demo$ python3 -m venv venv
~/demo$ ls
venv
$ 

Nyt luomallamme virtuaaliympäristöllä on kansio venv. Tarkastellaan sen sisältöä.

~/demo$ ls venv
bin  include  lib  lib64  pyvenv.cfg  share
$

Kansiossa on kansiot bin, include, lib ja share. Kansio lib64 on todellisuudessa linkki kansioon lib. Tiedosto pyvenv.cfg sisältää virtuaaliympäristön asetukset.

Kun haluamme ottaa luodun virtuaalisen Python-ympäristön käyttöön, aktivoimme sen komennolla source venv/bin/activate. Muuttuneesta komentokehoitteesta näkee että virtuaaliympäristö on aktiivinen.

~/demo$ source venv/bin/activate
(venv) ~/demo$

Haluamme lisätä käyttöömme Flask-kirjaston. Tämä onnistuu kansiossa bin olevalla pip-kemonnolla.

(venv) ~/demo$ pip install Flask
....
....
You are using pip version 8.1.1, however version 9.0.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
(venv) ~/demo$ 

Flask-kirjaston asentamisen yhteydessä saimme tiedon siitä, että käytössä oleva pip on vanhahko. Päivitetään se samalla.

(venv) ~/demo$ pip install --upgrade pip
Collecting pip
  Using cached pip-9.0.1-py2.py3-none-any.whl
    Installing collected packages: pip
Found existing installation: pip 8.1.1
  Uninstalling pip-8.1.1:
    Successfully uninstalled pip-8.1.1
Successfully installed pip-9.0.1
(venv) ~/demo$ ls venv
bin  include  lib  lib64  pip-selfcheck.json  pyvenv.cfg  share
(venv) ~/demo$

Käytössämme on nyt Flask, jonka lisäksi versionhallinnassa käytetyn pipin versiota on päivitetty.

Ensimmäinen Flask-sovellus

Flask-kirjaston etusivulla on seuraava lähdekoodi.

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

Luodaan uusi tiedosto hello.py edellä luotuun demo-kansioomme ja kopioidaan esimerkkilähdekoodi tiedoston hello.py sisällöksi. Suoritetaan tämän jälkeen tiedoston hello.py lähdekoodi.

(venv) ~/demo$ ls
hello.py  venv
(venv) ~/demo$ python3 hello.py
(venv) ~/demo$

Mitään ei tapahtunut. Huraa?

Flask-sovellusten käynnistäminen suoraan tiedostosta vaatii sovellukseen vielä ohjeistuksen komentoriviltä käynnistämiseen. Lisätään hello.py-tiedostoon vielä muutama rivi, jotka ohjeistavat sovelluksen käynnistämiseen kun se suoritetaan komentoriviltä.

from flask import Flask
app = Flask(__name__)
  
@app.route("/")
def hello():
    return "Hello World!"

if __name__ == "__main__":
    app.run()

Kokeillaan sovelluksen käynnistämistä uudestaan.

(venv) ~/demo$ ls
hello.py  venv
(venv) ~/demo$ python3 hello.py
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

Sovellus on nyt käynnissä. Kun menemme selaimella osoitteeseen http://127.0.0.1:5000/, näemme seuraavanlaisen sivun.

 

Sovellus on käynnissä! Huomaamme, että komentoriville on ilmestynyt muutamia lisärivejä. Rivit kuvaavat ovat palvelinohjelmiston logirivejä ja ne kertovat palvelimelle tulleista pyynnöistä.

Palvelimelle on tullut oikeastaan kaksi pyyntöä, vaikka haimme sivua vain kerran. Ensimmäinen pyyntö "GET / HTTP/1.1" haki tietoa sovelluksen juuripolusta. Tämä on oikeastaan juuri se, mitä sovelluksemme metodi hello() käsittelee. Toinen pyyntö "GET /favicon.ico HTTP/1.1" haki sivulle ikonia -- palvelimelta ei tällaista löytynyt.

(venv) ~/demo$ ls
hello.py  venv
(venv) ~/demo$ python3 hello.py
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
127.0.0.1 - - [29/Feb/2018 18:07:31] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [29/Feb/2018 18:07:31] "GET /favicon.ico HTTP/1.1" 404 -

Palvelimen sammuttaminen onnistuu komentoriviltä painamalla CTRL+C, eli näppäimiä ctrl ja c samanaikaisesti.

Debug-moodi

Lähdekooditiedoston hello.py suorittaminen käynnistää palvelinohjelmiston.

(venv) ~/demo$ ls
hello.py  venv
(venv) ~/demo$ python3 hello.py
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

Kun sovellus on käynnissä, muokkaukset tiedostoon hello.py eivät näy kun tietoa haetaan selaimella uudestaan. Ohjelmistokehityksen nopeuden kannalta olisi kuitenkin hyödyllistä, jos muutoksia voisi tarkastella ilman että palvelinta käynnistellään jatkuvasti uudelleen.

Flaskille voi määritellä ns. debug-moodin, mikä muuntaa sovelluksen toimintaa muunmuassa siten, että sovelluksen uudelleenkäynnistäminen muutosten yhteydessä ei ole tarpeellista. Muokataan sovelluksen käynnistävää tiedostoa hello.py siten, että komento app.run() saa parametrinaan tiedon debug-tilasta. Tämä onnistuu seuraavasti.

from flask import Flask
app = Flask(__name__)
  
@app.route("/")
def hello():
    return "Hello World!"

if __name__ == "__main__":
    app.run(debug=True)

Kun sovelluksen sammuttaa ja käynnistää uudelleen, selaimella sivu näyttää yhä seuraavalta.

 

Terminaalissa tosin tulostus on hieman erilainen.

(venv) ~/demo$ ls
hello.py  venv
(venv) ~/demo$ python3 hello.py
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: 231-450-049

Muokataan tiedostoa hello.py siten, että sivun pitäisi näyttää teksti "Hei maailma!".

from flask import Flask
app = Flask(__name__)
  
@app.route("/")
def hello():
    return "Hei maailma!"

if __name__ == "__main__":
    app.run(debug=True)

Kun tallennamme tiedoston, huomaamme, että terminaalissa näkyvä tulostus päivittyy.

(venv) ~/demo$ ls
hello.py  venv
(venv) ~/demo$ python3 hello.py
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: 231-450-049
* Detected change in '/polku/demo/hello.py', reloading
* Restarting with stat
* Debugger is active!
* Debugger PIN: 231-450-049

Kun sivun lataa selaimessa uudestaan, sivulla näkyy nyt päivitetty teksti.

 

Debug-tilasta on muitakin hyötyjä. Pääset esimerkiksi tarkastelemaan selaimesta sovelluksen tilaa virhetilanteen yhteydessä. Tämän takia on myös hyvä varmistaa, ettei debug-tila ole koskaan päällä kun sovellus viedään tuotantoon -- debug-tila mahdollistaa myös mm. tietokannan salasanojen ym tarkastelun. Ei hyvä asia tuotannossa.

HTML-näkymien luominen

Tutustutaan seuraavaksi HTML-kielellä toteutettavien näkymien luomiseen. Mikäli HTML-kieli ei ole tuttu, käy läpi ainakin osoitteessa https://developer.mozilla.org/en-US/docs/Learn/HTML oleva opas.

Jatketaan aiemmin luodun sovelluksen parissa.

(venv) ~/demo$ ls
hello.py  venv

Luodaan HTML-näkymiä varten kansio nimeltä templates ja mennään kansioon.

(venv) ~/demo$ mkdir templates
(venv) ~/demo$ cd templates
(venv) ~/demo/templates$ ls
(venv) ~/demo/templates$

Kansio on toistaiseksi tyhjä. Luodaan kansioon kaksi tiedostoa layout.html ja index.html. Tiedostoon layout.html tulee sivun yleinen rakenne, menuvalikko ym. Tiedostoon index.html taas sivun etusivun sisältö.

Asetetaan sivun layout.html sisällöksi seuraava.

  <!DOCTYPE html>
  <html>
    <head>
      <meta charset="utf-8">
      <title>Demo</title>
    </head>

    <body>
      {% block body %}
      <p>
	Tähän tuodaan sisältö muualta.
      </p>
      {% endblock %}
    </body>
  </html>

Ja sivun index.html sisällöksi seuraava.

{% extends "layout.html" %}

{% block body %}
<p>
  Hei maailma!
</p>
{% endblock %}
Jinja 2

Flask käyttää oletuksena Jinja-nimistä kirjastoa käyttäjälle näytettävien sivujen luomiseen. Jinja on hieman tietokantojen perusteista tutun Thymeleafin kaltainen kirjasto, jota käytetään HTML-sivujen luomiseen. Jinja mahdollistaa myös esimerkiksi toistolauseiden ym. käyttämisen osana HTML-näkymiä -- sivut luodaan palvelimella.

Nyt sovelluksemme kansion templates sisällön pitäisi olla seuraavanlainen.

(venv) ~/demo/templates$ ls
index.html  layout.html
(venv) ~/demo/templates$

Palataan tiedostohierarkiassa aiempaan kansioon.

(venv) ~/demo/templates$ ls
index.html  layout.html
(venv) ~/demo/templates$ cd ..
(venv) ~/demo$

Muokataan kansiossa olevaa hello.py-tiedostoa. Emme näytäkään käyttäjälle suoraan merkkijonoa Hei maailma!, vaan luomme käyttäjälle näkymän juuri luomiemme tiedostojen pohjalta.

Tarvitsemme sovelluksen käyttöön Flaskin render_template-funktion. Funktio lisätään sekä tiedoston alussa olevaan import-lauseeseen, että pyynnön käsittelevään funktioon hello, jossa kyseistä funktiota kutsutaan. Funktiolle render_template annetaan kutsuttaessa parametrina HTML-tiedoston nimi, josta käyttäjälle palautettava sivu luodaan.

from flask import Flask, render_template
app = Flask(__name__)
  
@app.route("/")
def hello():
    return render_template("index.html")

if __name__ == "__main__":
    app.run(debug=True)

Käynnistetään sovellus.

(venv) ~/demo$ ls
hello.py  templates  venv
(venv) ~/demo$ python3 hello.py 
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: 231-450-049

Kun menemme osoitteeseen http://127.0.0.1:5000/, näemme seuraavanlaisen sivun.

 

Nopealla vilkaisulla mikään ei ole muuttunut. Kun tarkastelemme sivuun liittyvää lähdekoodia, huomaamme kuitenkin selkeitä muutoksia. Lähdekoodin tarkastelu onnistuu selaimessa klikkaamalla sivua oikealla hiirennäppäimellä ja valitsemalla View page source (pikanäppäin Ctrl+S).

Lähdekoodi paljastaa totuuden. Näyttää siltä, että sivun lähdekoodin runko on tullut templates-kansion tiedostosta layout.html ja sisältö tiedostosta index.html.

 

Voimme siis määritellä sivustolle ulkoasun tiedostossa layout.html. Sivukohtainen sisältö määritellään taas sivukohtaisessa tiedostossa -- esimerkiksi juurisivun sisältö löytyy tiedostosta index.html.

Tiedon lisääminen näkymään

Funktiolle render_template voidaan antaa parametreina muuttujia, joiden arvoja voidaan lisätä näkymiin. Tarkastellaan tässä muuttujien, listojen sekä olioita sisältävien listojen käsittelyä.

Näkymien luomiseen käytettävä Jinja-kirjasto etsii HTML-koodista kaksinkertaisilla aaltosuluilla rajattuja alueita sekä niiden sisällä olevaa koodia. Mikäli aaltosulkujen sisältä löytyy render_template-funktiolle parametrina annetun muuttujan nimi, aaltosulkujen paikalle vaihdetaan muuttujan arvo.

Kontrollirakenteita kuten if ja for voi käyttää Jinjassa yksinkertaisten aaltosulkujen avulla siten, että avaavaa aaltosulkua seuraa prosenttimerkki, ja lopettavaa aaltosulkua edeltää prosenttimerkki. Esimerkiksi {% for arvo in lista %}{{ arvo }}{% endfor %} kävisi jokaisen listalla olevan arvon läpi ja lisäisi sen sivulle.

Luodaan kansioon templates tiedosto demo.html, jonka avulla demonstroidaan useampaa tapaa muuttujien käyttöön. Asetetaan tiedoston sisällöksi seuraava.

  {% extends "layout.html" %}

  {% block body %}
  <p>
    Hei maailma!
  </p>
  <p>
    <!-- etsitään muuttujaa nimeltä nimi ja asetetaan sen arvo tähän -->
    {{ nimi }}
  </p>

  <ul>
    <!-- Yritetään käydä lista-nimistä tietorakennetta läpi.
	 Jokaiselle tietorakenteen alkiolle luodaan li-elementti, 
	 jonka sisälle asetetaan alkion arvo. -->
    {% for arvo in lista %}
    <li>{{ arvo }}</li>
    {% endfor %}
  </ul>

  <table>
    <tr>
      <th>Nimi</th>
    </tr>
    <!-- Yritetään käydä tietorakenne nimeltä esineet läpi. 
	 Jokaiselle esineelle luodaan oma rivi taulukkoon. 
	 Jokaista taulukon solua luodessa oletetaan, että 
	 esine on olio, ja että alkiolla on muuttuja name. 
	 Muuttujan arvo asetetaan solun arvoksi. -->
    {% for esine in esineet %}
    <tr>
      <td>{{ esine.name }}</td>
    </tr>
    {% endfor %}
  </table>

  {% endblock %}

Edellä oletetaan, että käytössä on kolme muuttujaa: nimi, lista, ja esineet. Tämän lisäksi jokaisella esineellä tulee olla muuttuja name.

Muokataan taas tiedostoa hello.py. Luodaan tiedostoon esinettä kuvaava luokka Item, jolla on oliomuuttuja name. Luodaan tiedostoon myös muuttujat nimi, lista, ja esineet ja asetetaan näihin esimerkkiä varten arvot.

Luodaan lopulta erillinen funktio, joka kuuntelee polkuun /demo tehtäviä pyyntöjä. Kun pyyntö vastaanotetaan, käyttäjälle palautetaan funktion render_template luoma sivua kuvaava merkkijono. Funktiolle render_template annetaan parametrina aiemmin luotua demosivua kuvaava demo.html sekä muuttujat nimi, lista, ja esineet. Jokaiselle muuttujalle asetetaan myös nimi kutsun funktiokutsun yhteydessä.

from flask import Flask, render_template
app = Flask(__name__)

class Item:
    def __init__(self, name):
        self.name = name

nimi = "Essi Esimerkki"

lista = [1, 1, 2, 3, 5, 8, 11]

esineet = []
esineet.append(Item("Eka"))
esineet.append(Item("Toka"))
esineet.append(Item("Kolmas"))
esineet.append(Item("Neljäs"))
  
@app.route("/")
def hello():
    return render_template("index.html")

@app.route("/demo")
def content():
    return render_template("demo.html", nimi=nimi, lista=lista, esineet=esineet)

if __name__ == "__main__":
    app.run(debug=True)

Mikäli sovellus ei ole käynnissä, käynnistetään se.

(venv) ~/demo$ python3 hello.py 
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: 231-450-049

Osoitteessa http://127.0.0.1:5000/ on tuttu sivu, joka näyttää viestin "Hei maailma!". Kun menemme osoitteeseen http://127.0.0.1:5000/demo, pyyntö ohjautuu hello.py-tiedoston funktiolle nimeltä content. Näemme lopulta seuraavanlaisen sivun.

 

Aiheen valinta

Työ omasta aiheesta

Mikäli haluat tehdä työn omasta aiheesta ja työ täyttää harjoitustyön vaatimukset (tietokanta jossa noin 4-7 taulua, käyttöliittymä, järkevä maksimiarvosana), voit toteuttaa työn omalla aiheellasi. Omasta aiheesta täytyy laatia aihekuvaus valmiiden aiheiden tapaan, joka tulee palauttaa ensimmäisen viikon palautuksen yhteydessä. Voit myös toteuttaa valmiista aihe-ehdotuksesta oman variaatiosi.

Hyviä aiheideoita voit saada vaikkapa omista harrasteista ja kiinnostuksen kohteista. Kurssilla on vuosien saatossa toteutettu mm. kaikennäköisiä roolipelitietokantoja, lintutietokanta, bussinbongaustietokanta ja haalarimerkkigalleria.

Omasta aiheesta on sovittava ohjaajan kanssa. Täten varmistetaan aiheen sopiva laajuus, työ ei saa olla liian suppea, mutta se ei myöskään saa olla liian laaja. Mikäli haluat tehdä työn omasta aiheesta, ota aiheesi mielellään jo aloitusluennon jälkeen.

Valmiita aiheaihioita

Alla on poimittuna osoitteesta http://advancedkittenry.github.io/suunnittelu_ja_tyoymparisto/aiheet/index.html muutamia mahdollisia työaiheita. Sivulta aiheita löytyy enemmänkin -- huomaa, että em. sivulla olevat arvosanaehdotukset eivät aina pidä paikkansa.

Kevyempiä aiheita - maksimiarvosana noin 3

Kurssitarjonta ja kurssipaikan varaus

Kurssikeskus Opinahjo järjestää maksullisia kursseja eri aihepiireistä. Yhteen aihepiiriin liittyen pidetään vuodessa 1-20 kurssia. Sama kurssin voidaan vuoden aikana järjestää useaan kertaan. Kursseille voi osallistua keskimäärin 20 opiskelijaa, mutta isoja yli sadankin hengen kursseja on joskus ohjelmassa. Kustakin kurssista on laadittu esite, josta käyvät selville kurssin aika, kurssipaikka kurssin opettajat ja kurssin sisältö.

Kuka tahansa voi tutkia kurssitietoja ja ilmoittautua kurssille. Jotta ilmoittautuminen tulisi voimaan, on varaajan maksettava varausmaksu. Tätä varten varaajalle ilmoitetaan tilinumero ja varaukseen liittyvä viitenumero ja varausmaksun määrä. Jos varaaja erikseen pyytää laskua varausmaksusta, sellainen lähetetään. Varsinainen kurssimaksun laskutus ei kuulu tämän järjestelmän piiriin.

Toimintoja:

  • Kirjautuminen
  • Kurssin syöttö ja muokkaus
  • Kurssitarjonnan katselu ja varauksen teko
  • Varauslaskujen kirjoitus - niille jotka ovat sitä pyytäneet tai eivät ole viikon kuluessa vauksesta maksaneet varausmaksua. (valinnainen)
  • Ilmoittautuneiden luettelo
  • Varauksen peruutus yrityksen toimesta, jos maksua ei ole maksettu
  • Varauksen peruutus asiakkaan toimesta
  • Kurssin peruutus
Projektin työaikaseuranta

Tehtävänä on laatia järjestelmä, jolla voidaan seurata projektiin käytettyä työaikaa. Järjestelmää on tarkoitus käyttää ohjelmistotuotantoprojekteissa sekä harjoitustöissä. Projektipäällikkö tai ohjaaja saa järjestelmältä yhteenvetoja käytetystä työajasta viikottain, henkilöittäin ja tehtävälajeittain. Kukin projektiin osallistuva henkilö kirjaa järjestelmän tekemänsä työtunnit, työlajin ja mahdollisen selityksen. Projektin osallistuja saa nähtäväkseen tekemänsä kirjaukset. Hän saa esiin myös itseensä liittyvät yhteenvetoraportit. Projektipäällikkö saa halutessaan käyttöönsä myös tiedot kunkin työntekijään yksityiskohtaisista kirjauksista.

Toimintoja:

  • Kirjautuminen
  • Työaikakirjauksen teko
  • Projektin perustaminen
  • Henkilön liittäminen projektiin
  • Henkilön poistaminen projektista
  • Projektipäällikön raportit
  • Yksityiskohtainen työraportti

Haastavampia aiheita - maksimiarvosana noin 5

Keskustelufoorumi

Harjoitustyössä tehdään keskustelufoorumi jonkin yhteisön, vaikkapa opiskelijajärjestön sisäiseen käyttöön. Käyttäjä voi lukea järjestelmän tallennettuja kirjoituksia ja lisätä tietokantaan uusia kirjoituksia, jotka voivat olla myös vastineita aiempiin kirjoituksiin. Kirjoituksia voi hakea kirjoittajan nimen tai aiheen tai artikkelin iän perusteella. Lukija voi seurata myös vastinepolkua. Oletusarvoisesti lukijalle näytetään kaikki tietty ikää tuoreemmat artikkelit varustettuna informaatiolla siitä onko lukija itse ja ovatko kaikki yhteisön jäsenet jo lukeneet artikkelin. Lukija identifioi aina itsensä ja artikkeleihin liitetään tieto henkilöistä jotka ovat lukeneet ne. Tämä tieto on kaikkien lukijoiden saatavissa.

Järjestelmän ylläpitäjällä on oma liittymä, jonka kautta hän ylläpitää järjestön käyttäjien jäsentietoja ja heidän kuulumistan eri ryhmiin, siivota kirjoituskantaa ja määrittellä aiheita, joiden perusteella kirjoituksia voi ryhmitellä.

Toimintoja:

  • Kirjautuminen
  • Kirjoituksen lisääminen
  • Kirjoitusten näyttäminen eri kriteerein
  • Ryhmän jäsenen lisääminen, muokkaaminen ja poistaminen
  • Vastineen laatiminen ja muokkaus
  • Kirjoitusten poistaminen
  • Aiheiden määrittely, muokkaus ja poisto
Lääkäriaseman työvuorolista

Tehtävänä on laatia järjestelmä, jolla voidaan laatia lääkäriaseman työvuorolistoja. Lääkäriaseman henkilöstö jaetaan kolmeen luokkaan: lääkärit, sairaanhoitajat ja perushoitajat. Myös aseman aukioloajat jaetaan tarvittavan henkilöstövahvuuden mukaan eri kiireellisyysluokkiin. Jokaiselle kiireellisyysluokalle määritellään minimivahvuus eli kuinka monta kunkin henkilöstöluokan työntekijää täytyy olla töissä. Kuitenkin laskettessa minimivahvuutta ylempi voi korvata alemman eli lääkäri voi olla sairaanhoitaja tai perushoitaja, ja sairaanhoitaja voi olla myös perushoitaja. Jokainen aseman aukiolotunti kuuluu johonkin kiireellisyysluokkaan.

Huom. järjestelmä saa hyväksyä vain sellaiset työvuorolistat, jotka täyttävät vaaditut henkilöstövahvuudet. Lisäksi jokaisella työntekijällä on määritelty päivä- tai viikkotuntimäärä, jonka ylitykset järjestelmään täytyy estää.

Toimintoja:

  • Kirjautuminen
  • Kiireellisyysluokkien teko (ja muutos)
  • Henkilöstövahvuuskalenterin teko (ja muutos)
  • Työvuorolistan teko (ja muutos)
  • Henkilökohtaisen työvuorolistan listaus
  • Työvuorolistan listaus
  • Työntekijäkohtainen työraportti (tehdäyt tunnit tietyllä aikavälillä)
  • Työntekijään tekemien tuntien listaus kiireellisyysluokittain
  • Työvuorolistan ylimiehityksen raportointi

Kun olet valinnut aiheen..

Kun olet valinnut aiheen, kirjoita siitä kuvaus tai mukauta aiheen kuvausta itsellesi sopivaksi.

Luo aiheelle github-repositorio

Luo github-tunnuksesi alle uusi repositorio. Aseta repositorion nimeksi aiheesi nimi. Luo tämän jälkeen repositorion juureen tiedosto README.md, johon kirjoitat aihekuvauksen.

Siirrä sovellus Githubiin

Lisää ensin projektin kansioon .gitignore-tiedosto, johon lisätään versionhallinnasta poisjätettävät tiedostot. Emme halua, että virtuaaliympäristön sisältämät binäärit ovat versionhallinnassa, joten lisätään tiedostoon rivi "venv". Tämä tarkoittaa sitä, että kansiota venv ei lisätä versionhallintaan.

(venv) ~/demo$ echo "venv" > .gitignore
(venv) ~/demo$ cat .gitignore
venv
(venv) ~/demo$

Saat luomasi github-repositorion osoitteen selville Githubista. Tässä oletetaan, että osoite on https://github.com/avihavai/tsoha.git.

Luodaan projektikansiolle git-versionhallinta komennolla git init. Tämä luo mahdollisuuden projektin versiointiin ja luo kansioon .git-nimisen kansion.

(venv) ~/demo$ git init
(venv) ~/demo$ 

Lisätään githubissa oleva repositorio kansion paikallisen versionhallinnan etäpisteeksi. Projektin osoite löytyy githubista (se on tyypillisesti muotoa https://github.com/käyttäjätunnus/projektin-nimi.git.

(venv) ~/demo$ git remote add origin github-projektin osoite
(venv) ~/demo$ 

Lisätään tiedostot githubiin.

(venv) ~/demo$ git add .
(venv) ~/demo$ git push -u origin master
..-
(venv) ~/demo$ 

Nyt projektin lähdekoodit löytyvät githubista.

Siirrä sovellus Herokuun

Sovelluksen Herokuun siirtämistä varten sovellukselle tulee lisätä web-palvelin, jota Heroku osaa käyttää. Valitsemme käyttöön Gunicorn-palvelimen.

~/demo$ source venv/bin/activate
(venv) ~/demo$ pip install gunicorn
Collecting gunicorn
Downloading gunicorn-19.7.1-py2.py3-none-any.whl (111kB)
100% |████████████████████████████████| 112kB 2.0MB/s 
Installing collected packages: gunicorn
Successfully installed gunicorn-19.7.1
(venv) ~/demo$ 

Jäädytetään seuraavaksi projektin tämän hetkiset riippuvuudet, jotta Heroku tietää mitä riippuvuuksia tulee asentaa. Tämä onnistuu komennolla pip freeze. Komennon tulostus ohjataan tiedostoon requirements.txt. Alla tehdään sekä jäädytys että tulostetaan riippuvuudet sisältävän tiedoston requirements.txt sisältö.

(venv) ~/demo$ pip freeze > requirements.txt
(venv) ~/demo$ cat requirements.txt
click==6.7
Flask==0.12.2
gunicorn==19.7.1
itsdangerous==0.24
Jinja2==2.10
MarkupSafe==1.0
pkg-resources==0.0.0
Werkzeug==0.14.1
(venv) ~/demo$ 

Tiedostossa oleva rivi pkg-resources==0.0.0 aiheuttaa ongelmia Herokussa, joten poistetaan se toistaiseksi. Tiedoston requirements.txt sisältö on tämän jälkeen seuraava.

(venv) ~/demo$ cat requirements.txt
click==6.7
Flask==0.12.2
gunicorn==19.7.1
itsdangerous==0.24
Jinja2==2.10
MarkupSafe==1.0
Werkzeug==0.14.1
(venv) ~/demo$ 

Voit nyt tarvittaessa asentaa projektisi riippuvuudet requirements.txt-tiedoston avulla komennolla pip install -r requirements.txt. Jos jossain vaiheessa esimerkiksi kloonaat repositoriosi koodin toiselle koneelle ja aloitat siten työskentelyn "puhtaasta" koodista, voit asentaa riippuvuudet luomaasi uuteen virtuaaliseen ympäristöön.

Lisätään seuraavaksi projektille Procfile-niminen tiedosto. Tiedosto Procfile on Herokun odottama tiedosto, joka sisältää Herokun tarvitsemat ohjeet sovelluksen käynnistämiseen. Lisätään ohjeiksi "web: gunicorn --preload --workers 1 hello:app", eli käynnistä hello.py-tiedostosta app-sovellus web-prosessina gunicorn-palvelinta käyttäen.

(venv) ~/demo$ echo "web: gunicorn --preload --workers 1 hello:app" > Procfile
(venv) ~/demo$ cat Procfile
web: gunicorn --preload --workers 1 hello:app
(venv) ~/demo$

Luodaan tämän jälkeen sovellukselle paikka Herokuun. Tässä oletuksena on, että käytössä on Herokun käyttäjätunnus sekä Herokun työvälineet komentoriville (Heroku CLI). Paikan luominen tapahtuu komennolla heroku create, jota seuraa toivottu sovelluksen nimi. Sovelluksen nimen tulee olla uniikki, eli alla oleva tsoha-python-demo tulee vaihtaa omaa sovellusta kuvaavaksi. Mikäli nimen jättää pois, Heroku luo satunnaisen nimen sovellukselle, mikä riittää tällä kurssilla.

(venv) ~/demo$ heroku create tsoha-python-demo
Creating ⬢ tsoha-python-demo... done
https://tsoha-python-demo.herokuapp.com/ | https://git.heroku.com/tsoha-python-demo.git
(venv) ~/demo$

Nyt sovellukselle on paikka Herokussa. Lisätään vielä paikalliseen versionhallintaan tieto Herokusta.

(venv) ~/demo$ git remote add heroku https://git.heroku.com/tsoha-python-demo.git
(venv) ~/demo$ 

Ja lähetetään projekti Herokuun.

(venv) ~/demo$ git add .
(venv) ~/demo$ git commit -m "Initial commit"
(venv) ~/demo$ git push heroku master
Counting objects: 13, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (11/11), done.
Writing objects: 100% (13/13), 1.79 KiB | 0 bytes/s, done.
Total 13 (delta 2), reused 0 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote: 
remote: -----> Python app detected
remote: -----> Installing python-3.6.4
remote: -----> Installing pip
remote: -----> Installing requirements with pip
remote:        Collecting click==6.7 (from -r /tmp/build_eb15306f4a3962d45ca30ea90e9b4cb6/requirements.txt (line 1))
remote:          Downloading click-6.7-py2.py3-none-any.whl (71kB)
remote:        Collecting Flask==0.12.2 (from -r /tmp/build_eb15306f4a3962d45ca30ea90e9b4cb6/requirements.txt (line 2))
remote:          Downloading Flask-0.12.2-py2.py3-none-any.whl (83kB)
remote:        Collecting gunicorn==19.7.1 (from -r /tmp/build_eb15306f4a3962d45ca30ea90e9b4cb6/requirements.txt (line 3))
remote:          Downloading gunicorn-19.7.1-py2.py3-none-any.whl (111kB)
remote:        Collecting itsdangerous==0.24 (from -r /tmp/build_eb15306f4a3962d45ca30ea90e9b4cb6/requirements.txt (line 4))
remote:          Downloading itsdangerous-0.24.tar.gz (46kB)
remote:        Collecting Jinja2==2.10 (from -r /tmp/build_eb15306f4a3962d45ca30ea90e9b4cb6/requirements.txt (line 5))
remote:          Downloading Jinja2-2.10-py2.py3-none-any.whl (126kB)
remote:        Collecting MarkupSafe==1.0 (from -r /tmp/build_eb15306f4a3962d45ca30ea90e9b4cb6/requirements.txt (line 6))
remote:          Downloading MarkupSafe-1.0.tar.gz
remote:        Collecting Werkzeug==0.14.1 (from -r /tmp/build_eb15306f4a3962d45ca30ea90e9b4cb6/requirements.txt (line 7))
remote:          Downloading Werkzeug-0.14.1-py2.py3-none-any.whl (322kB)
remote:        Installing collected packages: click, itsdangerous, Werkzeug, MarkupSafe, Jinja2, Flask, gunicorn
remote:          Running setup.py install for itsdangerous: started
remote:            Running setup.py install for itsdangerous: finished with status 'done'
remote:          Running setup.py install for MarkupSafe: started
remote:            Running setup.py install for MarkupSafe: finished with status 'done'
remote:        Successfully installed Flask-0.12.2 Jinja2-2.10 MarkupSafe-1.0 Werkzeug-0.14.1 click-6.7 gunicorn-19.7.1 itsdangerous-0.24
remote: 
remote: -----> Discovering process types
remote:        Procfile declares types -> web
remote: 
remote: -----> Compressing...
remote:        Done: 42.7M
remote: -----> Launching...
remote:        Released v3
remote:        https://tsoha-python-demo.herokuapp.com/ deployed to Heroku
remote: 
remote: Verifying deploy... done.
To https://git.heroku.com/tsoha-python-demo.git
* [new branch]      master -> master
(venv) ~/demo$

Nyt sovellus on tarkasteltavana osoitteessa https://tsoha-python-demo.herokuapp.com/. Osoite on toki riippuvainen sovellukselle valitusta nimestä.

Sovellus on myös hyvä lähettää Githubiin, sillä siihen on tullut päivityksiä.

(venv) ~/demo$ git push origin master
(venv) ~/demo$ 

Viikko- ja loppupalautusten arvioinnit perustuvat github-repositoriossasi olevaan koodiin, joten ota käyttöön Herokun automaattinen github-integraatio. Tällöin sovellusta ei päivitetä itse Herokuun, vaan Heroku hakee käyttöön automaattisesti kaikki Githubiin talletetut päivitykset.

Palauta työ labtooliin

Kun olet luonut aihekuvauksen, tehnyt repositorion, lisännyt repositorioon aihekuvauksen sekä hello.py -sovelluksen, ja lisännyt sovelluksen herokuun, lisää lopulta aihe labtooliin. Olet nyt sitoutunut suorittamaan harjoitustyön tässä periodissa.

Voit mennä Labtooliin yllä olevasta linkistä, etsiä oikean kurssin ja rekisteröityä sille. Kurssin suora rekisteröitymisosoite Labtooliin ilmoitetaan normaalisti kurssin courses-sivulla, joten rekisteröityminen kyseisen sivun kautta voi säästää hieman vaivaa.

Jatkossa viikoittaiset palautukset tehdään palauttamalla ajan tasalla oleva koodi Githubiin ja päivittämällä sovellus Herokussa. Labtoolista voit lukea palautuksista saamasi pisteet ja ohjaajien kommentit.

Sisällysluettelo