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:
commit
855620c619
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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},
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
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 |
285
docs/doku.org
285
docs/doku.org
|
@ -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
|
||||
|
|
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
Loading…
Reference in New Issue