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.http import HttpResponseRedirect
|
||||||
from django.shortcuts import get_object_or_404, render
|
from django.shortcuts import get_object_or_404, render
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.auth.forms import UserCreationForm
|
from django.contrib.auth.forms import UserCreationForm
|
||||||
|
|
||||||
from webshop.models import (Article,
|
from webshop.models import (Article,
|
||||||
Category,
|
Category,
|
||||||
ArticleStatus,
|
ArticleStatus,
|
||||||
|
@ -14,58 +17,22 @@ from webshop.models import (Article,
|
||||||
from webshop.forms import (RegistrationForm,
|
from webshop.forms import (RegistrationForm,
|
||||||
AddToCartForm,
|
AddToCartForm,
|
||||||
CartForm)
|
CartForm)
|
||||||
|
from webshop.utils import (get_categories,
|
||||||
|
get_hidden_status_id,
|
||||||
|
process_article_prices)
|
||||||
|
|
||||||
from currencies.models import ExchangeRate, ExchangeRate_name
|
from currencies.models import ExchangeRate, ExchangeRate_name
|
||||||
from currencies.forms import CurrenciesForm
|
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):
|
def index(request):
|
||||||
category_list = get_categories()
|
category_list = get_categories()
|
||||||
articles = Article.objects.all().exclude(status=get_hidden_status_id())
|
|
||||||
articles_list = list(articles)
|
|
||||||
currencies_form = CurrenciesForm
|
currencies_form = CurrenciesForm
|
||||||
rate = ExchangeRate
|
|
||||||
article_view = True
|
article_view = True
|
||||||
currency_name = "CHF"
|
|
||||||
|
|
||||||
if not 'currency' in request.session:
|
articles = Article.objects.all().exclude(status=get_hidden_status_id())
|
||||||
request.session['currency'] = None
|
return_values = process_article_prices(request, articles)
|
||||||
|
articles_list = return_values['articles_list']
|
||||||
if request.method == 'POST':
|
currency_name = return_values['currency_name']
|
||||||
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 render(request,
|
return render(request,
|
||||||
'webshop/index.html',
|
'webshop/index.html',
|
||||||
|
@ -79,35 +46,15 @@ def index(request):
|
||||||
def articles_in_category(request, category_id):
|
def articles_in_category(request, category_id):
|
||||||
category_list = get_categories()
|
category_list = get_categories()
|
||||||
selected_category = Category.objects.get(id=category_id)
|
selected_category = Category.objects.get(id=category_id)
|
||||||
|
|
||||||
|
currencies_form = CurrenciesForm
|
||||||
|
article_view = True
|
||||||
|
|
||||||
articles = Article.objects.filter(
|
articles = Article.objects.filter(
|
||||||
category=selected_category.id).exclude(status=get_hidden_status_id())
|
category=selected_category.id).exclude(status=get_hidden_status_id())
|
||||||
articles_list = list(articles)
|
return_values = process_article_prices(request, articles)
|
||||||
currencies_form = CurrenciesForm
|
articles_list = return_values['articles_list']
|
||||||
rate = ExchangeRate
|
currency_name = return_values['currency_name']
|
||||||
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 render(request, 'webshop/category.html',
|
return render(request, 'webshop/category.html',
|
||||||
{'articles_list': articles_list,
|
{'articles_list': articles_list,
|
||||||
|
@ -214,21 +161,22 @@ def registration(request):
|
||||||
profile_form = RegistrationForm(request.POST)
|
profile_form = RegistrationForm(request.POST)
|
||||||
user_form = UserCreationForm(request.POST)
|
user_form = UserCreationForm(request.POST)
|
||||||
if (profile_form.is_valid() and user_form.is_valid()):
|
if (profile_form.is_valid() and user_form.is_valid()):
|
||||||
pf = profile_form.cleaned_data
|
with transaction.atomic():
|
||||||
uf = user_form.cleaned_data
|
pf = profile_form.cleaned_data
|
||||||
user = User.objects.create_user(uf['username'],
|
uf = user_form.cleaned_data
|
||||||
pf['email'],
|
user = User.objects.create_user(uf['username'],
|
||||||
uf['password2'])
|
pf['email'],
|
||||||
user.last_name = pf['last_name']
|
uf['password2'])
|
||||||
user.first_name = pf['first_name']
|
user.last_name = pf['last_name']
|
||||||
user.save()
|
user.first_name = pf['first_name']
|
||||||
person = Person.objects.create(
|
user.save()
|
||||||
salutation=pf['salutation'],
|
person = Person.objects.create(
|
||||||
city=City.objects.get(zip_code=pf['zip_code'],
|
salutation=pf['salutation'],
|
||||||
name=pf['city']),
|
city=City.objects.get(zip_code=pf['zip_code'],
|
||||||
street_name=pf['street_name'],
|
name=pf['city']),
|
||||||
street_number=pf['street_number'],
|
street_name=pf['street_name'],
|
||||||
user=user)
|
street_number=pf['street_number'],
|
||||||
|
user=user)
|
||||||
return HttpResponseRedirect('/login/')
|
return HttpResponseRedirect('/login/')
|
||||||
else:
|
else:
|
||||||
profile_form = RegistrationForm
|
profile_form = RegistrationForm
|
||||||
|
|
|
@ -98,11 +98,20 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@misc{tree,
|
@misc{tree,
|
||||||
month = {{09}},
|
month = {{11}},
|
||||||
note = {{\url{https://stackoverflow.com/a/39729832}}},
|
note = {{\url{https://stackoverflow.com/a/8177290/7723859}}},
|
||||||
Urldate = {{2018-01-15}},
|
Urldate = {{2018-01-15}},
|
||||||
author = {ht\_},
|
author = {Acorn},
|
||||||
title = {{Tree view in django template}},
|
title = {{Django hierarchical model list}},
|
||||||
year = {2016},
|
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},
|
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
|
Die Grafiken in diesem Dokument wurden hauptächlich mit dem Vektor
|
||||||
Grafik Editor Inkscape\footcite{inkscape} erstellt. Inkscape ist freie
|
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
|
Die Klassen Diagramme haben wir mit der Django Erweiterung
|
||||||
"Django-Extensions"\footcite{django_extensions} erstellt.
|
"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.
|
Login). Dabei wird die technische Lösung nicht konkret beschrieben.
|
||||||
Die Detailstufe kann dabei sehr unterschiedlich sein.\footcite{usecase}
|
Die Detailstufe kann dabei sehr unterschiedlich sein.\footcite{usecase}
|
||||||
|
|
||||||
**** Anwendungsfalliagramm
|
**** Anwendungsfalldiagramm
|
||||||
|
|
||||||
"Ein Anwendungsfalldiagramm ... ist eine der 14 Diagrammarten der
|
"Ein Anwendungsfalldiagramm ... ist eine der 14 Diagrammarten der
|
||||||
Unified Modeling Language (UML), einer Sprache für die Modellierung
|
Unified Modeling Language (UML), einer Sprache für die Modellierung
|
||||||
|
@ -507,7 +509,7 @@ Webshops beschränkt.
|
||||||
#+LATEX:\end{landscape}
|
#+LATEX:\end{landscape}
|
||||||
#+LATEX:\newpage
|
#+LATEX:\newpage
|
||||||
|
|
||||||
**** Use Case Detailbeschreibung
|
**** Use Cases Detailbeschreibung
|
||||||
|
|
||||||
Use Cases werden in der Regel mit Hilfe einer sogenannten Use Case
|
Use Cases werden in der Regel mit Hilfe einer sogenannten Use Case
|
||||||
Schablone im Detail beschrieben damit klar ist wie der Ablauf jeweils
|
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
|
viele Use Cases welche beschrieben und umgesetzt werden müssen. Aus
|
||||||
zeitlichen Gründen haben wir nur einen kleinen Teil der Use Cases im
|
zeitlichen Gründen haben wir nur einen kleinen Teil der Use Cases im
|
||||||
Detail ausgearbeitet. Insbesondere diese welche wir selber
|
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:
|
aus, die Use Cases mit den Nummern wurden dabei im Detail ausgearbeitet:
|
||||||
|
|
||||||
#+LATEX: {\footnotesize
|
#+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
|
#+CAPTION: Ein frühes Mockup des Shop
|
||||||
#+ATTR_LATEX: :width \textwidth
|
#+ATTR_LATEX: :width \textwidth
|
||||||
#+NAME: mockup
|
#+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]
|
#+ATTR_LATEX: :width 9cm :placement [H]
|
||||||
#+CAPTION: Klassenmodel für Kategorien
|
#+CAPTION: Klassenmodel für Kategorien
|
||||||
#+NAME: fig:category
|
#+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}
|
Da diese Variabel jedoch essentiell für die Funktion des Webshops ist
|
||||||
\footcite{removeadd}
|
mussten wir sicherstellen das sie von einem Administrator nicht aus
|
||||||
\footcite{removedelete}
|
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]
|
#+ATTR_LATEX: :width 9cm :placement [H]
|
||||||
#+CAPTION: Klassenmodel für Optionen
|
#+CAPTION: Klassenmodel für Optionen
|
||||||
#+NAME: fig:option
|
#+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]
|
#+ATTR_LATEX: :width 9cm :placement [H]
|
||||||
#+CAPTION: Klassenmodel für Artikelstatus
|
#+CAPTION: Klassenmodel für Artikelstatus
|
||||||
#+NAME: fig:articlestatus
|
#+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]
|
#+ATTR_LATEX: :width 9cm :placement [H]
|
||||||
#+CAPTION: Klassenmodel für Wechselkurse
|
#+CAPTION: Klassenmodel für Wechselkurse
|
||||||
#+NAME: fig:exchangerate
|
#+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]
|
#+ATTR_LATEX: :width 9cm :placement [H]
|
||||||
#+CAPTION: Klassenmodel für Artikel
|
#+CAPTION: Klassenmodel für Artikel
|
||||||
#+NAME: fig:article
|
#+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]
|
#+ATTR_LATEX: :width 9cm :placement [H]
|
||||||
#+CAPTION: Klassenmodel für Bestellstatus
|
#+CAPTION: Klassenmodel für Bestellstatus
|
||||||
#+NAME: fig:orderstatus
|
#+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]
|
#+ATTR_LATEX: :width 9cm :placement [H]
|
||||||
#+CAPTION: Klassenmodel für Warenbestellungen
|
#+CAPTION: Klassenmodel für Warenbestellungen
|
||||||
#+NAME: fig:orderofgoods
|
#+NAME: fig:orderofgoods
|
||||||
[[./pictures/class_orderofgoods.png]]
|
[[file:pictures/class_orderofgoods.png]]
|
||||||
|
|
||||||
**** NEXT Picture
|
**** Picture
|
||||||
|
|
||||||
\footcite{upload}
|
Über das Modell "Picture", Abbildung:([[fig:picture]]) können Bilder für
|
||||||
\footcite{images}
|
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]
|
#+ATTR_LATEX: :width 9cm :placement [H]
|
||||||
#+CAPTION: Klassenmodel für Bilder
|
#+CAPTION: Klassenmodel für Bilder
|
||||||
#+NAME: fig:picture
|
#+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]
|
#+ATTR_LATEX: :width 9cm :placement [H]
|
||||||
#+CAPTION: Klassenmodel für Bestellungen
|
#+CAPTION: Klassenmodel für Bestellungen
|
||||||
#+NAME: fig:order
|
#+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]
|
#+ATTR_LATEX: :width 9cm :placement [H]
|
||||||
#+CAPTION: Klassenmodel für Warenkörbe
|
#+CAPTION: Klassenmodel für Warenkörbe
|
||||||
#+NAME: fig:shoppingcart
|
#+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]
|
#+ATTR_LATEX: :width 9cm :placement [H]
|
||||||
#+CAPTION: Klassenmodel für Städte
|
#+CAPTION: Klassenmodel für Städte
|
||||||
#+NAME: fig:city
|
#+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]
|
#+ATTR_LATEX: :width 9cm :placement [H]
|
||||||
#+CAPTION: Klassenmodel für Anreden
|
#+CAPTION: Klassenmodel für Anreden
|
||||||
#+NAME: fig:salutation
|
#+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]
|
#+ATTR_LATEX: :width 9cm :placement [H]
|
||||||
#+CAPTION: Klassenmodel für Personen
|
#+CAPTION: Klassenmodel für Personen
|
||||||
#+NAME: fig:person
|
#+NAME: fig:person
|
||||||
[[./pictures/class_person.png]]
|
[[file:pictures/class_person.png]]
|
||||||
|
|
||||||
** Benutzerinterface
|
** Benutzerinterface
|
||||||
*** Mockup skizzieren
|
*** 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