#!/home/tjlahton/public_html/cgi-bin/ties4080/venv/bin/python # -*- coding: UTF-8 -*- #yksinkertainen ostoskorisovellus CGI-rajapinnalla. Päivitetty luentovideoversioon #muuttamalla kaikki merkkijonot unicode-merkkijonoiksi 15.1.2018 #muunnettu python 3 -muotoon 28.1.2021 #muunnettu flask-sovellukseksi ja tehty yksinkertaistettu versio 9.2.2022 from flask import Flask, request, Response, render_template import os import json import urllib.parse app = Flask(__name__) @app.route('/simple', methods=["GET", "POST"]) def simplekori(): form = request.values tuote = form.get("tuote", "") lkm = form.get("lkm", 1, type=int) hinta = form.get("hinta", 10.0, type=float) tuotteet = form.get("tuotteet", "[]") # muunnetaan json-muodossa oleva tuotelistaus takaisin pythonin listaksi try: tuotteet = json.loads( tuotteet ) except json.decoder.JSONDecodeError: tuotteet = [] # Onko kasvatettu ostoskorissa jonkin tuotteen lukumäärää? # vaikka tämä on täysin itse hallinnoitu muuttuja niin silti pitää varautua siihen, että # joku menee sorkkimaan sitä käsin eikä saadakkaan inttiä lisaa = form.get("lisaa", 0, type=int) poista = form.get("poista", 0, type=int) #lisätään jonkin tuotteen määrää if lisaa: for t in tuotteet: if t["id"] == lisaa: t["lkm"] = t["lkm"] + 1 if poista: for i in range(len(tuotteet)): if tuotteet[i]["id"] == poista: del tuotteet[i] break #lisätään uusi tuote if len(tuote): #täytyy keksiä uniikki id max = 1 for t in tuotteet: if t["id"] >= max: max = t["id"] + 1 t = {"id": max, "tuote": tuote, "lkm": lkm, "hinta" :hinta} tuotteet.append(t) # Muunnetaan lomakkeelle tallennettava tuotteet-lista json-muotoon # määritellään erotinmerkit ilman välilyöntejä, niin saadaan tiivis muoto tallenna = json.dumps( tuotteet, separators=(',', ':') ) tallennaurl = urllib.parse.quote_plus( tallenna ) #linkissä käytetty versio #tehdään siistimpi tulostusasu tuotteelle. Parempi on tehdä jinjassa def tulosta_tuote(tuote): return f"Tuote : {tuote['tuote']}\tId:{tuote['id']}\tLukumäärä: {tuote['lkm']}\tHinta: {tuote['hinta']}" # palautetaan lopullinen dokumentti return render_template( "simple.html", tuote=tuote, tuotteet=tuotteet, tallenna=tallenna, tallennaurl=tallennaurl, tulosta_tuote=tulosta_tuote) #monimutkaisempi ostoskori, joka käyttää omaa Tuoteluokkaa class Tuote: ''' Oma luokka tuotteiden ja niiden tietojen käsittelyä helpottamaan Tuo kuitenkin mukanaan vähän lisävaivaa, että saa toimimaan JSON-muodossa ''' # Luokan sisäinen muuttuja jolla saadaan aikaan juokseva tunnistenumero kaikille tuotteille tunniste = 1 def __init__(self, nimi="Tuote", lkm=1, hinta=1): self.nimi = nimi self.lkm = lkm self.hinta = hinta self.id = Tuote.tunniste Tuote.tunniste = Tuote.tunniste + 1 # Python-syntaksin kanssa yhteensopiva string-muotoinen esitys luokasta def __repr__(self): return str({"Tuote": True, "Id":self.id, "Nimi": self.nimi, "Lkm":self.lkm, "Hinta":self.hinta }) # Luokalle voi itse opettaa miten luokka esitetään stringinä. Kts. miten tulostuu # templaten sisällä. def __str__(self): return "Nimi\t"+ self.nimi + "\tLkm:\t" + str(self.lkm) + "\tHinta\t" + str(self.hinta) # serialisoi Tuotteen JSONiin sopivaan muotoon def encode_tuote(o): if isinstance(o, Tuote): # palautetaan Tuote-objektin sisältö dictinä, jonka simplejson taas osaa serialisoida return {"Tuote": True, "Nimi": o.nimi, "Lkm":o.lkm, "Hinta":o.hinta } raise TypeError(repr(o) + " is not JSON serializable") # deserialisoi JSON-muodon takaisin tuotteeksi def as_tuote(o): if 'Tuote' in o: # Palautetaan dictinä tallennettu Tuote alkuperäiseen muotoonsa return Tuote(o["Nimi"], o["Lkm"], o["Hinta"]) return o @app.route('/', methods=["GET", "POST"]) def kori(): form = request.values tuote = form.get("tuote", "") try: lkm = int(form.get("lkm", 1)) except: lkm = 1 try: hinta = double(form.get("hinta", 10.0)) except: hinta = 10.0 # huom. nyt on vain yksi tuotteet-kenttä lomakkeella try: tuotteet = form.get("tuotteet", []) except: tuotteet = "" # muunnetaan json-muodossa oleva tuotelistaus takaisin pythonin listaksi try: if len(tuotteet): # object_hook-määritys tarvitaan, koska serialisoidaan oma luokka # Pythonin perustietotyyppien kanssa ei tarvittaisi object_hook-parametria tuotteet = json.loads( tuotteet, object_hook=as_tuote ) except: tuotteet = [] # Onko kasvatettu ostoskorissa jonkin tuotteen lukumäärää? # vaikka tämä on täysin itse hallinnoitu muuttuja niin silti pitää varautua siihen, että # joku menee sorkkimaan sitä käsin eikä saadakkaan inttiä try: lisaa = int(form.get("lisaa", 0)) except: lisaa = 0 if lisaa: for t in tuotteet: if t.id == lisaa: t.lkm = t.lkm + 1 if len(tuote): t = Tuote(tuote, lkm, hinta) tuotteet.append(t) # Muunnetaan lomakkeelle tallennettava tuotteet-lista json-muotoon # on käytettävä apuna itse määriteltyä encode_tuote-funktiota, koska muuten # simplejson ei tiedä miten Tuote-luokka serialisoitaisiin JSON-muotoon # Pythonin perustietotyypit toimisivat suoraan ilman default-parametria tallenna = json.dumps( tuotteet, default=encode_tuote ) tallennaurl = urllib.parse.quote_plus( tallenna ) #linkissä käytetty versio # tulostetaan lopullinen dokumenttib return render_template( "kori.html", tuote=tuote, tuotteet=tuotteet, tallenna=tallenna, tallennaurl=tallennaurl)