#!/home/tjlahton/public_html/cgi-bin/ties4080/venv/bin/python # -*- coding: UTF-8 -*- import cgitb cgitb.enable() print("""Content-type: text/html; charset=UTF-8\n""") import cgi import os import json from jinja2 import Template, Environment, FileSystemLoader import urllib.parse #yksinkertainen ostoskorisovellus CGI-rajapinnalla. Päivitetty luentovideoversioon #muuttamalla kaikki merkkijonot unicode-merkkijonoiksi 15.1.2018 #muunnettu python 3 -muotoon 28.1.2021 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 form = cgi.FieldStorage() tuote = form.getfirst("tuote", "") try: lkm = int(form.getfirst("lkm", 1)) except: lkm = 1 try: hinta = double(form.getfirst("hinta", 10.0)) except: hinta = 10.0 # huom. nyt on vain yksi tuotteet-kenttä lomakkeella try: tuotteet = form.getfirst("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.getfirst("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 try: tmpl_path = os.path.join(os.path.dirname(os.environ['SCRIPT_FILENAME']), 'templates') except: # jos tänne päädytään www-palvelimessa niin koko sovellus kaatuu... tmpl_path = "templates" try: env = Environment(autoescape=True, loader=FileSystemLoader(tmpl_path), extensions=['jinja2.ext.autoescape']) except: env = Environment(autoescape=True, loader=FileSystemLoader(tmpl_path)) template = env.get_template('kori.html') # tulostetaan lopullinen dokumentti print(template.render(tuote=tuote, tuotteet=tuotteet, tallenna=tallenna, tallennaurl=tallennaurl))