Differences between revisions 1 and 35 (spanning 34 versions)
Revision 1 as of 2009-03-10 12:24:52
Size: 39
Editor: dial-92-52-21-192-orange
Comment:
Revision 35 as of 2009-03-10 20:54:20
Size: 9152
Editor: dial-92-52-21-192-orange
Comment:
Deletions are marked like this. Additions are marked like this.
Line 2: Line 2:

Django umožňuje pracovať s relačnou databázou pomocou objektovo-relačného
modelu. Robí to pomocou techniky menom ''objektovo-relačné mapovanie'' (ORM).
Z praktického hľadiska táto technika slúži na izolovanie programátora aplikácie
od databázového servra, Je možné začať vyvíjať aplikáciu lokálne pod sqlite a
v reálnom nasadení potom použiť povedzme Oracle, pričom jediná zmena je v {{{settings.py}}}.
Programátor sa nemusí zaoberať {{{SQL}}}, stačí mu vedieť python.

Nevýhoda tejto techniky je v tom, že neumožňuje účinne používať mnohé techniky určené
pre zvýšenie výkonnosti databázového servra (triggery a pod.). Primárnym účelom
djanga je vytvárať dynamické webové stránky, ale napríklad veľká aplikácia
ako napríklad http://is.stuba.sk vyžaduje trochu zložitejší návrh databázovej schémy,
než to umožňuje django.

== Vytvorenie modelu ==

Vytvorme si nový projekt s názvom {{{skola}}} a v ňom aplikáciu s názvom {{{ziacka}}}.

Ideme implementovať dátový model žiackej knižky naivným (a pre tento účel nesprávnym) spôsobom:
ako jednu veľkú tabuľku s mnohými stĺpcami. Nesmieme zabudnúť doplniť aplikáciu v {{{settings.py}}}.

V adresári ziacka máme súbor {{{models.py}}}, ktorý vyzerá takto:

{{attachment:models.py}}

Napíšme teraz
{{{
$ ./manage.py syncdb
}}}
a všimnime si, že vo výpise máme takýto riadok
{{{
Creating table ziacka_znamka
}}}
Pre zaujímavosť sa môžeme pozrieť, aké SQL príkazy boli použité na vytvorenie tabuľky.
{{{
$ ./manage.py sqlall ziacka
BEGIN;
CREATE TABLE "ziacka_znamka" (
    "id" integer NOT NULL PRIMARY KEY,
    "meno_ziaka" varchar(30) NOT NULL,
    "priezvisko_ziaka" varchar(30) NOT NULL,
    "meno_ucitela" varchar(30) NOT NULL,
    "priezvisko_ucitela" varchar(30) NOT NULL,
    "predmet" varchar(50) NOT NULL,
    "znamka" integer unsigned NOT NULL
)
;
COMMIT;
}}}

=== Všimnite si ===

 * Vzniklo niečo, čo sme explicitne nepožadovali, a to stĺpec {{{id}}}.
 * Názov tabuľky má ako prefix názov aplikácie. Preto nás nemusí trápiť, ak máme rovnako pomenované modely v dvoch rôznych aplikáciách.

=== Upozornenie ===

<<Pozor>>
'''Ak by sme sa rozhodli teraz triedu {{{Znamka}}} zmeniť, {{{./manage.py syncdb}}} už žiadne zmeny v databázovej tabuľke neurobí. Vie iba tabuľku vytvoriť, nie modifikovať. Z praktického hľadiska to znamená, že ak počas vývoja zmeníme model, musíme databázu vymazať.
Preto je dobrý nápad mať malý pythonovský skript, ktorý naplní databázu vzorkou dát, aby sme to nemuseli opakovane robiť ručne.

Takže pre znovuvytvorenie databázy potom už iba spustíme'''
{{{
$ ./manage.py shell < data_script.py
}}}
'''a hotovo.'''
<<Pohov>>
<<Pozor>>
'''Do {{{models.py}}} môžeme pridať kedykoľvek novú triedu, vtedy mazať databázu nemusíme.'''
<<Pohov>>

== Základná práca s modelom ==

=== Zapisovanie dát ===

Najprv si dáme náš model do globálneho namespace.

{{{#!python
$ ./manage.py shell
Python 2.5.2 (r252:60911, Jan 4 2009, 17:40:26)
[GCC 4.3.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from skola.ziacka.models import *
>>>
}}}

Vytvoríme si inštanciu modelu, t.j. riadok tabuľky:
{{{#!python
>>> z=Znamka(meno_ziaka="Jan",
... priezvisko_ziaka="Prvy",
... meno_ucitela="Ivan",
... priezvisko_ucitela="Hrozny",
... predmet="Matematika"
... , znamka=3
... )
>>> print z
Znamka object
>>>
}}}
Objekt {{{z}}} ešte nie je uložený v databáze. Aby sme ho uložili, musíme urobiť toto:
{{{#!python
>>> z.save()
>>>
}}}

Analogicky pridáme do databázy ešte zo dve známky. Potom môžeme ukončiť pythonovský
shell cez {{{CTRL-D}}}.

=== Čítanie dát ===

{{{#!python
$ ./manage.py shell
Python 2.5.2 (r252:60911, Jan 4 2009, 17:40:26)
[GCC 4.3.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from skola.ziacka.models import *
>>>
}}}

Skúsme si vypísať teraz všetky známky:
{{{#!python
>>> Znamka.objects.all()
[<Znamka: Znamka object>, <Znamka: Znamka object>, <Znamka: Znamka object>]
>>>
}}}

To nie je veľmi informatívne, ak chceme vypisovať známky trochu lepšie, dodajme
do triedy Znamka metódu {{{__unicode__}}}:
{{{#!python
class Znamka(models.Model):

    # meno a priezvisko ziaka
    meno_ziaka=models.CharField(max_length=30)
    priezvisko_ziaka=models.CharField(max_length=30)
    # meno a priezvisko ucitela
    meno_ucitela=models.CharField(max_length=30)
    priezvisko_ucitela=models.CharField(max_length=30)
    # predmet, z ktoreho bola znamka udelena
    predmet=models.CharField(max_length=50)
    # znamka
    znamka=models.PositiveIntegerField()
    
    def __unicode__(self):
        return u"%s : %d z %s" % (self.meno_ziaka,self.znamka,self.predmet)
}}}

Všimnite si, že vraciame unicode reťazec.

Aby kódovanie unicode reťazca fungovalo korektne, musíme špecifikovať v akom kódovaní
pracujeme. Prvý riadok nášho modulu preto bude
{{{#!python
# -*- coding: UTF-8 -*-
}}}

Pozn. ak robíme v B206 resp. vo Windows, bude tam {{{iso-8859-2}}} resp. {{{cp-1250}}}.

Skúsme znovu:

{{{#!python
$ ./manage.py shell
Python 2.5.2 (r252:60911, Jan 4 2009, 17:40:26)
[GCC 4.3.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from skola.ziacka.models import *
>>> znamky=Znamka.objects.all()
>>> print znamky
[<Znamka: Jan : 3 z Matematika>, <Znamka: Jozef : 1 z Anglicky jazyk>, <Znamka: Anna : 1 z Telesna vychova>]
>>>
}}}

Teraz Janovi zmeníme známku na objektívnejšiu:
{{{#!python
>>> zn_jano=znamky[0]
>>> print zn_jano
Jan : 3 z Matematika
>>> zn_jano.znamka=2
>>> zn_jano.save()
}}}

A môžeme si znovu známky vypísať:
{{{#!python
>>> print znamky
[<Znamka: Jan : 2 z Matematika>, <Znamka: Jozef : 1 z Anglicky jazyk>, <Znamka: Anna : 1 z Telesna vychova>]
>>>
}}}

Janovi sme zmenili známku na dvojku.

=== Filtrovanie dát ===

Začnime skúmaním djangovských typov, ktoré nám umožňujú horeuvedené hry.

Prvých dvoch hráčov poznáme, sú to
 * modely, t.j. podtriedy {{{django.db.models.Model}}} a
 * inštancie modelov.

To ale nie je všetko:
{{{#!python
>>> type(Znamka.objects)
<class 'django.db.models.manager.Manager'>
>>> type(Znamka.objects.all())
<class 'django.db.models.query.QuerySet'>
}}}

{{{Manager}}} má v podstate za úlohu prekladať pythonovské
volania na SQL. V tejto chvíli je pre nás dôležité to, že z neho môžeme vymámiť pomocou
rôznych metód objekt typu {{{QuerySet}}}.

Každý {{{QuerySet}}} je iterovateľný a indexovateľný.

V tejto chvíli vás už odkážem na dokumentáciu, dodám už len pár sedení.

=== Filtrovanie so špecifikáciou atribútov ===

V princípe nám nič nebráni vziať {{{Znamka.objects.all()}}} a začať
cez neho iterovať normálne pomocou {{{for}}} a vyberať si pre ďalšie spracovanie
tie objekty, ktoré potrebujeme.

Databázový server/knižnica to ale urobí rýchlejšie a spoľahlivejšie.

{{{#!python
>>> Znamka.objects.filter(meno_ziaka="Anna")
[<Znamka: Anna : 1 z Telesna vychova>]
>>> Znamka.objects.filter(meno_ziaka="Anna",priezvisko_ziaka="Nevyhnutna")
[<Znamka: Anna : 1 z Telesna vychova>]
>>> Znamka.objects.filter(priezvisko_ziaka="Nevyhnutna")
[<Znamka: Anna : 1 z Telesna vychova>]
}}}

Môže sa vrátiť prázdny zoznam:
{{{#!python
>>> Znamka.objects.filter(meno_ziaka="Anna",priezvisko_ziaka="Neexistujuca")
[]
>>>
}}}

Alebo zoznam viacerých známok:
{{{#!python
>>> Znamka.objects.filter(znamka=1)
[<Znamka: Jozef : 1 z Anglicky jazyk>, <Znamka: Anna : 1 z Telesna vychova>]
>>>
}}}

Duálom k {{{filter}}} je {{{exclude}}}:
{{{#!python
>>> Znamka.objects.exclude(znamka=1)
[<Znamka: Jan : 2 z Matematika>]
}}}

==== Zložitejšie filtre ====

Rafinovaným spôsobom sa využívajú pomenované argumenty.

{{{#!python
>>> Znamka.objects.filter(predmet__contains="jazyk")
[<Znamka: Jozef : 1 z Anglicky jazyk>]
>>> Znamka.objects.filter(predmet__startswith="Telesna")
[<Znamka: Anna : 1 z Telesna vychova>]
>>>
}}}

Nikto nemá lepšiu známku ako 1 a je len jedna horšia známka
ako 1.
{{{#!python
>>> Znamka.objects.filter(znamka__lt=1)
[]
>>> Znamka.objects.filter(znamka__gt=1)
[<Znamka: Jan : 2 z Matematika>]
>>>
}}}

Ide aj vyberať podľa abecedného poradia:
{{{#!python
>>> Znamka.objects.filter(meno_ziaka__lte="Jan")
[<Znamka: Jan : 2 z Matematika>, <Znamka: Anna : 1 z Telesna vychova>]
>>>
}}}

=== Zreťazovanie filtrov ===

{{{QuerySet}}} sa dá ďalej filtrovať.

{{{#!python
>>> Znamka.objects.filter(meno_ziaka__lte="Jan").exclude(znamka=1)
[<Znamka: Jan : 2 z Matematika>]
>>>
}}}











                 

Jednoduchý model a práca s ním

Django umožňuje pracovať s relačnou databázou pomocou objektovo-relačného modelu. Robí to pomocou techniky menom objektovo-relačné mapovanie (ORM). Z praktického hľadiska táto technika slúži na izolovanie programátora aplikácie od databázového servra, Je možné začať vyvíjať aplikáciu lokálne pod sqlite a v reálnom nasadení potom použiť povedzme Oracle, pričom jediná zmena je v settings.py. Programátor sa nemusí zaoberať SQL, stačí mu vedieť python.

Nevýhoda tejto techniky je v tom, že neumožňuje účinne používať mnohé techniky určené pre zvýšenie výkonnosti databázového servra (triggery a pod.). Primárnym účelom djanga je vytvárať dynamické webové stránky, ale napríklad veľká aplikácia ako napríklad http://is.stuba.sk vyžaduje trochu zložitejší návrh databázovej schémy, než to umožňuje django.

Vytvorenie modelu

Vytvorme si nový projekt s názvom skola a v ňom aplikáciu s názvom ziacka.

Ideme implementovať dátový model žiackej knižky naivným (a pre tento účel nesprávnym) spôsobom: ako jednu veľkú tabuľku s mnohými stĺpcami. Nesmieme zabudnúť doplniť aplikáciu v settings.py.

V adresári ziacka máme súbor models.py, ktorý vyzerá takto:

   1 from django.db import models
   2 
   3 class Znamka(models.Model):
   4 
   5     # meno a priezvisko ziaka
   6     meno_ziaka=models.CharField(max_length=30)
   7     priezvisko_ziaka=models.CharField(max_length=30)
   8     # meno a priezvisko ucitela
   9     meno_ucitela=models.CharField(max_length=30)
  10     priezvisko_ucitela=models.CharField(max_length=30)
  11     # predmet, z ktoreho bola znamka udelena
  12     predmet=models.CharField(max_length=50)
  13     # znamka
  14     znamka=models.PositiveIntegerField()

models.py

Napíšme teraz

$ ./manage.py syncdb

a všimnime si, že vo výpise máme takýto riadok

Creating table ziacka_znamka

Pre zaujímavosť sa môžeme pozrieť, aké SQL príkazy boli použité na vytvorenie tabuľky.

$ ./manage.py sqlall ziacka
BEGIN;
CREATE TABLE "ziacka_znamka" (
    "id" integer NOT NULL PRIMARY KEY,
    "meno_ziaka" varchar(30) NOT NULL,
    "priezvisko_ziaka" varchar(30) NOT NULL,
    "meno_ucitela" varchar(30) NOT NULL,
    "priezvisko_ucitela" varchar(30) NOT NULL,
    "predmet" varchar(50) NOT NULL,
    "znamka" integer unsigned NOT NULL
)
;
COMMIT;

Všimnite si

  • Vzniklo niečo, čo sme explicitne nepožadovali, a to stĺpec id.

  • Názov tabuľky má ako prefix názov aplikácie. Preto nás nemusí trápiť, ak máme rovnako pomenované modely v dvoch rôznych aplikáciách.

Upozornenie

Ak by sme sa rozhodli teraz triedu Znamka zmeniť, ./manage.py syncdb už žiadne zmeny v databázovej tabuľke neurobí. Vie iba tabuľku vytvoriť, nie modifikovať. Z praktického hľadiska to znamená, že ak počas vývoja zmeníme model, musíme databázu vymazať. Preto je dobrý nápad mať malý pythonovský skript, ktorý naplní databázu vzorkou dát, aby sme to nemuseli opakovane robiť ručne.

Takže pre znovuvytvorenie databázy potom už iba spustíme

$ ./manage.py shell < data_script.py

a hotovo.

Do models.py môžeme pridať kedykoľvek novú triedu, vtedy mazať databázu nemusíme.

Základná práca s modelom

Zapisovanie dát

Najprv si dáme náš model do globálneho namespace.

   1 $ ./manage.py shell
   2 Python 2.5.2 (r252:60911, Jan  4 2009, 17:40:26)
   3 [GCC 4.3.2] on linux2
   4 Type "help", "copyright", "credits" or "license" for more information.
   5 (InteractiveConsole)
   6 >>> from skola.ziacka.models import *
   7 >>>

Vytvoríme si inštanciu modelu, t.j. riadok tabuľky:

   1 >>> z=Znamka(meno_ziaka="Jan",
   2 ... priezvisko_ziaka="Prvy",
   3 ... meno_ucitela="Ivan",
   4 ... priezvisko_ucitela="Hrozny",
   5 ... predmet="Matematika"
   6 ... , znamka=3
   7 ... )
   8 >>> print z
   9 Znamka object
  10 >>>

Objekt z ešte nie je uložený v databáze. Aby sme ho uložili, musíme urobiť toto:

   1 >>> z.save()
   2 >>> 

Analogicky pridáme do databázy ešte zo dve známky. Potom môžeme ukončiť pythonovský shell cez CTRL-D.

Čítanie dát

   1 $ ./manage.py shell
   2 Python 2.5.2 (r252:60911, Jan  4 2009, 17:40:26)
   3 [GCC 4.3.2] on linux2
   4 Type "help", "copyright", "credits" or "license" for more information.
   5 (InteractiveConsole)
   6 >>> from skola.ziacka.models import *
   7 >>>

Skúsme si vypísať teraz všetky známky:

   1 >>> Znamka.objects.all()
   2 [<Znamka: Znamka object>, <Znamka: Znamka object>, <Znamka: Znamka object>]
   3 >>> 

To nie je veľmi informatívne, ak chceme vypisovať známky trochu lepšie, dodajme do triedy Znamka metódu __unicode__:

   1 class Znamka(models.Model):
   2 
   3     # meno a priezvisko ziaka
   4     meno_ziaka=models.CharField(max_length=30)
   5     priezvisko_ziaka=models.CharField(max_length=30)
   6     # meno a priezvisko ucitela
   7     meno_ucitela=models.CharField(max_length=30)
   8     priezvisko_ucitela=models.CharField(max_length=30)
   9     # predmet, z ktoreho bola znamka udelena
  10     predmet=models.CharField(max_length=50)
  11     # znamka
  12     znamka=models.PositiveIntegerField()
  13     
  14     def __unicode__(self):
  15         return u"%s : %d z %s" % (self.meno_ziaka,self.znamka,self.predmet)

Všimnite si, že vraciame unicode reťazec.

Aby kódovanie unicode reťazca fungovalo korektne, musíme špecifikovať v akom kódovaní pracujeme. Prvý riadok nášho modulu preto bude

   1 # -*- coding: UTF-8 -*-

Pozn. ak robíme v B206 resp. vo Windows, bude tam iso-8859-2 resp. cp-1250.

Skúsme znovu:

   1 $ ./manage.py shell
   2 Python 2.5.2 (r252:60911, Jan  4 2009, 17:40:26)
   3 [GCC 4.3.2] on linux2
   4 Type "help", "copyright", "credits" or "license" for more information.
   5 (InteractiveConsole)
   6 >>> from skola.ziacka.models import *
   7 >>> znamky=Znamka.objects.all()
   8 >>> print znamky
   9 [<Znamka: Jan : 3 z Matematika>, <Znamka: Jozef : 1 z Anglicky jazyk>, <Znamka: Anna : 1 z Telesna vychova>]
  10 >>>                            

Teraz Janovi zmeníme známku na objektívnejšiu:

   1 >>> zn_jano=znamky[0]
   2 >>> print zn_jano
   3 Jan : 3 z Matematika
   4 >>> zn_jano.znamka=2
   5 >>> zn_jano.save()

A môžeme si znovu známky vypísať:

   1 >>> print znamky
   2 [<Znamka: Jan : 2 z Matematika>, <Znamka: Jozef : 1 z Anglicky jazyk>, <Znamka: Anna : 1 z Telesna vychova>]
   3 >>>  

Janovi sme zmenili známku na dvojku.

Filtrovanie dát

Začnime skúmaním djangovských typov, ktoré nám umožňujú horeuvedené hry.

Prvých dvoch hráčov poznáme, sú to

  • modely, t.j. podtriedy django.db.models.Model a

  • inštancie modelov.

To ale nie je všetko:

   1 >>> type(Znamka.objects)
   2 <class 'django.db.models.manager.Manager'>
   3 >>> type(Znamka.objects.all())
   4 <class 'django.db.models.query.QuerySet'>

Manager má v podstate za úlohu prekladať pythonovské volania na SQL. V tejto chvíli je pre nás dôležité to, že z neho môžeme vymámiť pomocou rôznych metód objekt typu QuerySet.

Každý QuerySet je iterovateľný a indexovateľný.

V tejto chvíli vás už odkážem na dokumentáciu, dodám už len pár sedení.

Filtrovanie so špecifikáciou atribútov

V princípe nám nič nebráni vziať Znamka.objects.all() a začať cez neho iterovať normálne pomocou for a vyberať si pre ďalšie spracovanie tie objekty, ktoré potrebujeme.

Databázový server/knižnica to ale urobí rýchlejšie a spoľahlivejšie.

   1 >>> Znamka.objects.filter(meno_ziaka="Anna")
   2 [<Znamka: Anna : 1 z Telesna vychova>]
   3 >>> Znamka.objects.filter(meno_ziaka="Anna",priezvisko_ziaka="Nevyhnutna")
   4 [<Znamka: Anna : 1 z Telesna vychova>]
   5 >>> Znamka.objects.filter(priezvisko_ziaka="Nevyhnutna")
   6 [<Znamka: Anna : 1 z Telesna vychova>]

Môže sa vrátiť prázdny zoznam:

   1 >>> Znamka.objects.filter(meno_ziaka="Anna",priezvisko_ziaka="Neexistujuca")
   2 []
   3 >>>

Alebo zoznam viacerých známok:

   1 >>> Znamka.objects.filter(znamka=1)
   2 [<Znamka: Jozef : 1 z Anglicky jazyk>, <Znamka: Anna : 1 z Telesna vychova>]
   3 >>> 

Duálom k filter je exclude:

   1 >>> Znamka.objects.exclude(znamka=1)
   2 [<Znamka: Jan : 2 z Matematika>]

Zložitejšie filtre

Rafinovaným spôsobom sa využívajú pomenované argumenty.

   1 >>> Znamka.objects.filter(predmet__contains="jazyk")
   2 [<Znamka: Jozef : 1 z Anglicky jazyk>]
   3 >>> Znamka.objects.filter(predmet__startswith="Telesna")
   4 [<Znamka: Anna : 1 z Telesna vychova>]
   5 >>>

Nikto nemá lepšiu známku ako 1 a je len jedna horšia známka ako 1.

   1 >>> Znamka.objects.filter(znamka__lt=1)
   2 []
   3 >>> Znamka.objects.filter(znamka__gt=1)
   4 [<Znamka: Jan : 2 z Matematika>]
   5 >>>

Ide aj vyberať podľa abecedného poradia:

   1 >>> Znamka.objects.filter(meno_ziaka__lte="Jan")
   2 [<Znamka: Jan : 2 z Matematika>, <Znamka: Anna : 1 z Telesna vychova>]
   3 >>>

Zreťazovanie filtrov

QuerySet sa dá ďalej filtrovať.

   1 >>> Znamka.objects.filter(meno_ziaka__lte="Jan").exclude(znamka=1)
   2 [<Znamka: Jan : 2 z Matematika>]
   3 >>>

KMaDGWiki: ProgramovanieInternetovychAplikacii/SimpleModel (last edited 2009-03-10 20:54:20 by dial-92-52-21-192-orange)