- 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 %}
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 varausKurssikeskus 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
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
KeskustelufoorumiHarjoitustyö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
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.