Merge commit 'b228d5954ef71926b80ecc8c0f58435f0f3ae9c1' into cart

* commit 'b228d5954ef71926b80ecc8c0f58435f0f3ae9c1':
  clean up the process_article_prices function
  move some code out of the views.py file
  update paths
  rearrange figures
  extend the documentation
  extend the order and shoppingcart sections
  update the documentation
  add a class diagramme for the shoppingcartposition
  update the documentation
  add a bib entry for Dia
  update the erd
  add new class diagrammes
  wrap the registration in a transaction
  extend the documentation for models
  extend the bibliography
  add the erd diagramms and their description
  add an .eps version of the dia erd file
  add the final_erd files
This commit is contained in:
Ivan Hörler 2018-02-13 07:53:07 +01:00
commit 855620c619
19 changed files with 30911 additions and 131 deletions

View File

@ -0,0 +1,51 @@
from webshop.models import (Article,
Category,
ArticleStatus)
from currencies.models import ExchangeRate, ExchangeRate_name
from currencies.forms import CurrenciesForm
def process_article_prices(request, articles):
articles_list = list(articles)
rate = ExchangeRate
currency_name = "CHF"
if not 'currency' in request.session:
request.session['currency'] = None
if request.method == 'POST':
currencies_form = CurrenciesForm(request.POST)
if currencies_form.is_valid():
cf = currencies_form.cleaned_data
if cf['currencies']:
selection = cf['currencies']
request.session['currency'] = selection.id
currency_name = ExchangeRate_name.objects.get(id=selection.id)
else:
request.session['currency'] = None
if request.session['currency']:
currency = request.session['currency']
for idx, article in enumerate(articles_list):
article.price_in_chf = rate.exchange(currency, article.price_in_chf)
articles_list[idx] = article
currency_name = ExchangeRate_name.objects.get(id=currency)
return {'request':request,
'currency_name':currency_name,
'articles_list':articles_list}
def get_categories():
parent_category_list = Category.objects.filter(parent_category=None)
category_list = {}
for i in parent_category_list:
category_list.update(
{i: Category.objects.filter(parent_category=i.id)})
return category_list
def get_hidden_status_id():
hidden_status = ArticleStatus.objects.get(name="hidden")
return hidden_status.id

View File

@ -1,8 +1,11 @@
from decimal import Decimal
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from webshop.models import (Article,
Category,
ArticleStatus,
@ -14,58 +17,22 @@ from webshop.models import (Article,
from webshop.forms import (RegistrationForm,
AddToCartForm,
CartForm)
from webshop.utils import (get_categories,
get_hidden_status_id,
process_article_prices)
from currencies.models import ExchangeRate, ExchangeRate_name
from currencies.forms import CurrenciesForm
from decimal import Decimal
def get_categories():
parent_category_list = Category.objects.filter(parent_category=None)
category_list = {}
for i in parent_category_list:
category_list.update(
{i: Category.objects.filter(parent_category=i.id)})
return category_list
def get_hidden_status_id():
hidden_status = ArticleStatus.objects.get(name="hidden")
return hidden_status.id
def index(request):
category_list = get_categories()
articles = Article.objects.all().exclude(status=get_hidden_status_id())
articles_list = list(articles)
currencies_form = CurrenciesForm
rate = ExchangeRate
article_view = True
currency_name = "CHF"
if not 'currency' in request.session:
request.session['currency'] = None
if request.method == 'POST':
currencies_form = CurrenciesForm(request.POST)
if currencies_form.is_valid():
cf = currencies_form.cleaned_data
if cf['currencies']:
selection = cf['currencies']
request.session['currency'] = selection.id
currency_name = ExchangeRate_name.objects.get(id=selection.id)
else:
request.session['currency'] = None
if request.session['currency']:
currency = request.session['currency']
for idx, article in enumerate(articles_list):
article.price_in_chf = rate.exchange(
currency, article.price_in_chf
)
articles_list[idx] = article
currency_name = ExchangeRate_name.objects.get(id=currency)
articles = Article.objects.all().exclude(status=get_hidden_status_id())
return_values = process_article_prices(request, articles)
articles_list = return_values['articles_list']
currency_name = return_values['currency_name']
return render(request,
'webshop/index.html',
@ -79,35 +46,15 @@ def index(request):
def articles_in_category(request, category_id):
category_list = get_categories()
selected_category = Category.objects.get(id=category_id)
currencies_form = CurrenciesForm
article_view = True
articles = Article.objects.filter(
category=selected_category.id).exclude(status=get_hidden_status_id())
articles_list = list(articles)
currencies_form = CurrenciesForm
rate = ExchangeRate
article_view = True
currency_name = "CHF"
if not 'currency' in request.session:
request.session['currency'] = None
if request.method == 'POST':
currencies_form = CurrenciesForm(request.POST)
if currencies_form.is_valid():
cf = currencies_form.cleaned_data
if cf['currencies']:
selection = cf['currencies']
request.session['currency'] = selection.id
currency_name = ExchangeRate_name.objects.get(id=selection.id)
else:
request.session['currency'] = None
if request.session['currency']:
currency = request.session['currency']
for idx, article in enumerate(articles_list):
article.price_in_chf = rate.exchange(
currency, article.price_in_chf)
articles_list[idx] = article
currency_name = ExchangeRate_name.objects.get(id=currency)
return_values = process_article_prices(request, articles)
articles_list = return_values['articles_list']
currency_name = return_values['currency_name']
return render(request, 'webshop/category.html',
{'articles_list': articles_list,
@ -214,21 +161,22 @@ def registration(request):
profile_form = RegistrationForm(request.POST)
user_form = UserCreationForm(request.POST)
if (profile_form.is_valid() and user_form.is_valid()):
pf = profile_form.cleaned_data
uf = user_form.cleaned_data
user = User.objects.create_user(uf['username'],
pf['email'],
uf['password2'])
user.last_name = pf['last_name']
user.first_name = pf['first_name']
user.save()
person = Person.objects.create(
salutation=pf['salutation'],
city=City.objects.get(zip_code=pf['zip_code'],
name=pf['city']),
street_name=pf['street_name'],
street_number=pf['street_number'],
user=user)
with transaction.atomic():
pf = profile_form.cleaned_data
uf = user_form.cleaned_data
user = User.objects.create_user(uf['username'],
pf['email'],
uf['password2'])
user.last_name = pf['last_name']
user.first_name = pf['first_name']
user.save()
person = Person.objects.create(
salutation=pf['salutation'],
city=City.objects.get(zip_code=pf['zip_code'],
name=pf['city']),
street_name=pf['street_name'],
street_number=pf['street_number'],
user=user)
return HttpResponseRedirect('/login/')
else:
profile_form = RegistrationForm

View File

@ -98,11 +98,20 @@
}
@misc{tree,
month = {{09}},
note = {{\url{https://stackoverflow.com/a/39729832}}},
month = {{11}},
note = {{\url{https://stackoverflow.com/a/8177290/7723859}}},
Urldate = {{2018-01-15}},
author = {ht\_},
title = {{Tree view in django template}},
year = {2016},
author = {Acorn},
title = {{Django hierarchical model list}},
year = {2011},
}
@misc{snb,
month = {{01}},
note = {{\url{https://www.snb.ch/selector/de/mmr/exfeed/rss}}},
Urldate = {{2018-02-01}},
author = {Schweizerische National Bank},
title = {{SNB Devisenkurse}},
year = {2018},
}

View File

@ -149,3 +149,12 @@
year = {2018},
}
@misc{dia,
month = {{02}},
note = {{\url{http://dia-installer.de/}}},
Urldate = {{2018-02-06}},
author = {Macke, Steffen},
title = {{Dia draws your structured diagrams: Free Windows, Mac OS X and Linux version of the popular open source program}},
year = {2018},
}

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

29342
docs/diagrammes/erd.eps Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 269 KiB

View File

@ -271,7 +271,9 @@ LaTeX ist freie Software unter der LaTeX Project Public License.
Die Grafiken in diesem Dokument wurden hauptächlich mit dem Vektor
Grafik Editor Inkscape\footcite{inkscape} erstellt. Inkscape ist freie
Software unter der GNU Public License v3.
Software unter der GNU Public License v3. Für das Entity Relation
Diagramm in [[Models]] haben wir jedoch Dia\footcite{dia} verwendet. Dia
ist freie Software unter der GNU Public License v2.
Die Klassen Diagramme haben wir mit der Django Erweiterung
"Django-Extensions"\footcite{django_extensions} erstellt.
@ -486,7 +488,7 @@ ein Ergebnis eines Anwendungsfalls sein (e.g. falsches Pass- wort beim
Login). Dabei wird die technische Lösung nicht konkret beschrieben.
Die Detailstufe kann dabei sehr unterschiedlich sein.\footcite{usecase}
**** Anwendungsfalliagramm
**** Anwendungsfalldiagramm
"Ein Anwendungsfalldiagramm ... ist eine der 14 Diagrammarten der
Unified Modeling Language (UML), einer Sprache für die Modellierung
@ -507,7 +509,7 @@ Webshops beschränkt.
#+LATEX:\end{landscape}
#+LATEX:\newpage
**** Use Case Detailbeschreibung
**** Use Cases Detailbeschreibung
Use Cases werden in der Regel mit Hilfe einer sogenannten Use Case
Schablone im Detail beschrieben damit klar ist wie der Ablauf jeweils
@ -518,7 +520,7 @@ Da ein Web-Shop eine sehr umfangreiche Applikation ist gibt es sehr
viele Use Cases welche beschrieben und umgesetzt werden müssen. Aus
zeitlichen Gründen haben wir nur einen kleinen Teil der Use Cases im
Detail ausgearbeitet. Insbesondere diese welche wir selber
ausprogrammiert haben. Die gesamte Liste an Use Cases sieht wie folgt
aus programmiert haben. Die gesamte Liste an Use Cases sieht wie folgt
aus, die Use Cases mit den Nummern wurden dabei im Detail ausgearbeitet:
#+LATEX: {\footnotesize
@ -992,116 +994,317 @@ aus, die Use Cases mit den Nummern wurden dabei im Detail ausgearbeitet:
#+CAPTION: Ein frühes Mockup des Shop
#+ATTR_LATEX: :width \textwidth
#+NAME: mockup
[[./pictures/mockup-full-snipet.png]]
[[file:pictures/mockup-full-snipet.png]]
*** TODO Models
#+LATEX:\newpage
*** Models
\footcite{djangoextensions}
Wie bereits in [[Framework]] beschrieben übernimmt das Framework die
Erstellung der Tabellen in der Datenbank. Für den Aufbau der Anwendung
und der Kommunikation im Team ist es jedoch von absoluter
Notwendigkeit das man sich über die Beziehung zwischen den Objekten
Gedanken macht. Insbesondere wenn die Anwendung nach wie vor auf einer
relationalen Datenbank basiert. Aus diesem Grund haben wir vor Beginn
der Arbeit ein klassisches Entity Relation Diagramm aufgezeichnet.
Während der Entwicklung haben wir es dann kontinuierlich erweitert und
korrigiert. Das finale Ergebnis ist in der Abbildung:([[fig:erd]]) zu sehen.
erstellt haben.
**** NEXT Category
Django übernimmt dann jedoch das erstellen der Tabellen und benennen
derjenigen weshalb das Resultat in der Datenbank dann etwas anders
aussieht. Zusätzlich kommt Django auch noch mit eigenen Tabellen
daher. Der finale Aufbau der Datenbank ist in der
Abbildung:([[fig:final_erd]]) zu sehen. Dieses ERD wurde mit der Django
Erweiterung "Djangoextensions"\footcite{djangoextensions} erstellt.
\footcite{tree}
Nachfolgend werden wir die von uns erstellten Modells im Detail
beschreiben und auf jeweils spezifische Probleme eingehen.
#+LATEX:\newpage
#+LATEX:\begin{landscape}
#+ATTR_LATEX: :height.9\textwidth
#+CAPTION: Entity Relation Diagramm
#+NAME: fig:erd
[[file:diagrammes/erd.eps]]
#+LATEX:\end{landscape}
#+LATEX:\newpage
#+LATEX:\newpage
#+LATEX:\begin{landscape}
#+ATTR_LATEX: :height.9\textheight
#+CAPTION: Django Datenbank Aufbau
#+NAME: fig:final_erd
[[file:diagrammes/final_erd.png]]
#+LATEX:\end{landscape}
#+LATEX:\newpage
**** Category
Das "Category" Modell, Abbildung:([[fig:category]]) ist der Kernpunkt der
Artikelnavigation und vom Aufbau her eigentlich eher simpel.
Allerdings hatten wir etwas Mühe die hierarchische Darstellung im
Template sauber abzubilden. Hier half uns ein Artikel\footcite{tree}
von Stackoverflow auf die richtige Lösung zu kommen. Nämlich das sich
das ganze um zwei in einander verschachtelte Dictionaries handelt.
Somit konnten wir dann über die Kategorie iterieren.
#+ATTR_LATEX: :width 9cm :placement [H]
#+CAPTION: Klassenmodel für Kategorien
#+NAME: fig:category
[[./pictures/class_category.png]]
[[file:pictures/class_category.png]]
**** Option
**** NEXT Option
Gemäss der Anforderung FA\_1.4 muss es möglich sein für einen Artikel 0-5
Bilder hochzuladen. Wir stellen dies über eine Variabel im "Option"
Modell, Abbildung:([[fig:option]]), sicher gegen welche beim Speichern
überprüft wird. Die Variabel ist als Option im Admin Interface
hinterlegt. Dadurch ist es möglich den Wert auch nachträglich
noch zu ändern oder ganz zu deaktivieren.
\footcite{readonly}
\footcite{removeadd}
\footcite{removedelete}
Da diese Variabel jedoch essentiell für die Funktion des Webshops ist
mussten wir sicherstellen das sie von einem Administrator nicht aus
Versehen gelöscht oder umbenannt wird. Des weiteren macht es in der
Applikation im Momentan wenig Sinn wenn der User selber Optionen
hinzufügen kann. Aus diesen Gründen haben wir für das "Option" Modell
den "Add" Button\footcite{removeadd} und die "Delete"
Option\footcite{removedelete} entfernt sowie den Namen im Admin
Interface nur lesbar gemacht\footcite{readonly}. Somit ist nun nur
noch der Wert editierbar.
#+ATTR_LATEX: :width 9cm :placement [H]
#+CAPTION: Klassenmodel für Optionen
#+NAME: fig:option
[[./pictures/class_option.png]]
[[file:pictures/class_option.png]]
**** NEXT ArticleStatus
**** ArticleStatus
Das Modell "ArticleStatus", Abbildung:([[fig:articlestatus]]), wird über
einen Fremdschlüssel mit dem "Article" Modell verbunden und gibt
diesem verschiedene Status. Gemäss der Anforderung FA\_1.4 muss ein
Artikel die Status "active" und "hidden" haben. Wir haben dies in der
Applikation dann auch gleich so umgesetzt das nur die Artikel
angezeigt werden welche nicht den Status "hidden" haben.
#+ATTR_LATEX: :width 9cm :placement [H]
#+CAPTION: Klassenmodel für Artikelstatus
#+NAME: fig:articlestatus
[[./pictures/class_articlestatus.png]]
[[file:pictures/class_articlestatus.png]]
**** TODO ExchangeRate
**** ExchangeRate
\footcite{timezone}
Wir legen die Wechselkurse im Modell "ExchangeRate",
Abbildung:([[fig:exchangerate]]), ab. Um Manipulationen aufs Datum und den
Namen einfacher zu machen werden diese beiden Attribute als
Fremdschlüssel hinterlegt. Die Wechselkurse werden dabei aus dem RSS
Feed\footcite{snb} der Schweizerischen Nationalbank stündlich
abgeholt. Vor dem Ablegen in der Datenbank wird dann noch überprüft ob
sich die Werte geändert haben oder nicht.
Wir haben uns für den die Daten der SNB entschieden da sie einerseits
die benötigten Wechselkurse anbieten und anderseit bereits von unserer
Basiswährung CHF ausgehen. Dadurch müssen wir nicht zuerst aus einer
anderen Währung zurückrechnen.
#+ATTR_LATEX: :width 9cm :placement [H]
#+CAPTION: Klassenmodel für Wechselkurse
#+NAME: fig:exchangerate
[[./pictures/class_exchangerate.png]]
[[file:pictures/class_exchangerate.png]]
**** NEXT Article
**** ExchangeRate_name
Im Modell ExchangeRate_name, Abbildung:([[fig:exchangerate_name]]), ist nur
eine Liste mit allen möglichen Währungsnamen abgelegt.
#+ATTR_LATEX: :width 9cm :placement [H]
#+CAPTION: Klassenmodel für Wechselkurse
#+NAME: fig:exchangerate_name
[[file:pictures/exchangerate_name.png]]
**** ExchangeRate_date
Damit die Wechselkurse des Tages einfacher auf einer Zeile angezeigt
werden können haben wir das Datum in ein eigenes Modell,
Abbildung:([[fig:exchangerate_date]]), ausgelagert. Dabei wird das Datum
als Standardwert mitgegeben. Wir hatten dies zu Beginn noch falsch
implementiert und das Datum als Funktion übergeben. Das führte jedoch
dazu, dass die Funktion einmal beim Starten des Servers ausgeführt
wurde und alle Wechselkurse immer das gleiche Datum hatten. Auf
Stackoverflow fanden wir dann die Lösung\footcite{timezone} das wir
die Datumsfunktion als Variabel übergeben müssen damit sie bei jedem
Erstellen des Objekt evaluiert wird.
#+ATTR_LATEX: :width 9cm :placement [H]
#+CAPTION: Klassenmodel für Wechselkurse
#+NAME: fig:exchangerate_date
[[file:pictures/exchangerate_date.png]]
**** Article
Das Modell "Article", Abbildung([[fig:article]]), ist als solches nicht
sehr komplex und widerspiegelt einen Artikel aus der realen Welt.
Gemäss der Anforderung FA\_1.4 hat er eine eindeutige ID (den
Primärschlüssel), einen Namen von maximal 200 Zeichen, eine
Beschreibung von maximal 2000 Zeichen, Status sowie 0 - 5
Produktbilder.
#+ATTR_LATEX: :width 9cm :placement [H]
#+CAPTION: Klassenmodel für Artikel
#+NAME: fig:article
[[./pictures/class_article.png]]
[[file:pictures/class_article.png]]
**** NEXT OrderStatus
**** OrderStatus
Damit nachvollzogen werden kann in welchen Zustand sich eine
Bestellung gerade befindet haben wir ein Modell "OrderStatus",
Abbildung:([[fig:orderstatus]]), erstellt. Für dieses Modell sind folgende
Status angedacht:
- ordered -> vom Kunden bestellt
- delivered -> Bestellung wurde versandt
- cancelled -> Bestellung storniert
- on hold -> Bestellung pausiert
Der "OrderStatus" wird vom "Order" sowie auch dem "OrderOfGoods" Modell
verwendet.
#+ATTR_LATEX: :width 9cm :placement [H]
#+CAPTION: Klassenmodel für Bestellstatus
#+NAME: fig:orderstatus
[[./pictures/class_orderstatus.png]]
[[file:pictures/class_orderstatus.png]]
**** NEXT OrderOfGoods
**** OrderOfGoods
Das Modell "OrderOfGoods", Abbildung:([[fig:orderofgoods]]), bildet die
Nachbestellungen fürs Warenlager ab. Dabei wird es hauptsächlich für
die Verwaltung verwendet um die Nachbestellungen im Griff zu haben.
#+ATTR_LATEX: :width 9cm :placement [H]
#+CAPTION: Klassenmodel für Warenbestellungen
#+NAME: fig:orderofgoods
[[./pictures/class_orderofgoods.png]]
[[file:pictures/class_orderofgoods.png]]
**** NEXT Picture
**** Picture
\footcite{upload}
\footcite{images}
Über das Modell "Picture", Abbildung:([[fig:picture]]) können Bilder für
einen Artikel hochgeladen werden. Grundsätzlich kann man Bilder
relativ einfach über das Attribut "models.ImageField" zu einem Modell
hinzufügen. Wir hatten allerdings noch einige Probleme mit dem
Konfigurieren von Django damit der Upload funktionierte und wir die
Bilder in den Templates verwenden konnten. Die Lösungen für den Upload
fanden wir in einem Stackoverflow Post\footcite{upload}. Auch für das
verwenden der Bilder in den Templates fanden wir in einem Post auf
Stackoverflow\footcite{images} die Lösung.
#+ATTR_LATEX: :width 9cm :placement [H]
#+CAPTION: Klassenmodel für Bilder
#+NAME: fig:picture
[[./pictures/class_picture.png]]
[[file:pictures/class_picture.png]]
**** NEXT Order
**** Order und OrderPosition
Bestellungen der Kunden werden im Modell "Order",
Abbildung:([[fig:order]]), erfasst. Wobei im Modell Order nur die Kunden
ID gespeichert wird, sowie, gemäss der Anforderung FA\_3.3, der
Foreign Key zum "ExchangeRate" Modell. Über den Foreign Key wird eine
Beziehung auf den für die Bestellung aktuellen Wechselkurs der Währung
hergestellt.
Da sich bei der Beziehung zwischen den Artikeln und dem Kunden um eine
"Viele zu Viele" Beziehung handelt braucht es noch ein zusätzliches
Modell welches die Beziehung abbildet. Dies realisieren wir über das
Modell "OrderPostion", Abbildung:([[fig:orderposition]]).
In diesem Modell werden dann noch zusätzlich die bestellte Menge sowie
der Preis zur Zeit der Bestellung in schweizer Franken des jeweiligen
Artikels erfasst. Somit kann auch später noch nachvollzogen werden zu
welchem Preis die Ware bezogen wurde.
#+ATTR_LATEX: :width 9cm :placement [H]
#+CAPTION: Klassenmodel für Bestellungen
#+NAME: fig:order
[[./pictures/class_order.png]]
[[file:pictures/class_order.png]]
**** NEXT ShoppingCart
#+ATTR_LATEX: :width 9cm :placement [H]
#+CAPTION: Klassenmodel für Bestellungens Positionen
#+NAME: fig:orderposition
[[file:pictures/class_orderposition.png]]
**** ShoppingCart und ShoppingCartPosition
Bevor die Bestellungen erfasst werden kann der Kunde die Artikel in
einem Warenkorb sammeln. Dieser funktioniert sehr ähnlich wie die
Bestellungen. Über das Modell "ShoppingCart",
Abbildung:([[fig:shoppingcart]]), und das Modell "ShoppingCartPosition",
Abbildung:([[fig:shoppingcartposition]]), werden die ausgewählten Artikel
sowie ihre Mengen einem User zugewiesen. Im Gegensatz zur Bestellung
wird im Artikel jedoch der Preis nicht gespeichert da sich der Preis
vor der Bestellung noch ändern könnte. Wenn die Verwaltung etwa die
Preise anpasst oder die Währungen den Kurs ändern.
#+ATTR_LATEX: :width 9cm :placement [H]
#+CAPTION: Klassenmodel für Warenkörbe
#+NAME: fig:shoppingcart
[[./pictures/class_shoppingcart.png]]
[[file:pictures/class_shoppingcart.png]]
**** NEXT City
#+ATTR_LATEX: :width 9cm :placement [H]
#+CAPTION: Klassenmodel für Warenkorbs Positionen
#+NAME: fig:shoppingcartposition
[[file:pictures/class_shoppingcartposition.png]]
**** City
Das "City" Modell speichert Städte Namen und die dazugehörige
Postleizahl. Die Städte werden als Teil der Adresse auf dem "Person"
Modell hinterlegt. Im aktuellen Zustand der Applikation enthält die
Tabelle die Daten aller schweizer Städte.
#+ATTR_LATEX: :width 9cm :placement [H]
#+CAPTION: Klassenmodel für Städte
#+NAME: fig:city
[[./pictures/class_city.png]]
[[file:pictures/class_city.png]]
**** NEXT Salutation
**** Salutation
"Salutation", zu Deutsch Anrede, ist das Modell welches die möglichen
Anreden beinhaltet die ein User für sich hinterlegen kann.
Für den Moment haben wir die folgenden Auswahlmöglichkeiten
hinterlegt:
- Herr
- Frau
- Dr.
#+ATTR_LATEX: :width 9cm :placement [H]
#+CAPTION: Klassenmodel für Anreden
#+NAME: fig:salutation
[[./pictures/class_salutation.png]]
[[file:pictures/class_salutation.png]]
**** NEXT Person
**** Person
\footcite{usermodel}
Das "Person" Modell dient dazu Informationen über einen User zu
speichern die nicht relevant sind für die Authentifizierung.
Es gibt mehrere Möglichkeiten wie man das "User" Modell in Django
erweitern kann. In einem Post\footcite{usermodel} von Vitor Freitas
werden die möglichen vier Varianten aufgeführt und erklärt. Eine davon
ist nicht dafür gemacht zusätzliche Informationen zu speichern. Zwei
weitere Varianten bauen darauf auf von einer Basis "User" Klasse
abzuleiten. Die erste Variante war für unsere Zwecke nicht geeignet da
wir zwingend zusätzliche Informationen speichern wollten. Die
Varianten mit Vererbungen erschienen uns ungeeignet da die Möglichkeit
besteht die Sicherheit der Authentifizierung zu schwächen. Aus diesem
Grund wird in der Django Dokumentation eher davor abgeraten diese
Varianten wenn man nicht genau weiss was man macht.
Die verbeiblende Variante erweitert das "User" Modell über eine
"One-to-One" Beziehung ein sogenanntes "Profil". Dadurch bleibt das
"User" Modell intakt und man kann zusätzliche Informationen über den
User speichern. Man sollte im Profil jedoch nur Daten speichern welche
nicht sicherheitsrelevant sind. Der Nachteil dieser Variante ist das
die Datenbank mit zusätzlichen Anfragen belastet werden kann.
#+ATTR_LATEX: :width 9cm :placement [H]
#+CAPTION: Klassenmodel für Personen
#+NAME: fig:person
[[./pictures/class_person.png]]
[[file:pictures/class_person.png]]
** Benutzerinterface
*** Mockup skizzieren

View File

@ -0,0 +1,64 @@
digraph model_graph {
// Dotfile by Django-Extensions graph_models
// Created: 2018-01-29 22:04
// Cli Options: -a
fontname = "Helvetica"
fontsize = 8
splines = true
node [
fontname = "Helvetica"
fontsize = 8
shape = "plaintext"
]
graph [ dpi = 300 ];
edge [
fontname = "Helvetica"
fontsize = 8
]
// Labels
webshop_models_OrderPosition [label=<
<TABLE BGCOLOR="palegoldenrod" BORDER="0" CELLBORDER="0" CELLSPACING="0">
<TR><TD COLSPAN="2" CELLPADDING="4" ALIGN="CENTER" BGCOLOR="olivedrab4">
<FONT FACE="Helvetica Bold" COLOR="white">
OrderPosition
</FONT></TD></TR>
<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Helvetica Bold">id</FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Helvetica Bold">AutoField</FONT>
</TD></TR>
<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Helvetica Bold">article</FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Helvetica Bold">ForeignKey (id)</FONT>
</TD></TR>
<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Helvetica Bold">order</FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Helvetica Bold">ForeignKey (id)</FONT>
</TD></TR>
<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Helvetica ">amount</FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Helvetica ">FloatField</FONT>
</TD></TR>
<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Helvetica ">price_in_chf</FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Helvetica ">DecimalField</FONT>
</TD></TR>
</TABLE>
>]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

@ -0,0 +1,63 @@
digraph model_graph {
// Dotfile by Django-Extensions graph_models
// Created: 2018-01-29 22:04
// Cli Options: -a
fontname = "Helvetica"
fontsize = 8
splines = true
node [
fontname = "Helvetica"
fontsize = 8
shape = "plaintext"
]
graph [ dpi = 300 ];
edge [
fontname = "Helvetica"
fontsize = 8
]
// Labels
webshop_models_ShoppingCartPosition [label=<
<TABLE BGCOLOR="palegoldenrod" BORDER="0" CELLBORDER="0" CELLSPACING="0">
<TR><TD COLSPAN="2" CELLPADDING="4" ALIGN="CENTER" BGCOLOR="olivedrab4">
<FONT FACE="Helvetica Bold" COLOR="white">
ShoppingCartPosition
</FONT></TD></TR>
<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Helvetica Bold">id</FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Helvetica Bold">AutoField</FONT>
</TD></TR>
<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Helvetica Bold">article</FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Helvetica Bold">ForeignKey (id)</FONT>
</TD></TR>
<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Helvetica Bold">order</FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Helvetica Bold">ForeignKey (id)</FONT>
</TD></TR>
<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Helvetica ">amount</FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Helvetica ">FloatField</FONT>
</TD></TR>
<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Helvetica ">price_in_chf</FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Helvetica ">DecimalField</FONT>
</TD></TR>
</TABLE>
>]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

@ -0,0 +1,45 @@
digraph model_graph {
// Dotfile by Django-Extensions graph_models
// Created: 2018-01-29 22:04
// Cli Options: -a
fontname = "Helvetica"
fontsize = 8
splines = true
node [
fontname = "Helvetica"
fontsize = 8
shape = "plaintext"
]
graph [ dpi = 300 ];
edge [
fontname = "Helvetica"
fontsize = 8
]
currencies_models_ExchangeRate_date [label=<
<TABLE BGCOLOR="palegoldenrod" BORDER="0" CELLBORDER="0" CELLSPACING="0">
<TR><TD COLSPAN="2" CELLPADDING="4" ALIGN="CENTER" BGCOLOR="olivedrab4">
<FONT FACE="Helvetica Bold" COLOR="white">
ExchangeRate_date
</FONT></TD></TR>
<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Helvetica Bold">id</FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Helvetica Bold">AutoField</FONT>
</TD></TR>
<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Helvetica ">date</FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Helvetica ">DateField</FONT>
</TD></TR>
</TABLE>
>]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -0,0 +1,44 @@
digraph model_graph {
// Dotfile by Django-Extensions graph_models
// Created: 2018-01-29 22:04
// Cli Options: -a
fontname = "Helvetica"
fontsize = 8
splines = true
node [
fontname = "Helvetica"
fontsize = 8
shape = "plaintext"
]
graph [ dpi = 300 ];
edge [
fontname = "Helvetica"
fontsize = 8
]
currencies_models_ExchangeRate_name [label=<
<TABLE BGCOLOR="palegoldenrod" BORDER="0" CELLBORDER="0" CELLSPACING="0">
<TR><TD COLSPAN="2" CELLPADDING="4" ALIGN="CENTER" BGCOLOR="olivedrab4">
<FONT FACE="Helvetica Bold" COLOR="white">
ExchangeRate_name
</FONT></TD></TR>
<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Helvetica Bold">id</FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Helvetica Bold">AutoField</FONT>
</TD></TR>
<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Helvetica ">name</FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Helvetica ">CharField</FONT>
</TD></TR>
</TABLE>
>]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB