Calculatoare și tehnologia informației [630844]

UNIVERSITATEA TEHNICĂ „Gheorghe Asachi” din IAȘI
FACULTATEA DE AUTOMATICĂ ȘI CALCULATOARE
DOMENIUL: Calculatoare și tehnologia informației
SPECIALIZAREA:Tehnologia informației
Aplicație web pentru managementul
angajaților unei firme de curierat
LUCRARE DE LICENȚĂ
Profesor coordonator:
Ș.l.dr.ing. George-Emil Vieriu
Student: [anonimizat], 2020

Cuprins
Introducere…………………………………………………………………………………………………………………….. 1
Capitolul 1. Noțiuni teoretice …………………………………………………………………………………………… 2
1.1. Contextul lucrării ………………………………………………………………………………………………… 2
1.2. Aplicații asemănătoare …………………………………………………………………………………………. 2
1.2.1. Evernote………………………………………………………………………………………………………. 2
1.2.2. Slack…………………………………………………………………………………………………………… 3
1.2.3. Trello………………………………………………………………………………………………………….. 3
1.3. Tehnologii folosite pentru implementare ………………………………………………………………… 5
1.3.1. Sublime Text Editor ………………………………………………………………………………………. 5
1.3.2. Framework-ul Django …………………………………………………………………………………… 5
1.3.3. SQLite………………………………………………………………………………………………………… 7
1.3.4. HTML…………………………………………………………………………………………………………. 8
1.3.5. CSS…………………………………………………………………………………………………………….. 9
1.3.6. Bootstrap…………………………………………………………………………………………………… 10
Capitolul 2. Proiectarea aplicației …………………………………………………………………………………… 11
2.1. Funcționalități ……………………………………………………………………………………………………. 11
2.2. Arhitectura generală a aplicației …………………………………………………………………………… 12
2.2.1. WSGI………………………………………………………………………………………………………… 12
2.2.2. Arhitectura Django ……………………………………………………………………………………… 12
2.3. Proiectarea bazei de date …………………………………………………………………………………….. 14
2.3.1. Diagrama bazei de date. Generarea automată …………………………………………………. 15
2.4. Proiectarea aplicației Django ………………………………………………………………………………. 17
2.4.1. Interfața pentru administrator ……………………………………………………………………….. 17
2.4.2. Interfața pentru utilizatori …………………………………………………………………………….. 19
Capitolul 3. Implementarea aplicației ……………………………………………………………………………… 21
3.1. Crearea și configurarea proiectului ………………………………………………………………………. 21
3.2. Implementarea bazei de date ……………………………………………………………………………….. 22
3.2.1. Model Form ……………………………………………………………………………………………….. 23
3.2.2. Filter Form …………………………………………………………………………………………………. 24
3.3. Transmiterea datelor în Template-uri ……………………………………………………………………. 25
3.4. Adrese URL………………………………………………………………………………………………………. 26
3.5. Autentificare și înregistrarea useri-lor …………………………………………………………………… 27
3.5.1. Decoratori Django……………………………………………………………………………………… 29
3.6. Interfața cu utilizatorul ……………………………………………………………………………………….. 30
Capitolul 4. Testarea aplicației ……………………………………………………………………………………….. 35
Concluzii……………………………………………………………………………………………………………………… 37
Bibliografie………………………………………………………………………………………………………………….. 38
Anexe………………………………………………………………………………………………………………………….. 39
Anexa 1. Codul din fișierul all_models.dot generat pentru crearea diagramei bazei de date 39

Aplicație web pentru managementul angajaților unei firme de
curierat
Emanuel Ursache
Rezumat
Tema lucrării de licență o reprezintă aplicația web pentru managementul angajaților unei
firme de curierat, ce oferă o serie de facilități ce ușurează gestionarea angajaților unei firme de
profil.
Aplicația noastră include o serie de tehnologii necesare implementării și dezvoltării
acesteia: Framework-ul Django, SQLite, HTML, CSS, Bootstrap.
În cele din urmă aplicația dezvoltată oferă două interfețe: una pentru administrator și una
pentru curieri, și dispune de o serie de funcționalități, ce diferă în funcție de tipul utilizatorului
(administrator sau curier):
•autentificarea și înregistrarea userilor;
•plasarea (respectiv editarea sau ștergerea) de către administrator a unei noi
comenzi către oricare dintre curieri;
•crearea de sondaje noi (respectiv editarea sau ștergerea lor) de către administrator,
iar voturile vor fi centralizate într-o statistică;
•posibilitatea schimbării informațiilor personale ale unui curier, disponibile pe
pagina lui de profil (nume, email, număr de telefon, precum și poza de profil);
•un filtru de căutare, disponibil pentru a căuta, după mai multe câmpuri
disponibile, între comenzile plasate unui curier (această funcționalitate este
disponibilă și curierilor, aceștia având posibilitatea să caute, după aceleași
câmpuri, în comenzile plasate lor de către administrator);
•curierii au la dispoziție o listă personală de sarcini – aceștia au posibilitatea să-și
adauge sarcini noi, să le modifice sau să le bifeze drept îndeplinite (cele
îndeplinite vor apărea tăiate cu o linie dreptă);
•votarea sondajelor de către curieri (aceștia pot alege dintre opțiunile de răspuns
adăugate inițial de către administrator).

Introducere
Introducere
Aplicația pe care am dezvoltat-o este o aplicație web pentru managementul angajaților
dintr-o firmă de curierat, dezvoltată în framework -ul1 Django. Aplicația își propune să ofere o
serie de facilități atât administratorului firmei cât și angajaților, pentru a le ușura munca de zi cu
zi.
Am ales această temă deoarece, în ziua de astăzi, totul se învârte în jurul eficienței la
locul de muncă, fiind considerat un aspect esențial nu doar pentru angajați, dar și pentru
angajatori. Fiecare angajat sau angajator își dorește să lucreze într-un spațiu și într-un mediu cât
mai eficient.
De asemenea, strâns legat de conceptul de productivitatea, este conceptul de eficiență, un
concept foarte important în mediul de afaceri. După o simplă căutare pe internet putem găsi mii
de studii și de articole ce au ca scop creșterea productivității, lucru cu totul indispensabil într-o
piață care pe zi ce trece, devine tot mai competitivă.
Din aceste motive, am vrut să văd dacă reușesc să dezvolt o aplicație care să permită
integrarea acestor concepte absolut necesare și fără de care o afacere nu poate prospera.
Am ales să dezvolt aplicația în framework -ul Django (care, alături de Flask, reprezintă
cele mai bune framework -uri web scrise în Python) deoarece, deși nu stăpâneam deloc acest
framework când am ales tema lucrării, totuși am luat acest lucru ca pe o provocare cu mine
însumi, propunându-mi astfel nu doar să realizez un proiect, ci, în același timp, să învăț cât mai
multe despre ceea ce presupune Django.
Mi-am ales ca obiectiv acela de a crea o aplicație intuitivă, care să ne ofere și să ne
faciliteze activitatea de management al angajaților, acest lucru presupune atât dezvoltarea
aplicației web, interfața cu care utilizatorii vor avea contact, cât și a instrumentelor sau
serviciilor din spatele aplicației care fac posibil accesul la diferite funcționalități.
Întregul proces necesar pentru dezvoltarea aplicației, de la stadiul de ideea, până în
stadiul în care să avem o aplicație funcțională, ne este expus în decursul celor 4 capitole din
acestă lucrare, capitole intitulate astfel:
•Noțiuni teoretice
•Proiectarea aplicației
•Implementarea aplicației
•Testarea aplicației
Bazele teoretice necesare pentru dezvoltarea aplicației și respectiv pentru întocmirea
acestei lucrări au fost dobândite în urma parcurgerii obiectelor studiate în cursul celor patru ani
de facultate, dintre care cel mai mult m-au ajutat următoarele:
•Proiectarea Sistemelor de Baze de Date
•Extragerea Cunoștințelor din Baza de Date
•Programare Web
•Tehnologii Internet
•Sisteme Distribuite
Pe lângă acestea, pentru realizarea aplicației, se adaugă și cunoștințe acumulate de-a
lungul timpului prin învățare autodidactă. Acest lucru l-am făcut datorită interesului și pasiunii
pentru domeniul IT, dar și dintr-o curiozitate pentru a descoperi ceva nou. În tot acest proces de
învățare un rol esențial l-a jucat internetul, informațiile vaste, exemplele și tutorialele disponibile
pe acesta.
1Un framework este o aplicație ce conține o colecție de scripturi cu ajutorul căreia creatorii de pagini web pot
realiza mult mai rapid un site complex
1

Emanuel Ursache
Capitolul 1. Noțiuni teoretice
1.1. Contextul lucrării
Prin natura sa, omul a încercat să-și simplifice și să-și eficientizeze munca, drept urmare,
și-a construit diferite „unelte” și mijloace care să-i permită acest lucru, trecând astfel de la idee la
concept.
Drept urmare, în ceea ce privește gestionarea resurselor materiale cât și a resurselor
umane s-a dezvoltat de-a lungul timpului conceptul de management1. Acest concept s-a impus în
sfera afacerilor în anul 1941, prin lucrarea ”The Managerial Revolution”, publicată de către
James Burnham, la New York, în care s-a stabilit termenul de manager, ca vector al inovației și
al progresului.
Importanța resursei umane în gestionarea cu succes a unei afaceri e cea care face din
managementul resurselor umane, un set de competențe și de deprinderi ce nu trebuie să lipsească
niciunui manager. Aceste lucruri sunt legate direct de valorile principale ale companiei.
De aceea, de-a lungul anilor s-au dezvoltat diferite modalități de a tine evidența resursei
umane, de la foi de pontaj până, în zilele noastre, la aplicații moderne și eficiente de gestionare a
angajaților. Așadar, î n ultima vreme, s-au dezvoltat o serie de astfel de aplicații, de
managementul angajaților, disponibile atât în variante gratuite cât și contra cost, fiecare cu
specificul ei, în funcție de viziunea creatorului [1].
1.2. Aplicații asemănătoare
1.2.1. Evernote
Evernote este o aplicație foarte utilă mai ales pentru oamenii de afaceri care au o
activitate mai dinamică și sunt tot timpul în mișcare. Permite, de asemenea, crearea de liste și
prezentări, precum stocarea de fotografii și de înregistrări audio.
Pe lângă acestea, simplifică managementul echipei, dar, mai mult decât atât, și a
sarcinilor personale ale administratorului, cum ar fi crearea de notițe pe telefonul mobil și să le
transmită rapid angajaților, fiind foarte utilă și pentru sincronizarea între dispozitivele mobile și
desktop2.
Această aplicație dispune de o versiune gratuită, ce permite utilizatorilor încărcarea de
date de a până 60 MB pe lună. Există și o variantă Plus, ce costă 34,99 $ pe an, și în plus față de
versiunea gratuită, permite accesarea notelor atunci când utilizatorul este offline3, salvarea
e-mailurilor, precum și încărcarea a până la un 1 GB de date în fiecare lună. Varianta Premium,
alături de alte opțiuni suplimentare, permite stocarea a până 10 GB de date lunar, iar costul este
de 69,99$ pe an.
1Managemet – reprezintă procesul de gestionare a resurselor materiale, financiare și informaționale ale unei
organizații, în scopul îndeplinirii obiectivelor esențiale ale acesteia
2Computer
3Offline – fără conexiune la internet
2

Capitolul 1. Noțiuni teoretice
1.2.2. Slack
Slack este o platformă foarte utilă de mesagerie, cu ajutorul acesteia utilizatorul poate
organiza conversațiile echipei sale în diferite forme: pot fi canale private, publice sau, de
asemenea, se pot trimite mesaje directe spre alți utilizatori. De asemenea, sunt disponibile în
aplicație opțiuni precum cea de drag&drop, de partajare a imaginilor, a diferitelor fișiere precum
cele în format PDF, indexează automat și arhivează orice mesaj, fișier precum și notificări. Un alt
avantaj îl constituie faptul că nu există practic o limita în ceea ce privește numărul de utilizatori
pe care un administrator îi poate adăuga.
Aplicația standard este disponibilă gratuit pentru utilizatori, însă exista o variantă ce
dispune de mai multe funcții. Această variantă costa 8$ pe lună pentru fiecare utilizator.
1.2.3. Trello
Trello este o aplicație ce are drept scop simplificarea fluxului de lucru și centralizarea
comunicării. Acest gen de aplicație permite întregii echipe să dispună de o pagină comună în
care să se regăsească sarcinile de zi cu zi ale acestora.
O caracteristică foarte importantă a acestei aplicații o constituie vizibilitatea. Fiecare
proiect este actualizat după status, în funcție de etapa în care se află: în așteptare, în curs de
actualizare, finisat. Alte opțiuni ale aplicației sunt: atașarea de fișiere, atribuirea de sarcini
angajaților, distribuirea angajaților în funcție de proiect. Permite, de asemenea, ca orice angajat
să fie pus la curent pe măsură ce apar schimbări în desfășurarea proiectului.
În versiunea standard, Torello este disponibil gratuit pentru utilizatori, însă există și o
versiune ce dispune de mai multe opțiuni. Această variantă începe de la 3,75$ pe lună pentru
3
Figura 1.1. Interfata Evernote, figură preluată de la
https://help.evernote.com/hc/en-us/articles/209006027-What-s-new-in-Evernote-Web.

Emanuel Ursache
fiecare angajat al companiei.
4
Figura 1.2. Interfață Slak – figură preluata de la https://www.theverge.com/2020/3/18/21184865/slack-
redesign-update-sidebar-changes-available-now-download.
Figura 1.3. Interfață Trello – figură preluată de la https://blog.trello.com/how-design-teams-are-using-
trello-ultimate-guide.

Capitolul 1. Noțiuni teoretice
1.3. Tehnologii folosite pentru implementare
1.3.1. Sublime Text Editor
Sublime Text Editor este un editor de coduri sursă sofisticat,
ce este utilizat pe scară largă în rândul dezvoltatorilor, pentru scrierea
codurilor în Python. Interfața cu utilizatorul al editorului împreună cu
numeroasele sale extensii pentru evidențierea sintaxei, găsirea
fișierelor sursă și Syntax Highlight1, fac ca editorul să fie mai
accesibil pentru programatorii noi decât alte aplicații precum Vim2 și
Emacs3 [2].
Pe lângă acestea editorul mai dispune și de opțiuni precum
auto completare (completări automate de înregistrări pe măsură ce
utilizatorul tastează în funcție de limba utilizată. De asemenea,
completează automat variabilele create de utilizator), construirea de
coduri în editor, ce permite utilizatorilor să ruleze cod pentru anumite
limbi din editor, ceea ce elimină nevoia de a comuta la linia de
comandă și înapoi. Această funcție poate fi, de asemenea, setată
pentru a construi codul automat de fiecare dată când este salvat
fișierul.
Versiunea 3 a intrat în versiune beta la 29 ianuarie 2013. La
început este disponibilă numai pentru utilizatorii înregistrați care au
achiziționat Sublime Text 2, la 28 iunie 2013 a devenit disponibilă
publicului larg.
1.3.2. Framework-ul Django
Acesta este unul dintre cele mai populare framework-uri web
folosite la ora actuală. Foarte multe companii și instituții din toată
lumea îl folosesc pentru site-uri și aplicații web, cum ar fi: NASA,
Pinterest, Instagram, Disque. Cu relativ puține linii de cod se pot
construi rapid aplicații sigure și scalabile pentru milioane de
utilizatori.
Este un framework scris în Python, gratuit și open source4, ce
ajută utilizatorii să scrie un cod cu următoarele caracteristici [3]:
•Complet: oferă aproape tot ceea ce dezvoltatorii au nevoie.
Totul funcționează perfect împreună, respectă principii de
proiectare consecvente și are o documentare extinsă și
actualizată.
•Portabil: Django este scris în Python, care rulează pe mai
multe platforme. Asta înseamnă că utilizatorul nu este legat de nicio platformă de server
anume și poate rula aplicațiile pe mai multe tipuri de Linux, Windows și Mac OS X. Mai
mult, Django este bine susținut de mulți furnizori de găzduire web, care furnizează
1Syntax Highlight reprezintă o facilitate a numeroase editoare de text ce presupune evidențierea cuvintelor cheie
cu diferite culori pentru a crește lizibilitatea codului.
2Vim este un editor de text foarte configurabil, creat pentru a face crearea și schimbarea oricărui tip de text foarte
eficient.
3Emacs reprezintă o clasă de editoare multi platformă caracterizate prin extensibilitate.
4Open source descrie practica de a dezvolta anumite produse finite, permițând utilizatorilor accesul de a acționa
liber asupra procesului de producție sau dezvoltare.
5
Figura 1.4. Structură de fișiere și
directoare în Sublime Text Editor

Emanuel Ursache
adesea infrastructură specifică și documentație pentru găzduirea site-urilor Django.
•Versatil: Django poate fi (și a fost) folosit pentru a construi aproape orice tip de site web –
de la sisteme de gestionare a conținutului, până la rețele sociale și site-uri de știri. Poate
funcționa cu orice framework din partea clientului și poate livra conținut în aproape orice
format (inclusiv HTML, fluxuri RSS, JSON, XML1 etc).
•Sigur: Django îi ajută pe dezvoltatori să evite multe greșeli comune de securitate, oferind
un cadru conceput pentru a face lucrurile corecte și pentru a proteja automat site-ul. De
exemplu, Django oferă o modalitate sigură de a gestiona conturile de utilizator și
parolele, evitând greșelile obișnuite precum introducerea informațiilor în cookie-urile2
unde acestea sunt vulnerabile (în schimb cookie-urile conțin doar o cheie, iar datele reale
sunt stocate în baza de date) sau stocarea directă a parolelor, decât a un hash de parolă.3
•Scalabil: Django folosește o arhitectură bazată pe componente (fiecare parte a arhitecturii
este independentă de celelalte și, prin urmare, poate fi înlocuită sau schimbată dacă este
nevoie). A avea o separare clară între diferitele părți înseamnă că poate scala pentru un
trafic crescut prin adăugarea de hardware la orice nivel: servere de memorie în cache,
servere de baze de date sau servere de aplicații [3].
În Django, o aplicație web așteaptă solicitări HTTP de la browserul web (sau de la un alt
client). La primirea unei solicitări, aplicația rezolvă ceea ce este necesar pe baza adresei URL și,
eventual, a informațiilor din datele POST sau din datele GET. În funcție de ceea ce este necesar,
poate citi sau scrie informații dintr-o bază de date sau poate efectua alte sarcini necesare pentru a
satisface solicitarea. Aplicația va întoarce apoi un răspuns la browserul web, creând în mod
dinamic o pagină HTML pentru ca browserul să fie afișat prin inserarea datelor preluate în locații
într-un șablon HTML.
Aplicațiile web Django grupează de obicei codul care gestionează fiecare dintre acești
pași în fișiere separate:
1 Diferite tipuri de reprezentare și interschimb de date între aplicații informatice
2 Reprezintă un text special, deseori codificat, trimis de un server unui navigator web și apoi trimis înapoi
(nemodificat) de către navigator, de fiecare dată când accesează acel server.
3 Un hash de parolă este o valoare de lungime fixă creată prin trimiterea parolei printr-o funcție de hash.
6
Figura 1.5. Arhitectura Django.

Capitolul 1. Noțiuni teoretice
•URLs: Deși este posibil să se proceseze cererile de la fiecare adresă URL printr-o singură
funcție, este mult mai ușor să se scrie o funcție de vizualizare separată pentru a gestiona
fiecare resursă. Un Mapper URL este utilizat pentru a redirecționa cererile HTTP către
vizualizarea corespunzătoare pe baza adresei URL a solicitării. Mapper-ul URL poate, de
asemenea, să corespundă modelelor particulare de șiruri sau cifre care apar într-o adresă
URL și să le transmită unei funcții de vizualizare ca date.
•View : Un view este o funcție de gestionare a cererilor, care primește solicitări HTTP și
returnează răspunsuri HTTP. Aceasta accesează datele necesare pentru a satisface cererile
prin Models și delegă formatarea răspunsului la Template.
•Model: Acestea sunt obiecte Python care definesc structura datelor unei aplicații și oferă
mecanisme de gestionare (adăugare, modificare, ștergere) și înregistrări de interogări din
baza de date.
•Template: Un Template este un fișier text care definește structura sau aspectul unui fișier
(cum ar fi o pagină HTML). Un View poate crea dinamic o pagină HTML folosind un
șablon HTML, populându-l cu date dintr-un model. Un șablon poate fi utilizat pentru a
defini structura oricărui tip de fișier, nu trebuie să fie neparat HTML.
1.3.3. SQLite
SQLite este o mică bibliotecă C1 ce implementează un motor de baze de date SQL
încapsulat, oferă posibilitatea de a-l introduce în diverse sisteme și nu necesită configurare.
SQLite este diferit de majoritatea altor motoare de baze de date SQL prin aceea că a fost
proiectat pentru a fi simplu: [4]
•de administrat;
•de folosit ;
•de a fi încapsulat într-un program mai mare;
•de întreținut;
•de setat.
SQLite are o serie de caracteristici care îl diferențiază de restul motoarelor de baze de
date SQL
•Zero-Configurare: SQLite nu are nevoie de o instalare în prealabil și nu are
nevoie nici de setup. De asemenea, nu există vreun proces server, care să necesite
o pornire, oprire sau configurare (nu folosește fișiere de configurare). Pe lângă
aste, nu este necesar un administrator pentru crearea unei noi instanțe de bază de
date sau pentru permisiuni de acces pentru utilizatori.
•Fără server: contrar altor motoare de baze de date, SQLite nu folosește niciun
proces server intermediar. Pentru a baza de date, se citește și se scrie direct din
fișierele bază de date de pe disc. Marele avantaj al acestei caracteristici îl
constituie faptul că nu este nevoie de un proces server de instalat, inițializat, setat,
administrat, configurat și reparat.
•Un singur fișier bază de date: în SQLite, o bază de date reprezintă un singur fișier
disc. Acesta nu are nevoie de o poziție specială în ierarhia de directoare, ci poate
fi plasat oriunde în interiorul acesteia. De asemenea, acestea sunt fi ușor de
partajat, necesită doar a fi copiate și trimise prin orice mijloc (USB2, e-mail, etc.)
1 C este un limbaj de programare relativ minimalist ce operează în strânsă legătură cu hardware-ul, fiind cel mai
apropiat de limbajul de asamblare față de majoritatea celorlalte limbaje de programare.
2 Universal Serial Bus: este o specificație pentru cabluri, conectori și protocoale de comunicații folosite pentru
conectarea, comunicarea și alimentarea cu energie electrică între diverse dispozitive
7

Emanuel Ursache
•Compact: Atunci când are toate opțiunile activate, și este optimizată pentru
mărime, întreaga librărie SQLite, este mai mică de 225 KiO1. Cu toate acestea,
mărimea librării poate fi micșorata până la 170 KiO atunci când, în timpul
compilării, sunt dezactivate opțiunile nenecesare
•Alocarea tipului de date evident: aceste mod de alocare înseamnă ca tipul de date
reprezintă o proprietate a valorii însăși, și nu a coloanei în care este stocată
valoarea. Acest lucru înseamnă că în SQLite este permis utilizatorului să stocheze
orice valoare de orice tip în orice coloană, indiferent de tipul declarat al acelei
coloane.
•Înregistrări de lungime variabilă: spre deosebire de alte motoare de baze de date
SQL, în SQLite se folosesc doar cantitatea de spațiu de pe disc necesară să
stocheze informația într-o linie. Acest avantaj se concretizează în faptul ca vom
avea fișiere de bază de date mult mai mici, deci baza de date va rula mai repede,
de vreme ca avem mai puțină informație pe disc [5]
1.3.4. HTML
HTML (HyperText Markup Language) este limbajul standard de marcare pentru
documentele concepute pentru a fi afișate într-un browser web. Poate fi asistat de tehnologii
precum CSS2 și limbaje de script cum ar fi JavaScript3.
HTML 1.0, prima versiune a limbajului HTML a apărut în anul1991 și avea suport din
partea Mosaic, primului browser cu succes. După aceasta, 4 ani mai târziu, în septembrie 1995,
este admisă ca standard prima versiune oficială, HTML 2.0. Următoarea versiune, HTML 3.0 nu
s-a bucurat de un succes prea mare, însă, versiunea 4.0 vine cu o serie de schimbări majore, cum
ar fi introducerea CSS (Cascade Style Sheets). Apare HTML 5 în ianuarie 2008, când a fost
publicat un document de lucru pentru o nouă versiune, iar specificația sa a fost finalizată în
octombrie 2014 [6].
Browserele Web primesc documente HTML de pe un server web sau de la stocarea locală
și le redau în pagini web multimedia. HTML descrie structura unei pagini web în mod semantic
și inițial a inclus indicii pentru apariția documentului.
Elementele HTML sunt blocurile de construcție ale paginilor HTML. Cu construcții
HTML, imagini și alte obiecte, cum ar fi formulare interactive, pot fi încorporate în pagina
redată. HTML oferă un mijloc de a crea documente structurate notând semantica structurală
pentru text cum ar fi titluri, paragrafe, liste, link-uri, citate și alte elemente. Elementele HTML
sunt delimitate prin etichete, scrise cu paranteze de unghi. Etichete precum <img /> și <input />
introduc direct conținut în pagină. Alte etichete, cum ar fi <p> oferă informații despre textul
documentului și pot include alte etichete ca sub-elemente. Navigatoarele nu afișează etichetele
HTML, ci le folosesc pentru a interpreta conținutul paginii [7].
În literatura de specialitate găsim așa numitele TAG-uri. Aceste, prin convenție, încep cu
paranteză unghiulara deschisă „<” și se încheie cu paranteză unghiulară închisă „>”.
Orice document HTML are 3 tag-uri esențiale. Primul este <html>, ce se termină cu
notația </html>. Între aceste două tag-uri se află întreg codul HTML.
Cu tag-ul <head> se începe cea de-a doua secțiune care se încheie cu tagul </head>.
Aceasta conține informații ce nu sunt afișate în browser.
În interiorul marcajului <body>, terminat de marcajul </body> , unde avem corpul
documentului, se află tot conținutul paginii web care va apărea în browser (text, imagini, tabele,
1KibiOctet – unitate de măsură pentru memorie egală cu 1024 octeți.
2 Cascading Style Sheets este un standard pentru formatarea documentelor HTML.
3 Este un limbaj de programare orientat obiect bazat pe conceptul prototipurilor.
8

Capitolul 1. Noțiuni teoretice
etc.).
1.3.5. CSS
CSS sau Cascade Style Sheet reprezintă un standard pentru formatarea documentelor
HTML. Codul CSS se poate accesa prin doua moduri, primul fiind prin intermediul fișierelor
externe ce au extensia „.css”, iar al doilea mod consta în integrarea codului CSS în interiorul
paginii HTML cu ajutorul tag-ului <style> și/sau atributului style
Numele ”Cascade” provine din schema prioritară specificată pentru a determina ce regulă
de stil se aplică dacă mai multe reguli se potrivesc cu un anumit element
Acest limbaj este proiectat pentru a permite separarea prezentării și conținutului, inclusiv
aspectul, culorile și fonturile. Această separare poate îmbunătăți accesibilitatea conținutului,
poate oferi mai multă flexibilitate și control în specificarea caracteristicilor de prezentare,
permite mai multor pagini web să partajeze formatarea. De asemenea reduce complexitatea și
repetarea conținutului structural, precum și permite fișierul .css care urmează să fie memorat în
cache pentru a îmbunătăți viteza de încărcare a paginii între paginile care partajează fișierul și
formatarea acestuia.
Separarea formatării și a conținutului face, de asemenea, posibilă prezentarea aceleiași
pagini de marcare în diferite stiluri pentru diferite metode de redare, cum ar fi pe ecran, în
tipărire, prin voce și pe Braille dispozitive tactile. CSS are, de asemenea, reguli pentru
formatarea alternativă dacă este accesat conținutul pe un dispozitiv mobil [8].
1.3.6. Bootstrap
9
Figura 1.6. Structura generală a un fișier html. Imagine preluată de la –
http://www.irinaciocan.ro/tehnici_web/lab1.php.

Emanuel Ursache
Bootstrap este un framework pentru dezvoltarea front-end-ului aplicațiilor web. Inițial
numit Twitter Blueprint, a fost dezvoltat de Mark Otto și Jacob Thornton la Twitter ca și cadru
pentru a încuraja coerența între instrumentele interne. Înainte de Bootstrap, diverse biblioteci au
fost utilizate pentru dezvoltarea interfeței, ceea ce a dus la incoerențe și o sarcină mare de
întreținere.
Principalele caracteristici sunt:
•ușor de utilizat;
•flexibil („responsive”), se ajustează la telefoane, tablete sau desktop-uri;
•asigură compatibilitatea cu browserele principale.
Scopul principal al adăugării la un proiect web este de a aplica opțiunile Bootstrap de
culoare, dimensiune, font și aspect la acel proiect. Ca atare, factorul principal este ca
dezvoltatorii fac acele alegeri după bunul lor plac. Odată adăugat la un proiect, Bootstrap oferă
definiții de bază ale stilului pentru toate elementele HTML. Rezultatul este un aspect uniform
pentru text, tabele și elemente de formă din browserele web. În plus, dezvoltatorii pot profita de
clasele CSS definite în Bootstrap pentru a personaliza în continuare aspectul conținutului lor. De
exemplu, Bootstrap a prevăzut tabele cu culori deschise și închise, titluri de pagină și text cu
evidențiere.
Bootstrap vine de asemenea cu mai multe componente JavaScript sub formă de plugin-uri
jQuery. Acestea furnizează elemente suplimentare de interfață, cum ar fi casetele de dialog, fișele
de unelte și multe alte elemente. Fiecare componentă Bootstrap constă dintr-o structură HTML,
declarații CSS și, în unele cazuri, însoțitoare de cod JavaScript. De asemenea, extind
funcționalitatea unor elemente de interfață existente [9].
10

Capitolul 2. Proiectarea aplicației
Capitolul 2. Proiectarea aplicației
Aplicația propriu zisă este formată din trei proiecte diferite, dar legate între ele, fiecare
având o serie de funcționalități diferite:
•Primul proiect intitulat ”accounts”, se ocupă cu parte de gestionarea comenzilor,
de gestionarea conturilor și de creare de noi conturi.
•Al doilea proiect intitulat ”pools”, se ocupă cu crearea de statistici de către
administrator, userii având posibilitatea de a vota aceste poll-uri1.
•Al treilea proiect intitulat ”tasks”, se ocupă cu crearea unei ”to do list2” de către
fiecare utilizator, pe care o poate modifica ulterior.
Toate acestea sunt integrate într-un întreg prin intermediului ”proiectului mamă” intitulat
generic ”licenta”.
2.1. Funcționalități
Am implementat o serie de funcționalități utile pentru ca aplicația să-și poate îndeplini
scopul, și anume acela de a putea gestiona și conduce o echipă în cazul administratorului,
respectiv ușurarea muncii în cazul curierilor.
Administratorul dispune de următoarele funcționalități:
•autentificarea pe baza username-ului și a parolei;
•crearea unei comenzi noi pentru un curier (introducerea informațiilor despre colet,
destinație, cât și despre client);
•editarea și ștergerea unei comenzile;
•are o evidență clara a tuturor comenzilor în funcție de statusul acestora;
•dispune de o funcție de search3 (administratorul poate opta să facă căutarea după
unul sau mai multe câmpuri: client, adresă de livrare, statusul comenzii,
specificații despre colet, precum și după data creării comenzii);
•poate accesa pagina de profil a fiecărui curier, unde dispune de mai multe
informații despre angajatul respectiv precum și despre activitatea acestuia
(informațiile acestuia, numărul de comenzi, informații despre fiecare comandă în
parte, cu posibilitatea de a edita sau a șterge respectiva comandă, precum și
funcția de search cu care poate căuta în comenzile curierului);
•creează noi sondaje pentru angajați pe care le poate edita sau ștergere, și dispune
de o evidență clara a voturilor în cazul fiecărui sondaj în parte.
Angajații dispun de următoarele facilități:
•posibilitatea de a se înregistra cu un username și o parolă în cazul în care este un
curier nou;
•autentificarea pe baza username-ului și a parolei;
•are o evidență clara a comenzilor sale de la administrator, în funcție de statusul
acestora;
•dispune de funcția de search de care dispune și administratorul, pentru ca căuta în
comenzile sale;
1Poll – reprezintă un sondaj, o consultare realizată în scopul de a afla părerea generală a participanților la
respectivul sondaj în legătură cu anumite teme sau acțiuni
2To do list – reprezintă o forma de organizare a activității pe o perioadă de timp, sub forma unor sarcini de lucru
trecute pe o lista bine intocmită
3Reprezintă o funcție de căutare după niște câmpuri prestabilite
11

Emanuel Ursache
•fiecare angajat are o pagina de profil, cu poză de profil și informații personale
(acesta poate edita atât poza de profil cât și informațiile personale);
•poate vota în sondajele făcute de administrator, și de asemenea, își poate schimba
votul;
•fiecare angajat dispune de o listă personală de ”to do”, unde poate adăuga task-uri
noi, poate șterge orice task dorește, și poate edita fiecare task. Asta înseamna ca
poate modifica atât enunțul acestuia, cât și statusul (îndeplinit sau neîndeplinit).
2.2. Arhitectura generală a aplicației
2.2.1. WSGI
În linii mari, WSGI (Web Server Gateway Interface) reprezintă o interfață între server-ul
web și aplicația Django. Un server web obișnuit nu permite rularea aplicațiilor scrise în Python,
drept urmare, comunitatea Python a venit cu WSGI, ca o interfață standard pe care modulele și
containerele le-ar putea implementa.
Dacă utilizăm un framework web standard, cum ar fi Django, Flask sau Bottle1, sau
aproape orice alt framework Python actual, nu trebuie să ne facem griji cu privire la modul în
care framework-ul implementează partea de aplicare a standardului WSGI, aceste lucruri sunt
configurate implicit. Drept urmare, serverul nostru web este configurat pentru a transmite
cererile către containerul WSGI care rulează aplicația web, apoi trece răspunsul (sub forma
HTML) înapoi solicitantului.
Serverele WSGI gestionează solicitările de procesare de la serverul web și decid cum să
comunice acele solicitări aplicației procesului unui cadru de aplicație. Segregarea
responsabilităților este importantă pentru scalarea eficientă a traficului web [10].
2.2.2. Arhitectura Django
În continuare voi prezenta mai multe scheme ce vor arata modul de funcționare a
aplicației create.
1Bottle este un micro web framework scris în Python.
12
Figura 2.1: Mod de funcționare WSGI.

Capitolul 2. Proiectarea aplicației
1.Se trimite o cerere.
2.Web server-ul recepționează cererea de la client și o trimite mai departe către un
server WSGI sau accesează direct o resursă statică din sistemul de fișiere.
3.Spre deosebire de un server web clasic, serverele WSGI pot rula aplicații Python.
Cererea populează o structură de date de tip dicționar, numită environ, după care
ajunge în cele din urmă în aplicația Django propriu-zisă (acolo unde are acces
developer-ul).
4.URLconf este defapt router-ul aplicației, acesta este răspunzător de rutarea
adreselor URL și selectarea view-urilor potrivite ; într-un final HttpRequest-ul este
transformat într-un obiect Python.
5.View-ul selectat, de obicei, realizează următoarele lucruri:
a).comunică cu baza de date prin intermediul modelelor;
b).redă pagini HTML sau orice alt tip de răspuns folosind template-uri;
c).returnează ca răspuns un text simplu (fără nici o formatare);
d).aruncă o excepție.
6.Obiectul HttpResponse este trimis ca un șir de caractere către web server.
7.Pagina web formatată este afișată în browser.
Fișierele wsgi.py (fișierul serverului WSGI) și manage.py (aceasta ne da accesul la o
listă de comenzi foarte utile, inclusiv aceea de pornire a serverului, de migrații1 sau de creare a
unui superuser2) vor rămâne intacte, nu ne vom atinge de ele.
În fișierul templates.py vom găsi template-uri, ce conține părțile statice ale ieșirii
HTML dorite, precum și o sintaxă specială care descrie modul în care va fi inserat conținut
dinamic, iar în fișierul models.py găsim structurată baza de date, fiecare tabelă fiind o clasă.
Conform convențiilor, toate funcțiile vor fi scrise în fișierul view.py. Un view este o
funcție Python care preia o solicitare Web și returnează un răspuns Web. Acest răspuns poate fi
1Migrațiile reprezintă modul Django de a implementa modificările aduse modelelor (adăugarea unui câmp,
ștergerea unui model etc.) în schema bazei de date
2Un user cu drepturi depline
13
Figura 2.2: Arhitectura aplicației Django.

Emanuel Ursache
conținutul HTML al unei pagini Web, sau o redirecționare, sau o eroare 404, sau o imagine, etc.
Acestă funcție în sine conține orice logică arbitrară este necesară pentru a returna acel răspuns, și
reprezintă puntea de legătură dintre models și templates (o funcție view ia o instanță specifică a
unui model și o pune într-un template).
2.3. Proiectarea bazei de date
Baza de date a aplicației este formată din 7 tabele. În acestea sunt stocate toate
informațiile, excepție făcând sigla și pozele de profil ale angajaților, care sunt stocate în folderul
”static/images”.
Pe lângă tabelele create pentru această aplicație, Django ne oferă din oficiu o serie de
tabele. Acest lucru ușurează cu mult munca dezvoltatorului deoarece poate extinde modelul
implicit de utilizator sau poate înlocui un model complet personalizat.
Ne vom folosi, în primul rând de tabela ” Users”. Alegând să extindem clasa ” Users” prin
clasa ”employee”.
De asemenea, Django ne oferă încă o clasă implicită intitulată ” Groups” în care putem
crea diferite grupuri în care să împărțim utilizatorii cu scopul de a distribui permisiunile fiecărui
grup, vom reveni asupra acestui aspect în Capitolul 3.
Din oficiu, Django atribuie fiecărui model o cheie primară, deci nu mai este nevoie de o
cheie primară declarată de dezvoltator.
id = models.AutoField(primary_key =True)
În ”accounts” avem 3 tabele:
•tabela ”employee”, ce are o relație unu la unu cu tabela ” User”, ceea ce înseamnă
că nu pot exista mai mulți angajați pe un user, și nici mai mulți useri pe un
angajat. De asemenea avem în această tabelă câmpuri pentru nume, număr de
telefon, mail, poză de profil și data la care a fost creat utilizatorul.
user = models.OneToOneField(User, null=True, blank=True, on_delete=models.CASCADE)
Are în dreptul fiecărui câmp din tabela ” null=True” deoarece, în cazul
14
Figura 2.3: Structura proiectului.

Capitolul 2. Proiectarea aplicației
introducerii unei noi înregistrări fără a avea toate câmpurile completate, să nu ne
fie semnalată nicio eroare. De asemenea ” on_delete=models.CASCADE ” asigură
faptul că dacă un user este șters automat este ștersă și înregistrarea din tabela
employee.
•Tabela ”customer” are o relație unu la unu cu tabela ” order”, are câmpuri pentru
nume, număr de telefon, adresă, mail și data la care a fost creată înregistrarea. Are
constrângeri în ceea ce privește lungimea datelor introduse, precum și cea de
primary key.
•Tabela ”order” are o relație unu la unu cu tabela ” customer”, foreing key cu
referință la tabela employee, precum și câmpuri pentru statusul comenzii,
categoria acesteia, adresa de livrare, și note suplimentare despre comandă. Prin
constrângerea ”on_delete=models.CASCADE ” ne este asigurat faputl ca dacă un
client este șters, atunci și comanda sa va fi ștearsă.
În ”poll” avem 3 tabele:
•Tabela ”question” are o cheie străină cu referință la tabela User, precum și
câmpuri pentru titlul întrebării, status, data creării, data actualizării, data de start
precum și data până e valabil sondajul.
•Tabela ”choice” are o cheie străină cu referință la tabela question, precum și
câmpuri pentru textul alegerii, data crării și data actualizării.
•Tabela ”answer” are două chei străine, una cu referință către tabela User, iar
cealaltă cu referință către tabela choice. Are de asemenea câmpuri pentru data
creării și data actualizării.
În ”tasks” avem o singură tabelă:
•Tabela ”task”, pe lângă cheia primară implicită, are o cheie străină cu referință la
tabela User, precum și câmpuri pentru enunțul task-ului, data creării, precum și un
câmp de tip boolean pentru verificarea acestuia dacă este sau nu îndeplinit
Constrângerea ”on_delete=models.SET_NULL ” asigură faptul că dacă un task
este șters, atunci userul nu este afectat cu nimic.
u = models.ForeignKey(User, null=True, on_delete= models.SET_NULL)
2.3.1. Diagrama bazei de date. Generarea automată
Putem genera automat diagrama bazei de date folosind pachetul Graph Models, și avem
nevoie de asemenea să instalăm pygraphviz (acesta ne va genera un fișier cu extensia .png) sau
pydot (acesta ne va genera un fișier cu extensia .dot) pentru a genera graful.
$pip install pygraphviz
$pip install pyparsing pydot
Comanda pentru generarea grafului:
$python manage.py graph_models -a -o all_modes.png
15

Emanuel Ursache
16

Capitolul 2. Proiectarea aplicației
2.4. Proiectarea aplicației Django
Într-o aplicație web, interfața grafică poarta un rol esențial. Cu alte cuvinte, aplicația
noastră trebuie sa ofere o interfață ușor de înțeles, intuitivă și sugestivă. Din acest motiv, am
gândit structura acestei aplicații cât mai simplă și mai eficientă pentru utilizatori.
La intrarea în aplicație, utilizatorul (fie el administrator sau curier) va accesa ecranul de
Login, sau eventual cel de Register. În cazul în care se încearcă logarea cu un username sau o
parolă greșită, atunci va fi afișat un mesaj implicit de eroare.
După logarea utilizatorului, avem două cazuri posibile: utilizatorul este administrator sau
este curier. După cum aminteam și în capitolele anterioare, administratorul are utilități diferite
față de un utilizator obișnuit. Drept urmare, vom avea interfețe diferite, atât pentru administrator
cât și pentru curieri.
2.4.1. Interfața pentru administrator
După logare, administratorul are pagina principală împărțită în câteva părți principale:
Prima parte principală o reprezintă bara de navigare. Pe aceasta găsim o serie de butoane:
acasă (spre pagina principală) , statistici (spre pagina de creare a sondajelor, de editare, de
vizualizare și de ștergere a acestora) , și Logout (spre pagina de Login).
La apăsarea butonului Statistici vom fi redirecționați spre o nouă pagină, unde vom găsi
un buton pentru crearea unui nou sondaj, precum și o listă cu sondajele deja creare de către
administrator, listate în ordinea lor cronologică. În dreptul fiecăreia vom observa butoane pentru
vizualizarea, editarea și ștergerea acesteia.
Dacă dorim să facem un nou sondaj, la apăsarea butonului adaugă statistică vom fi
direcționați spre pagina de creare a unei statistici, unde vom găsi niște casete text unde vom
putea introduce enunțul sondajului precum și o serie de opțiuni dintre care curierii vor putea
alege.
O altă parte o reprezintă o secțiune cu patru panouri unde se află o evidență clară a
tuturor comenzilor ( Total comenzi, Comenzi livrate, Comenzi pe drum și Comenzi în așteptare ).
Acestea se actualizează automat la introducerea, editarea sau ștergerea unei comenzi.
17
Figura 2.4: Schema ecranelor Login și Register.

Emanuel Ursache
Jumătatea de jos a structurii paginii acasă o avem împărțită în două. Și anume, partea din
stânga o reprezintă o listă cu toți curierii, iar partea din dreapta, o listă cu toate comenzile.
Se poate vizita profilul oricărui angajat prin apăsarea butonului View. V om fi
redirecționați spre profilul acestuia, unde vom întâlni o serie de facilități menite să simplifice
administratorului munca de management.
În partea de sus vom vedea numele, poza de profil a curierului, date de contact (număr de
telefon și email), precum și un contor cu numărul total de comenzi ale acestuia.
Pe lângă contorul cu numărul total de comenzi, vom avea și o listă cu toate comenzile
respectivului user. Administratorul are posibilitatea de a vizualiza, de a edita și de a șterge orice
comandă a curierului.
În fiecare pagină de profil, administratorul găsește și un filtru de căutare pentru. Acest
filtru de căutare dispune de 7 câmpuri, deci se poate face căutare după:
•client;
•adresa de livrare;
•statusul comenzii;
•categoria coletului;
•note și informații suplimentare despre colet;
•dacă data plasării comenzii mai mare decât o dată dorita;
•dacă data plasării comenzii mai recentă decât o dată dorita;
18
Figura 2.5: Statistici. Structura ecranelor.

Capitolul 2. Proiectarea aplicației
2.4.2. Interfața pentru utilizatori
Un utilizator, față de un administrator, are o altă interfață. În primul rând avem o altă bara
de navigare față de cea pe care o are administratorul:
•acasă
•profil
•statistici / to do
•logout
Pe pagina acasă avem 4 panouri unde se află evidența clara a comenzilor userului, după
statusul fiecărei comenzi ( Total comenzi, Comenzi livrate, Comenzi pe drum, Comenzi în
așteptare). De asemenea, pe această pagina mai găsim filtrul de căutare între comenzi după
aceleași 7 câmpuri ca și în cazul administratorului, precum și lista comenzilor userului, putând
utiliza butoanele de view și update care-i permit vizualizarea și editarea fiecărei comenzi.
Pe pagina profil găsim profilul utilizatorului, unde se află poza acestuia de profil, precum
și informații precum: nume, prenume, adresă de email. Utilizatorul poate modifica aceste
informații, inclusiv poate să-și schimbe poza de profil.
Pagina statistici / to do împărțită în două părți principale. În partea stângă avem lista de
to do, unde utilizatorul poate să-și introducă sarcini, acesta având și două butoane: update și
delete. Fiecare dintre aceste pagini redirecționează utilizatorul către o alta. Cea de update
permite editarea titlului și a statusului, iar cea de delete, ștergerea task-ului.
19
Figura 2.6: Curieri & Comenzi. Structura ecranelor.

Emanuel Ursache
În partea dreaptă a pagini statistici / to do avem o listă cu sondajele create de utilizator.
Fiecare are câte un buton de view care ne redirecționează către altă pagină, unde avem detaliat
sondajul cu opțiunile acestuia. Aici utilizatorul are posibilitatea de a bifa opțiunea dorită, după
care, prin apăsarea butonului vote, iar votul acestuia va fi cuantificat.
20
Figura 2.7: Schema ecranelor pentru utilizatori.

Capitolul 3. Implementarea aplicației
Capitolul 3. Implementarea aplicației
3.1. Crearea și configurarea proiectului
Pentru crearea unui proiect Django, va trebui rulată următoarea comandă:
$ django-admin startproject project_name
După rularea acestei comenzi vom avea un director cu următoarea structură:
project_name/
manage.py
project_name/
__init__.py
settings.py
urls.py
wsgi.py
•project_name/: fișierul ce conține to proiectul.
•mangae.py: ne da accesul la o listă de comenzi foarte utile, inclusiv aceea de
pornire a serverului, de migrații sau de creare a unui superuser.
•project_name/: directorul interior este pachetul Python propriu pentru proiect.
Numele său este numele pachetului Python pe care trebuie să-l folosim pentru a
importa ceva din interiorul său.
•project_name/__init__.py : este necesare pentru a face Python tratarea
directoarelor care conțin fișierul ca pachete. Acest lucru împiedică directoarele cu
un nume comun ascunderea neintenționată a modulelor valide care apar mai târziu
pe calea de căutare a modulului. În cel mai simplu caz, __init__.py poate fi doar
un fișier gol.
•project_name/settings.py : setările / configurările pentru acest proiectul
Django. În interiorul fișierului vom găsi instrucțiuni despre modul în care
funcționează acesta.
•project_name/urls.py : declarațiile URL ale acestui proiect Django; un
„cuprins” al site-ului Diango.
•project_name/wsgi.py : un punct de intrare pentru serverele web compatibile cu
WSGI.
Pentru a rula porni aplicația va trebui să rulăm în linia de comandă comanda [11]:
$ python manage.py runserver
Aceasta rulează implicit pe portul 8000, dar dacă vrem să schimbăm portul, de exemplu
dorim să schimbăm portul pe 8080 vom folosi următoarea comandă:
$ python manage.py runserver 8080
În continuare, vom crea aplicațiile noastre accounts, poll și tasks în același director ca și
fișierul manage.py, astfel încât să poată fi importate ca propriile module de nivel superior, și nu
ca niște submodule ale aplicației principale.
Pentru a crea aplicație, ne asigurăm că ne aflăm în același director ca manage.py și
21

Emanuel Ursache
introducem următoarea comandă:
$ python manage.py startapp app_name
Următorul pas este acela de a crea un superuser (adică un administrator). Avem nevoie de
acest superuser pentru a ne loga pe pagina de admin (disponibilă implicit la orice aplicație
Django la adresa URL http://127.0.0.1:8000/admin/ ) Pentru aceasta va trebui să rulăm
următoarea comandă:
$ python manage.py createsuperuser
3.2. Implementarea bazei de date
Setarea DATABASES din fișierul settings.py configurează o bază de date implicită; poate
fi specificat și orice număr de baze de date suplimentare. Baza noastră de date, de tip SQLite este
configurată folosind următoarele [11]:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
După cum aminteam și în capitolul anterior, vom implementa 7 tabele, informațiile
despre acestea, precum și o schemă le avem detaliate în capitolul respectiv.
După scrierea modelelor în fișierele models.py din interiorul fiecărei aplicații, trebuie sa
edităm fișierul settings.py pentru ca Django să știe că va folosi respectivele modele.
INSTALLED_APPS = [
'channels',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'accounts',
'poll',
'tasks',
'django_filters',
'django_extensions',
]
Migrațiile reprezintă modul Django de a propaga modificările pe care le aducem
modelelor (adăugarea unui câmp, ștergerea unui model etc.) în schema bazei de date. Acestea
sunt proiectate pentru a fi în mare parte automate, dar va trebui să știm când să efectuăm
migrațiile, când să le executăm și care sunt problemele comune cu care le putem confrunta.
22

Capitolul 3. Implementarea aplicației
Următoare comandă are rolul de a sincroniza starea bazei de date cu setul curent de
modele și migrați mod automat.
$ python manage.py migrate
Acestă comandă analizează setarea INSTALLED_APPS și creează tabelele de bază de date
necesare în funcție de setările bazei de date din fișierul licenta/settings.py și migrațiile bazei
de date livrate cu aplicația. V om vedea un mesaj pentru fiecare migrare care se aplică.
$ python manage.py makemigrations accounts
Dacă executăm această comandă după crearea modelelor, în linia de comandă ne va fi
afișat:
Migrations for 'accounts':
accounts/migrations/0001_initial.py
– Create model Customer
– Create model Employee
– Create model Order
Comanda makemigrations produce migrațiile corespunzătoare modificărilor făcute, pe
când comanda migrate aplică acele schimbări bazei de date.
Un rol foarte important În dezvoltarea și managementul bazei de date îl poarta pagina de
administrator oferită implicit de Django. Aceasta oferă o interfață intuitivă pentru adăugarea,
editarea sau ștergerea înregistrărilor în baza de date.
3.2.1. Model Form
Django ModelForm reprezintă o clasă care este utilizată pentru a crea un form HTML
utilizând modelele din baza de date. Este un mod eficient de a crea un form fără a scrie cod
HTML.
Prin aceasta, Django elimină redundanța codului. De exemplu, un model și un form de
înregistrare a utilizatorului ar avea aceeași aceeași cantitate de câmpuri. Așadar, în loc să creăm
un cod redundant pentru a crea mai întâi un form și apoi să-l mapăm cu modelul într-un view,
putem folosi ModelForm direct. Acesta ia ca argument numele modelului și îl transformă într-un
Django form. Nu numai acest lucru, ModelForm oferă o mulțime de metode și funcții care
automatizează întregul proces [12].
De exemplu, modelul Question:
class Question(models.Model):
title = models.TextField(null=True, blank=True)
status = models.CharField(default='inactive', max_length=10)
created_by = models.ForeignKey(User, null=True, blank=True,
on_delete=models.CASCADE)
start_date = models.DateTimeField(null=True, blank=True)
end_date = models.DateTimeField(null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
23

Emanuel Ursache
def __str__(self):
return self.title
Un form creat pentru acest model este:
class PollForm(forms.ModelForm):
title = forms.CharField(max_length=255, label='Question')
class Meta:
model = Question
fields = ['title']
Putem alege ca form-ul nostru să conțină unul, mai multe sau toate câmpurile modelului.
3.2.2. Filter Form
Instalăm Django-filter cu următoarea comandă:
$ pip install django-filter
În acest filtru avem o serie de câmpuri și dorim să permitem utilizatorilor să filtreze
comenzile după mai multe câmpuri.
class OrderFilter(django_filters.FilterSet):
start_date = DateFilter(field_name="date_created", lookup_expr='gte')
end_date = DateFilter(field_name="date_created", lookup_expr='lte')
note = CharFilter(field_name='note', lookup_expr='icontains')
class Meta:
model = Order
fields = '__all__'
exclude = ['employee', 'date_created']
La fel ca în cazul ModelForm, putem înlocui filtrele sau adăuga altele noi folosind o
sintaxă declarativă. Avem toate câmpurile tabelei Order exceptând câmpurile employee și
date_created, plus alte 3 câmpuri suplimnetare pe care le am declarat: start_date, end_date și
note.
orders = employee.order_set.all()
myFilter = OrderFilter(request.GET, queryset=orders)
orders = myFilter.qs
Filtrul nostru primește ca parametrii o cerere, un queryset (o colecție de obiecte din baza
de date, în care se află toate comenzile curierului respectiv), și în funcție de cerea trimisă către
filtru, acesta ne va returna acele comenzile din baza de date datele, care corespund cu cerințele
cererii.
24

Capitolul 3. Implementarea aplicației
3.3. Transmiterea datelor în Template-uri
Un template conține părțile statice ale ieșirii HTML dorite, precum și o sintaxă specială
care descrie modul în care va fi inserat conținut dinamic.
Context reprezintă un dicționar returnat de o funcție. Fiecare element al acestui dicționar
este reprezentat de o pereche formată din numele variabilei ce poartă rol de cheie, și valoarea
variabilei.
În fișierul settings.py avem lista context_processors . Acestea preiau obiecte
HttpRequest și returnează dicționare (similar obiectului Context). Dicționarul (contextul) returnat
de ContextProcessor este contopit în contextul transmis de Django de către utilizator
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'licenta','templates'),
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
Sunt două tipuri de tag-uri pe care le folosim:
•{{ }} acest tag afișează conținut din context-ul returnat de o funcție din view.
•{% %} acest tag poate afișa conținut, poate servi în interiorul său o structură de
control (if, for), sau poate accesa conținut din baza de date
De exemplu, luăm funcția home din accounts/views.py
def home(request):
orders = Order.objects.all()
employees = Employee.objects.all()
total_orders = orders.count()
delivered = orders.filter(status='Livrat').count()
pending = orders.filter(status='In asteptare').count()
road = orders.filter(status='Pe drum').count()
context = {'orders':orders, 'employees':employees,
'total_orders':total_orders,'delivered':delivered,
'pending':pending, 'road':road }
return render(request, 'accounts/dashboard.html', context)
Aceasta primește ca parametru o cerere, și returnează dicționarul creat context către
25

Emanuel Ursache
template-ul accounts/dashboard.html . Acest dicționar preia din baza de date următoarele
informații: toate comenzile, precum cuantificarea acestora statusul, precum și toți angajații.
{% for employee in employees %}
<tr>
<td><a class="btn btn-sm btn-info" href="{% url 'employee' employee.id
%}">View</a></td>
<td>{{employee.name}}</td>
<td>{{employee.phone}}</td>
</tr>
{% endfor %}
{% for order in orders %}
<tr>
<td><a class="btn btn-sm btn-info" href="">View</a></td>
<td>{{order.date_created}}</td>
<td>{{order.status}}</td>
<td><a class="btn btn-sm btn-info" href="{% url 'update_order' order.id
%}">Update</a></td>
<td><a class="btn btn-sm btn-danger" href="{% url 'delete_order'
order.id %}">Delete</a></td>
<td></td>
</tr>
{% endfor %}
Codul de mai sus reprezintă o parte de cod concludent din template-ul
accounts/dashboard.html . Cuvântul cheie render combină un template dat cu un dicționar
context dat și returnează un obiect HttpResponse cu acel text redat.
3.4. Adrese URL
Structura proiectelor Django ce conțin mai multe aplicații ne permite să avem un fișier
urls.py global, unde orice cerere de la browser va fi redirecționată spre un fișier urls.py local
(fiecare aplicație în parte are un asemenea fișier).
from django.contrib import admin
from django.urls import path
from django.conf.urls import include
from django.conf.urls.static import static
from django.conf import settings
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('accounts.urls')),
path('chat/', include('chat.urls')),
path('poll/', include('poll.urls')),
path('tasks/', include('tasks.urls')),
26

Capitolul 3. Implementarea aplicației
]
Avem două tipuri de adrese URL: statice și dinamice. Cele statice au următoarea
structură:
path('register/', views.registerPage, name="register"),
Path-ul reprezintă adresa url spre pagina de înregistrare a userilor. Prin
views.registerPage atribuim un view (o funcție) nuimit registerPage adresei URL, iar
name="register" numele adresei URL ce va fi folosit pentru a identifica un nume.
Adresele URL dinamice au următoarea structură:
path('update_order/<str:pk>/', views.updateOrder, name="update_order"),
Spre deosebire de cele statice, adresele URL dinamice au în plus o cheie primară ce
reprezintă un id (în exemplul dat reprezintă id-ul comenzii ce va trebui modificată), deci în
funcție de id-ul trimis avem content diferit în același template. Distingem în antetul funcțiilor ce
redirecționează un dicționar context spre un asemenea template, încă un parametru pentru cheia
primară, pe lângă parametru request.
def updateOrder(request, pk):
De asemenea și butoanele de navigare precum și cele pentru anumite funcționalități au în
spate aceste adrese. La apăsarea unui buton vom fi redirecționați spre pagina sau spre
funcționalitatea dorită.
<a class="btn btn-sm btn-info" href="{% url 'employee' employee.id %}">View</a>
path('employee/<str:pk_test>/', views.employee, name="employee"),
În acest mod, în Django se creează o cale, în cazul nostru spre pagina de profil a unui
angajat. În această sintaxă avem: ' employee' este numele adresei URL din accounts/urls.py
(cea de mai sus), iar employee.id reprezintă id-ul angajatului a cărui pagină dorim să o accesăm.
Un avantaj foarte mare al acestei sintaxe este acela că dacă schimbăm în vreunfel numele
”employee/<str:pk_test>/ ”, atunci nu va trebui moficat niciun link din template care face
referire spre această adresă URL deoarece ea este identificată după name="employee".
3.5. Autentificare și înregistrarea useri-lor
Framework-ul Django oferă un form numit UserCreationForm (care se moștenește din
clasa ModelForm) pentru a gestiona crearea de noi utilizatori. Noi vom extinde din acesta un
form propriu (funcționează la fel ca și UserCreationForm ) pentru a-i putea customiza câmpurile.
class CreateUserForm(UserCreationForm):
class Meta:
model = User
fields = ['username', 'email', 'password1', 'password2']
Aceasta este funcția din view.py pentru înregistrarea unui nou user:
27

Emanuel Ursache
form django.contrib.auth.forms import CreateUserForm
def registerPage(request):
form = CreateUserForm()
if request.method == 'POST':
form = CreateUserForm(request.POST)
if form.is_valid():
user = form.save()
username = form.cleaned_data.get('username')
group = Group.objects.get(name='employee')
user.groups.add(group)
Employee.objects.create(
user=user,
name=user.username,
)
messages.success(request, 'Contul a fost creat pentru ' + username)
return redirect('login')
context = {'form':form}
return render(request, 'accounts/register.html', context)
Această funcție primește ca parametru o cerere și salvează un user cu informațiile
introduse în form = CreateUserForm(request.POST) . Este creat de asemenea și un obiect de
tip Employee ce reprezintă practic același user.
def loginPage(request):
if request.method == 'POST':
username = request.POST.get('username')
password =request.POST.get('password')
user = authenticate(request, username=username, password=password)
print(request.POST)
if user is not None:
login(request, user)
return redirect('home')
else:
messages.info(request, 'Username OR password is incorrect')
context = {}
return render(request, 'accounts/login.html', context)
Pentru a autentifica un user, utilizăm authenticate(). Este nevoie de două argumente
username și password și returnează un obiect user dacă parola este valabilă pentru numele de
utilizator dat. Dacă parola nu este validă, authenticate() returnează None. Funcția login() ia
un obiect HttpRequest și un obiect User. Și salvează ID-ul utilizatorului în sesiune, folosind
28

Capitolul 3. Implementarea aplicației
Django's session framework .
3.5.1. Decoratori Django
Un decorator este un design patterns. Este un mod de modificare aparentă a
comportamentului unui obiect, înglobându-l în interiorul unui obiect de tip decorator cu o
interfață similară. Decoratorii modifică în mod dinamic funcționalitatea unei funcții, metode sau
clase, fără a fi nevoie să facă subclase sau să schimbe codul sursă al clasei decorate. Datorită
acestui fapt, codul nostru va fi mai curat, mai lizibil, mai ușor de întreținut [13].
Decoratorul login_required verifică dacă un utilizator este logat, în caz contrar îl
redirecționează pe acesta că adresa URL de autentificare.
from django.contrib.auth.decorators import login_required
@login_required(login_url='login')
Pe lângă decoratorii standard, putem construi proprii decoratori, în fișierul
decorators.py.
def unauthenticated_user(view_func):
def wrapper_func(request, *args, **kwargs):
if request.user.is_authenticated:
return redirect('home')
else:
return view_func(request, *args, **kwargs)
return wrapper_func
Acest decorator nu lasă un user logat să acceseze o anume adresă URL. În cazul nostru.
Nu dorim ca un user logat să poată accesa adresele URL de logare și înregistrare.
Următorii decoratori îi folosim pentru a permite sau nu unui utilizator să acceseze
anumite adrese URL, în funcție de grupul din care face parte userul.
Django ne oferă implicit o clasă ce se numește Groups, ce ne permite să distingem userii
prin niște grupuri create de noi. Așadar, avem un grup numit admins și unul employee. În funcție
de apartenența la unul din aceste grupuri, și cu decoratorilor creați, vom impune restricții în ceea
ce privește accesarea adreselor URL de către useri.
def allowed_users(allowed_roles=[]):
def decorator(view_func):
def wrapper_func(request, *args, **kwargs):
group = None
if request.user.groups.exists():
group = request.user.groups.all()[0].name
if group in allowed_roles:
return view_func(request, *args, **kwargs)
else:
return HttpResponse('Nu ai permisiunea sa accesezi aceasta
pagina')
return wrapper_func
29

Emanuel Ursache
return decorator
3.6. Interfața cu utilizatorul
În ceea ce privește interfața grafică, am respectat schemele de design prezentate în
capitolul de proiectare a aplicației.
La rularea aplicației, aveam disponibile paginile de logare și de înregistrare.

Pe pagina principală, interfața pentru administrator prezintă cele patru panouri în care se
ține evidența clară a comenzilor după statusul acestora (numărul total de comenzi, comenzile
livrate, comenzile pe drum, și cele în așteptare)
30
Figura 3.1: Pagina de logare.
Figura 3.2: Pagina de înregistrare.

Capitolul 3. Implementarea aplicației
În partea stângă jos putem observa lista cu curierii, și butoanele de view către paginile de
profil ale fiecăruia dintre ei.
Aici regăsim în partea de sus poza de profil, informațiile și numărul total de comenzi ale
angajatului respectiv. Pe lângă asta, mai găsim filtrul de căutare în comenzile acestuia, precum și
lista coletelor, cu butoane către paginile de view, update și delete.
În partea dreaptă jos pagini principale găsim lista cu toate comenzile, cu butoane către
paginile de view, update și delete, precum și un buton ce ne redirecționează pe pagina de creare a
unei noi comenzi. Pagina de creare a unei noi comenzi este formată din nou părți. În partea
dreaptă introducem informațiile clientului care trimite coletul, iar în partea dreaptă informații
despre colet
31
Figura 3.3: Pagina principală. Interfața administratorului.
Figura 3.4: Pagina de vizitare a profilului unui angajat.

Emanuel Ursache
În pagina Statistici găsim lista cu sondajele create de către utilizator, cu butoane către
paginile de vizualizare, editare și ștergere ale acestora.
Pe lângă asta avem un buton de creare a unei noi statistici.
32
Figura 3.5: Pagina de inserare a unei noi comenzi.
Figura 3.6: Pagina Statistici.
Figura 3.7: Pagina de crearea a unui nou sondaj.

Capitolul 3. Implementarea aplicației
Aici avem câmpuri pentru enunțul sondajului cât și pentru opțiunile dintre care pot alege
angajații.
În cazul în care utilizatorul care se loghează este un simplu user, pe pagina principală
găsim cele patru panouri în care se ține evidența clară a comenzilor sale după statusul acestora,
în partea stânga jos găsim filtrul de căutare în comenzile sale după câmpurile anterior
specificate, iar în partea dreaptă, lista cu comenzile acestuia, cu butoane către paginile de
vizualizare și respectiv actualizare.
Pagina de profil a unui curier este constituită din informațiile acestuia: nume, număr de
telefon, email și poză de profil. Utilizatorul își poate edita aceste informații după bunul plac.
Pagina Statistics/ToDo este formată din două părți.
Partea din stânga o reprezintă lista de sarcini personale ale curierului, pe care acesta și le
propune. Curierul poate șterge oricare sarcină, îi poate edita enunțul sau o poate bifa ca și
îndeplinită.
33
Figura 3.8: Pagina principală. Interfața curierului.
Figura 3.9: Pagina de profil a curierului.

Emanuel Ursache
Partea dreaptă este reprezentată de lista sondajelor create de către administrator.
Utilizatorul poate vota (bifa) opțiunea dorită.
34
Figura 3.10: Pagina Statistici/ToDo.
Figura 3.11: Pagina de votare a sondajelor.

Capitolul 4. Testarea aplicației
Capitolul 4. Testarea aplicației
Pentru testarea cererilor HTTP efectuate din browser am folosit extensia YARC pentru
Google Chrome. YARC reprezintă abrevierea de la Yet Another REST Client și este, un client
pentru efectuarea de request-uri. Acesta este gratis, ușor de utilizat, și suportă toate tipurile de
cereri HTTP, răspunsul cererilor este afișat într-un format înfrumusețat și măsoară timpul necesar
ca o cerere ca să fie executată [14].
Pentru a testa un request, este nevoie să introducem adresa URL, și tipul cererii, după
care apăsăm butonul Send Request.
Aceste informații ne sunt afișate și în linia de comandă, la executarea fiecărei cereri.
Putem vedea din Figura 4.2 de mai sus, cum o cerere de logare durează 61 de
milisecunde1, iar plasarea unei noi comenzi 24 de milisecunde.
11 Secundă = 103 Milisecunde
35
Figura 4.1: Testarea unui request utilizând extensia YARC.
Figura 4.2: Date preluate din linia de comandă referitoare la performanțele cererilor.
Figura 4.3: Date preluate din linia de comandă referitoare la performanțele cererilor.

Emanuel Ursache
În Figura 4.3 putem observa, în cazul unui curier, că un request POST pentru plasarea
unui nou task în lista personală de ToDo durează 23 de milisecunde, iar ștergerea ei durează 11
milisecunde.
Spre deosebire de YARC, în linia de comandă ne sunt afișate absolut toate cererile trimise
în timp ce folosim aplicația, cu tipul, durata și codul HTTP aferent, în timp ce, extensia YARC ne
oferă posibilitatea de a testa pe rând câte un request prin adresa URL.
Testare aplicației s-a realizat pe mai multe browsere (Google Chrome, Internet Explorer,
Mozila FireFox și Opera) și s-a dovedit a fi rapidă și funcțională.
36

Concluzii
Concluzii
Prin dezvoltarea acestui proiect de licență am urmărit încă de la început să învăț lucruri
noi, drept urmare am ales, din pură curiozitate, să folosesc un framework nou pentru mine, ceea
ce a reprezentat principala provocare.
Rezultatul final a venit cu ceva modificări față de ideea inițială, pe care am dezvoltat-o în
faza incipientă a acestui proiect, prin adăugarea și scoaterea unor funcționalități.
Ca și viitoare direcții de dezvoltare pentru îmbunătățirea aplicației am luat în considerare
următoarele îmbunătățiri:
•În primul rând, implementarea chat-ului pentru a facilita comunicarea între
personalul firmei.
•Posibilitatea ca administratorul să gestioneze crearea conturilor, aceasta făcându-
se doar în cazul unei noi persoane angajate, pe baza unui link primit de angajat de
la angajator.
•Crearea unei interfețe pentru clienți astfel încât un client să poată introduce singur
o comandă în genul celei introduse de către administrator.
•Posibilitatea ca administratorul să poată plasa task-uri curierilor în lista fiecăruia
de ToDo.
•Implementarea unei versiuni a aplicației pentru telefonul mobil.
•Implementarea unei hărți pentru curieri, în care să fie introduse automat adresa de
ridicare a coletului cât și cea de livrare, cât și un traseu optim.
În concluzie, crearea acestui proiect a reprezentat o provocare continuă, de la faza de
concept, până la implementare și redactarea documentației aferente, și, totodată, o oportunitate
de a aplica cunoștințele asimilate pe durata celor patru ani de studiu, într-un proiect mai amplu
decât cele cu care am avut de-a face până acum.
37

Emanuel Ursache
Bibliografie
[1], Evoluția Managementului [Online], Disponibil la adresa:
http://www.mpt.upt.ro/doc/curs/gp/Bazele_Managementului/Evolutia_managementului_cap1.pdf,
Accesat: 2020.
[2]Matt Makai, [Online], Disponibil la adresa: https://www.fullstackpython.com/sublime-text.html,
Accesat: 2020.
[3]MDN contributors, Django introduction [Online], Disponibil la adresa:
https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Introduction, Accesat: 2020.
[4]SQLite Consortium members, SQLite [Online], Disponibil la adresa:
https://www.sqlite.org/docs.html, Accesat: 2020.
[5]SQLite Consortium members, SQLite about [Online], Disponibil la adresa:
https://www.sqlite.org/about.html, Accesat: 2020.
[6]Valentin Clocotici, Istoria HTML [Online], Disponibil la adresa:
https://profs.info.uaic.ro/~val/istoric.html, Accesat: 2020.
[7]MDN contributors, about HTML [Online], Disponibil la adresa: https://developer.mozilla.org/en-
US/docs/Web/HTML, Accesat: 2020.
[8]MDN contributors, CSS [Online], Disponibil la adresa:
https://developer.mozilla.org/en-US/docs/Web/CSS, Accesat: 2020.
[9]Dan Neamțu, Ce este Bootstrap și cum te poate ajuta în dezvoltarea de site-uri web moderne
[Online], Disponibil la adresa: https://ctrl-d.ro/tutoriale/ce-este-bootstrap-si-cum-te-poate-ajuta-in-
dezvoltarea-de-site-uri-web-moderne/, Accesat: 2020.
[10]Matt Makai, WSGI [Online], Disponibil la adresa: https://www.fullstackpython.com/wsgi-
servers.html, Accesat: 2020.
[11]Django Software Foundation, Django Tutorial [Online], Disponibil la adresa:
https://docs.djangoproject.com/en/3.1/intro/tutorial02/, Accesat: 2020.
[12]Geeksforgeeks Team, Django model form [Online], Disponibil la adresa:
https://www.geeksforgeeks.org/django-modelform-create-form-from-models/, Accesat: 2020.
[13]Vitor Freitas, Django decorators [Online], Disponibil la adresa:
https://simpleisbetterthancomplex.com/2015/12/07/working-with-django-view-decorators.html,
Accesat: 2020.
[14]Paul Hitz, YARC [Online], Disponibil la adresa: https://github.com/paulhitz/yet-another-rest-client,
Accesat: 2020.
38

Anexe.
Anexe.
Anexa 1. Codul din fișierul all_models.dot generat pentru crearea diagramei
bazei de date
digraph model_graph {
// Dotfile by Django-Extensions graph_models
// Created: 2020-08-21 01:27
// Cli Options: -a -g -o all_models.dot
fontname = "Roboto"
fontsize = 8
splines = true
node [
fontname = "Roboto"
fontsize = 8
shape = "plaintext"
]
edge [
fontname = "Roboto"
fontsize = 8
]
// Labels
subgraph cluster_poll {
label=<
<TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0">
<TR><TD COLSPAN="2" CELLPADDING="4" ALIGN="CENTER">
<FONT FACE="Roboto" COLOR="Black" POINT-SIZE="10">
<B>poll</B>
</FONT>
</TD></TR>
</TABLE>
>
color=olivedrab4
style="rounded"

poll_models_Question [label=<
<TABLE BGCOLOR="white" BORDER="1" CELLBORDER="0" CELLSPACING="0">
<TR><TD COLSPAN="2" CELLPADDING="5" ALIGN="CENTER" BGCOLOR="#1b563f">
<FONT FACE="Roboto" COLOR="white" POINT-SIZE="10"><B>
Question
</B></FONT></TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto"><B>id</B></FONT>
</TD><TD ALIGN="LEFT">
39

Emanuel Ursache
<FONT FACE="Roboto"><B>AutoField</B></FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT COLOR="#7B7B7B" FACE="Roboto"><B>created_by</B></FONT>
</TD><TD ALIGN="LEFT">
<FONT COLOR="#7B7B7B" FACE="Roboto"><B>ForeignKey (id)</B></FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT COLOR="#7B7B7B" FACE="Roboto">created_at</FONT>
</TD><TD ALIGN="LEFT">
<FONT COLOR="#7B7B7B" FACE="Roboto">DateTimeField</FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT COLOR="#7B7B7B" FACE="Roboto">end_date</FONT>
</TD><TD ALIGN="LEFT">
<FONT COLOR="#7B7B7B" FACE="Roboto">DateTimeField</FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT COLOR="#7B7B7B" FACE="Roboto">start_date</FONT>
</TD><TD ALIGN="LEFT">
<FONT COLOR="#7B7B7B" FACE="Roboto">DateTimeField</FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto">status</FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto">CharField</FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT COLOR="#7B7B7B" FACE="Roboto">title</FONT>
</TD><TD ALIGN="LEFT">
<FONT COLOR="#7B7B7B" FACE="Roboto">TextField</FONT>
</TD></TR>

40

Anexe.

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT COLOR="#7B7B7B" FACE="Roboto">updated_at</FONT>
</TD><TD ALIGN="LEFT">
<FONT COLOR="#7B7B7B" FACE="Roboto">DateTimeField</FONT>
</TD></TR>

</TABLE>
>]

poll_models_Choice [label=<
<TABLE BGCOLOR="white" BORDER="1" CELLBORDER="0" CELLSPACING="0">
<TR><TD COLSPAN="2" CELLPADDING="5" ALIGN="CENTER" BGCOLOR="#1b563f">
<FONT FACE="Roboto" COLOR="white" POINT-SIZE="10"><B>
Choice
</B></FONT></TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto"><B>id</B></FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto"><B>AutoField</B></FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto"><B>q</B></FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto"><B>ForeignKey (id)</B></FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT COLOR="#7B7B7B" FACE="Roboto">created_at</FONT>
</TD><TD ALIGN="LEFT">
<FONT COLOR="#7B7B7B" FACE="Roboto">DateTimeField</FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT COLOR="#7B7B7B" FACE="Roboto">text</FONT>
</TD><TD ALIGN="LEFT">
<FONT COLOR="#7B7B7B" FACE="Roboto">TextField</FONT>
</TD></TR>

41

Emanuel Ursache

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT COLOR="#7B7B7B" FACE="Roboto">updated_at</FONT>
</TD><TD ALIGN="LEFT">
<FONT COLOR="#7B7B7B" FACE="Roboto">DateTimeField</FONT>
</TD></TR>

</TABLE>
>]

poll_models_Answer [label=<
<TABLE BGCOLOR="white" BORDER="1" CELLBORDER="0" CELLSPACING="0">
<TR><TD COLSPAN="2" CELLPADDING="5" ALIGN="CENTER" BGCOLOR="#1b563f">
<FONT FACE="Roboto" COLOR="white" POINT-SIZE="10"><B>
Answer
</B></FONT></TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto"><B>id</B></FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto"><B>AutoField</B></FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto"><B>ch</B></FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto"><B>ForeignKey (id)</B></FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto"><B>u</B></FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto"><B>ForeignKey (id)</B></FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT COLOR="#7B7B7B" FACE="Roboto">created_at</FONT>
</TD><TD ALIGN="LEFT">
<FONT COLOR="#7B7B7B" FACE="Roboto">DateTimeField</FONT>
</TD></TR>

42

Anexe.
<TR><TD ALIGN="LEFT" BORDER="0">
<FONT COLOR="#7B7B7B" FACE="Roboto">updated_at</FONT>
</TD><TD ALIGN="LEFT">
<FONT COLOR="#7B7B7B" FACE="Roboto">DateTimeField</FONT>
</TD></TR>

</TABLE>
>]
}
subgraph cluster_tasks {
label=<
<TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0">
<TR><TD COLSPAN="2" CELLPADDING="4" ALIGN="CENTER">
<FONT FACE="Roboto" COLOR="Black" POINT-SIZE="10">
<B>tasks</B>
</FONT>
</TD></TR>
</TABLE>
>
color=olivedrab4
style="rounded"

tasks_models_Task [label=<
<TABLE BGCOLOR="white" BORDER="1" CELLBORDER="0" CELLSPACING="0">
<TR><TD COLSPAN="2" CELLPADDING="5" ALIGN="CENTER" BGCOLOR="#1b563f">
<FONT FACE="Roboto" COLOR="white" POINT-SIZE="10"><B>
Task
</B></FONT></TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto"><B>id</B></FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto"><B>AutoField</B></FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto"><B>u</B></FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto"><B>ForeignKey (id)</B></FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto">complete</FONT>
</TD><TD ALIGN="LEFT">
43

Emanuel Ursache
<FONT FACE="Roboto">BooleanField</FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT COLOR="#7B7B7B" FACE="Roboto">created</FONT>
</TD><TD ALIGN="LEFT">
<FONT COLOR="#7B7B7B" FACE="Roboto">DateTimeField</FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto">title</FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto">CharField</FONT>
</TD></TR>

</TABLE>
>]
}
subgraph cluster_django_contrib_admin {
label=<
<TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0">
<TR><TD COLSPAN="2" CELLPADDING="4" ALIGN="CENTER">
<FONT FACE="Roboto" COLOR="Black" POINT-SIZE="10">
<B>django.contrib.admin</B>
</FONT>
</TD></TR>
</TABLE>
>
color=olivedrab4
style="rounded"

django_contrib_admin_models_LogEntry [label=<
<TABLE BGCOLOR="white" BORDER="1" CELLBORDER="0" CELLSPACING="0">
<TR><TD COLSPAN="2" CELLPADDING="5" ALIGN="CENTER" BGCOLOR="#1b563f">
<FONT FACE="Roboto" COLOR="white" POINT-SIZE="10"><B>
LogEntry
</B></FONT></TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto"><B>id</B></FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto"><B>AutoField</B></FONT>
</TD></TR>

44

Anexe.

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT COLOR="#7B7B7B" FACE="Roboto"><B>content_type</B></FONT>
</TD><TD ALIGN="LEFT">
<FONT COLOR="#7B7B7B" FACE="Roboto"><B>ForeignKey (id)</B></FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto"><B>user</B></FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto"><B>ForeignKey (id)</B></FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto">action_flag</FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto">PositiveSmallIntegerField</FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto">action_time</FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto">DateTimeField</FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT COLOR="#7B7B7B" FACE="Roboto">change_message</FONT>
</TD><TD ALIGN="LEFT">
<FONT COLOR="#7B7B7B" FACE="Roboto">TextField</FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT COLOR="#7B7B7B" FACE="Roboto">object_id</FONT>
</TD><TD ALIGN="LEFT">
<FONT COLOR="#7B7B7B" FACE="Roboto">TextField</FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
45

Emanuel Ursache
<FONT FACE="Roboto">object_repr</FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto">CharField</FONT>
</TD></TR>

</TABLE>
>]
}
subgraph cluster_django_contrib_auth {
label=<
<TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0">
<TR><TD COLSPAN="2" CELLPADDING="4" ALIGN="CENTER">
<FONT FACE="Roboto" COLOR="Black" POINT-SIZE="10">
<B>django.contrib.auth</B>
</FONT>
</TD></TR>
</TABLE>
>
color=olivedrab4
style="rounded"

django_contrib_auth_models_Permission [label=<
<TABLE BGCOLOR="white" BORDER="1" CELLBORDER="0" CELLSPACING="0">
<TR><TD COLSPAN="2" CELLPADDING="5" ALIGN="CENTER" BGCOLOR="#1b563f">
<FONT FACE="Roboto" COLOR="white" POINT-SIZE="10"><B>
Permission
</B></FONT></TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto"><B>id</B></FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto"><B>AutoField</B></FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto"><B>content_type</B></FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto"><B>ForeignKey (id)</B></FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto">codename</FONT>
</TD><TD ALIGN="LEFT">
46

Anexe.
<FONT FACE="Roboto">CharField</FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto">name</FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto">CharField</FONT>
</TD></TR>

</TABLE>
>]

django_contrib_auth_models_Group [label=<
<TABLE BGCOLOR="white" BORDER="1" CELLBORDER="0" CELLSPACING="0">
<TR><TD COLSPAN="2" CELLPADDING="5" ALIGN="CENTER" BGCOLOR="#1b563f">
<FONT FACE="Roboto" COLOR="white" POINT-SIZE="10"><B>
Group
</B></FONT></TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto"><B>id</B></FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto"><B>AutoField</B></FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto">name</FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto">CharField</FONT>
</TD></TR>

</TABLE>
>]

django_contrib_auth_models_User [label=<
<TABLE BGCOLOR="white" BORDER="1" CELLBORDER="0" CELLSPACING="0">
<TR><TD COLSPAN="2" CELLPADDING="5" ALIGN="CENTER" BGCOLOR="#1b563f">
<FONT FACE="Roboto" COLOR="white" POINT-SIZE="10"><B>
User<BR/>
</B></FONT></TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto"><B>id</B></FONT>
47

Emanuel Ursache
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto"><B>AutoField</B></FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto"><I>date_joined</I></FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto"><I>DateTimeField</I></FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT COLOR="#7B7B7B" FACE="Roboto"><I>email</I></FONT>
</TD><TD ALIGN="LEFT">
<FONT COLOR="#7B7B7B" FACE="Roboto"><I>EmailField</I></FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT COLOR="#7B7B7B" FACE="Roboto"><I>first_name</I></FONT>
</TD><TD ALIGN="LEFT">
<FONT COLOR="#7B7B7B" FACE="Roboto"><I>CharField</I></FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto"><I>is_active</I></FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto"><I>BooleanField</I></FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto"><I>is_staff</I></FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto"><I>BooleanField</I></FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto"><I>is_superuser</I></FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto"><I>BooleanField</I></FONT>
</TD></TR>
48

Anexe.

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT COLOR="#7B7B7B" FACE="Roboto"><I>last_login</I></FONT>
</TD><TD ALIGN="LEFT">
<FONT COLOR="#7B7B7B" FACE="Roboto"><I>DateTimeField</I></FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT COLOR="#7B7B7B" FACE="Roboto"><I>last_name</I></FONT>
</TD><TD ALIGN="LEFT">
<FONT COLOR="#7B7B7B" FACE="Roboto"><I>CharField</I></FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto"><I>password</I></FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto"><I>CharField</I></FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto"><I>username</I></FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto"><I>CharField</I></FONT>
</TD></TR>

</TABLE>
>]
}
subgraph cluster_django_contrib_contenttypes {
label=<
<TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0">
<TR><TD COLSPAN="2" CELLPADDING="4" ALIGN="CENTER">
<FONT FACE="Roboto" COLOR="Black" POINT-SIZE="10">
<B>django.contrib.contenttypes</B>
</FONT>
</TD></TR>
</TABLE>
>
color=olivedrab4
style="rounded"

49

Emanuel Ursache
django_contrib_contenttypes_models_ContentType [label=<
<TABLE BGCOLOR="white" BORDER="1" CELLBORDER="0" CELLSPACING="0">
<TR><TD COLSPAN="2" CELLPADDING="5" ALIGN="CENTER" BGCOLOR="#1b563f">
<FONT FACE="Roboto" COLOR="white" POINT-SIZE="10"><B>
ContentType
</B></FONT></TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto"><B>id</B></FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto"><B>AutoField</B></FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto">app_label</FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto">CharField</FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto">model</FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto">CharField</FONT>
</TD></TR>

</TABLE>
>]
}
subgraph cluster_django_contrib_sessions {
label=<
<TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0">
<TR><TD COLSPAN="2" CELLPADDING="4" ALIGN="CENTER">
<FONT FACE="Roboto" COLOR="Black" POINT-SIZE="10">
<B>django.contrib.sessions</B>
</FONT>
</TD></TR>
</TABLE>
>
color=olivedrab4
style="rounded"

}
50

Anexe.
subgraph cluster_accounts {
label=<
<TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0">
<TR><TD COLSPAN="2" CELLPADDING="4" ALIGN="CENTER">
<FONT FACE="Roboto" COLOR="Black" POINT-SIZE="10">
<B>accounts</B>
</FONT>
</TD></TR>
</TABLE>
>
color=olivedrab4
style="rounded"

accounts_models_Customer [label=<
<TABLE BGCOLOR="white" BORDER="1" CELLBORDER="0" CELLSPACING="0">
<TR><TD COLSPAN="2" CELLPADDING="5" ALIGN="CENTER" BGCOLOR="#1b563f">
<FONT FACE="Roboto" COLOR="white" POINT-SIZE="10"><B>
Customer
</B></FONT></TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto"><B>id</B></FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto"><B>AutoField</B></FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto">address</FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto">CharField</FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT COLOR="#7B7B7B" FACE="Roboto">date_created</FONT>
</TD><TD ALIGN="LEFT">
<FONT COLOR="#7B7B7B" FACE="Roboto">DateTimeField</FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto">email</FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto">CharField</FONT>
</TD></TR>

51

Emanuel Ursache

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto">name</FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto">CharField</FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto">phone</FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto">CharField</FONT>
</TD></TR>

</TABLE>
>]

accounts_models_Employee [label=<
<TABLE BGCOLOR="white" BORDER="1" CELLBORDER="0" CELLSPACING="0">
<TR><TD COLSPAN="2" CELLPADDING="5" ALIGN="CENTER" BGCOLOR="#1b563f">
<FONT FACE="Roboto" COLOR="white" POINT-SIZE="10"><B>
Employee
</B></FONT></TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto"><B>id</B></FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto"><B>AutoField</B></FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT COLOR="#7B7B7B" FACE="Roboto"><B>user</B></FONT>
</TD><TD ALIGN="LEFT">
<FONT COLOR="#7B7B7B" FACE="Roboto"><B>OneToOneField (id)</B></FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT COLOR="#7B7B7B" FACE="Roboto">date_created</FONT>
</TD><TD ALIGN="LEFT">
<FONT COLOR="#7B7B7B" FACE="Roboto">DateTimeField</FONT>
</TD></TR>

52

Anexe.

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto">email</FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto">CharField</FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto">name</FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto">CharField</FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto">phone</FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto">CharField</FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT COLOR="#7B7B7B" FACE="Roboto">profile_pic</FONT>
</TD><TD ALIGN="LEFT">
<FONT COLOR="#7B7B7B" FACE="Roboto">ImageField</FONT>
</TD></TR>

</TABLE>
>]

accounts_models_Order [label=<
<TABLE BGCOLOR="white" BORDER="1" CELLBORDER="0" CELLSPACING="0">
<TR><TD COLSPAN="2" CELLPADDING="5" ALIGN="CENTER" BGCOLOR="#1b563f">
<FONT FACE="Roboto" COLOR="white" POINT-SIZE="10"><B>
Order
</B></FONT></TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto"><B>id</B></FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto"><B>AutoField</B></FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT COLOR="#7B7B7B" FACE="Roboto"><B>customer</B></FONT>
</TD><TD ALIGN="LEFT">
53

Emanuel Ursache
<FONT COLOR="#7B7B7B" FACE="Roboto"><B>OneToOneField (id)</B></FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto"><B>employee</B></FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto"><B>ForeignKey (id)</B></FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto">category</FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto">CharField</FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT COLOR="#7B7B7B" FACE="Roboto">date_created</FONT>
</TD><TD ALIGN="LEFT">
<FONT COLOR="#7B7B7B" FACE="Roboto">DateTimeField</FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto">delivery_address</FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto">CharField</FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto">note</FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto">CharField</FONT>
</TD></TR>

<TR><TD ALIGN="LEFT" BORDER="0">
<FONT FACE="Roboto">status</FONT>
</TD><TD ALIGN="LEFT">
<FONT FACE="Roboto">CharField</FONT>
</TD></TR>

</TABLE>
>]
}
// Relations
54

Anexe.
poll_models_Question -> django_contrib_auth_models_User
[label=" created_by (question)"] [arrowhead=none, arrowtail=dot, dir=both];
poll_models_Choice -> poll_models_Question
[label=" q (choice)"] [arrowhead=none, arrowtail=dot, dir=both];
poll_models_Answer -> django_contrib_auth_models_User
[label=" u (answer)"] [arrowhead=none, arrowtail=dot, dir=both];
poll_models_Answer -> poll_models_Choice
[label=" ch (answer)"] [arrowhead=none, arrowtail=dot, dir=both];
tasks_models_Task -> django_contrib_auth_models_User
[label=" u (task)"] [arrowhead=none, arrowtail=dot, dir=both];
django_contrib_admin_models_LogEntry -> django_contrib_auth_models_User
[label=" user (logentry)"] [arrowhead=none, arrowtail=dot, dir=both];
django_contrib_admin_models_LogEntry ->
django_contrib_contenttypes_models_ContentType
[label=" content_type (logentry)"] [arrowhead=none, arrowtail=dot, dir=both];
django_contrib_auth_models_Permission ->
django_contrib_contenttypes_models_ContentType
[label=" content_type (permission)"] [arrowhead=none, arrowtail=dot, dir=both];
django_contrib_auth_models_Group -> django_contrib_auth_models_Permission
[label=" permissions (group)"] [arrowhead=dot arrowtail=dot, dir=both];
django_contrib_auth_models_User -> django_contrib_auth_models_Group
[label=" groups (user)"] [arrowhead=dot arrowtail=dot, dir=both];
django_contrib_auth_models_User -> django_contrib_auth_models_Permission
[label=" user_permissions (user)"] [arrowhead=dot arrowtail=dot, dir=both];
accounts_models_Employee -> django_contrib_auth_models_User
[label=" user (employee)"] [arrowhead=none, arrowtail=none, dir=both];
accounts_models_Order -> accounts_models_Customer
[label=" customer (order)"] [arrowhead=none, arrowtail=none, dir=both];
accounts_models_Order -> accounts_models_Employee
[label=" employee (order)"] [arrowhead=none, arrowtail=dot, dir=both];
}
55

Similar Posts