Differences between revisions 6 and 18 (spanning 12 versions)
Revision 6 as of 2009-03-17 11:32:20
Size: 2196
Editor: 95
Comment:
Revision 18 as of 2009-03-17 17:53:37
Size: 8074
Editor: 95
Comment:
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
= Zložitejší model = = Zložitejšia schéma =
Line 4: Line 4:
Model, ktorý sme použili v predošlom prípade má mnoho zásadných nevýhod.

Na prvý pohľad vidno, že dáta sú v ňom duplicitné. Teda ak budeme chcieť zmeniť nejaký
Schéma, ktorú sme použili v predošlom prípade má mnoho zásadných nevýhod.

Na prvý pohľad vidno, že dáta sú duplicitné. Teda ak budeme chcieť zmeniť nejaký
Line 9: Line 9:
Teraz si ukážeme lepší prístup Teraz si ukážeme lepší prístup.

Celá schéma je [[attachment:models.py]].
Line 56: Line 58:
Teraz ideme vytvoriť niekoľko žiakov a zaradiť ich do Tried. Teraz ideme vytvoriť žiaka a (nevyhnutne) zaradiť ho do Triedy. 
Line 87: Line 89:

Ešte vytvoríme zopár žiakov
{{{#!python
>>> Ziak(meno="Jozef",priezvisko="Druhy",trieda=tretia_B).save()
>>> Ziak(meno="Katarina",priezvisko="Tretia",trieda=tretia_B).save()
>>> tretia_A=Trieda.objects.get(rocnik=3,pismeno="A")
>>> Ziak(meno="Milan",priezvisko="Stvrty",trieda=tretia_A).save()
>>> Ziak(meno="Jana",priezvisko="Piata",trieda=tretia_A).save()
>>> Ziak(meno="Anna",priezvisko="Siesta",trieda=tretia_A).save()
>>>
}}}

== Vypísanie žiakov patriacich do triedy ==

Prvý spôsob je jednoducho použiť filter
na všetkých žiakov.

{{{#!python
>>> tretia_A=Trieda.objects.get(rocnik=3,pismeno="A")
>>> ziaci_3A=Ziak.objects.filter(trieda=tretia_A)
>>> print ziaci_3A
[<Ziak: Milan Stvrty>, <Ziak: Jana Piata>, <Ziak: Anna Siesta>]
>>>
}}}

Druhý spôsob je takto:

{{{#!python
>>> ziaci_3A=tretia_A.ziak_set.all()
>>> print ziaci_3A
[<Ziak: Milan Stvrty>, <Ziak: Jana Piata>, <Ziak: Anna Siesta>]
>>>
}}}

Otázka je, čo je rýchlejšie. Odpoveď v tejto chvíli nepoznám,
závisí to od toho, ako inteligentne django ošetrí prvý spôsob.
Som si istý, že druhý spôsob nie je pomalší ako prvý.

== Predmety a učitelia ==

Predmet nemá referencie na nič:

{{{#!python
class Predmet(models.Model):
    nazov=models.CharField(max_length=50)

    def __unicode__(self):
        return self.nazov
}}}

Vzťah medzi predmetmi a učiteľmi je iný ako medzi žiakmi a triedami;
žiak patrí do jedinej triedy ale predmet je spravidla učený viacerými
učiteľmi, a aj učiteľ učí viac predmetov.

{{{#!python
class Ucitel(models.Model):
    meno=models.CharField(max_length=50)
    priezvisko=models.CharField(max_length=50)
    predmety=models.ManyToManyField(Predmet)

    def __unicode__(self):
        return u"%s %s" % (self.meno,self.priezvisko)
}}}

Predpokladajme, že predmety sme už vytvorili.

{{{#!python
>>> print Predmet.objects.all()
[<Predmet: Matematika>, <Predmet: Fyzika>, <Predmet: Telocvik>]
}}}

Ideme vytvoriť učiteľa.

{{{#!python
>>> matika=Predmet.objects.get(nazov="Matematika")
>>> fyzika=Predmet.objects.get(nazov="Fyzika")
>>> telak=Predmet.objects.get(nazov="Telocvik")
>>> ih=Ucitel(meno="Ivan",priezvisko="Hrozny")
>>> type(ih.predmety)
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/var/lib/python-support/python2.5/django/db/models/fields/related.py", line 563, in __get__
    target_col_name=qn(self.field.m2m_reverse_name())
  File "/var/lib/python-support/python2.5/django/db/models/fields/related.py", line 375, in __init__
    raise ValueError("%r instance needs to have a primary key value before a many-to-many relationship can be used." % instance.__class__.__name__)
ValueError: 'Ucitel' instance needs to have a primary key value before a many-to-many relationship can be used.
>>>
}}}

Problém je v tom, že sme nezavolali {{{ih.save()}}}. Teda {{{ih.id}}} ešte neexistuje a {{{ih.predmety}}}
ešte nie je funkčné. V pozadí {{{ManyToManyField}}} je totiž nová tabuľka obsahujúca dvojice {{{ (id_ucitel,id_predmet) }}}.

{{{#!python
>>> ih.save()
>>> print ih.predmety
<django.db.models.fields.related.ManyRelatedManager object at 0xa13fdac>
>>>
}}}
 
Vidíme, že {{{ih.predmety}}} je akýsi {{{Manager}}}. Robíme s ním
podobne, ako s managerom modelu:
{{{#!python
>>> ih.predmety.all()
[]
>>> ih.predmety.add(matika)
>>> ih.predmety.add(fyzika)
>>> ih.predmety.all()
[<Predmet: Matematika>, <Predmet: Fyzika>]
>>> ih.predmety.filter(nazov__contains="M")
[<Predmet: Matematika>]
>>>
}}}

Podobne pridáme ďalších učiteľov.

Ako vyhľadáme všetkých matematikárov?

{{{#!python
>>> matika.ucitel_set
<django.db.models.fields.related.ManyRelatedManager object at 0xa13f2ac>
>>> matika.ucitel_set.all()
[<Ucitel: Ivan Hrozny>, <Ucitel: Berta Dobrotiva>]
>>>
}}}

== Celé to je poprepájané ==

Ak Ivan Hrozny prestal byť matikárom, môžeme vyhodiť Matematiku
zo zoznamu jeho predmetov metódou {{{remove}}}. Ide to ale aj naopak:

{{{#!python
>>> ih=Ucitel.objects.get(meno="Ivan",priezvisko="Hrozny")
>>> matika=Predmet.objects.get(nazov="Matematika")
>>> print matika.ucitel_set
<django.db.models.fields.related.ManyRelatedManager object at 0xa14526c>
>>> matika.ucitel_set.remove(ih)
>>> matika.ucitel_set.all()
[<Ucitel: Berta Dobrotiva>]
>>> ih.predmety.all()
[<Predmet: Fyzika>]
}}}

Vidíme, že Matematika zmizla zo zoznamu predmetov vyučovaných
Ivanom Hrozným.

Pridajme ih do zoznamu telocvikárov:

{{{#!python
>>> telak=Predmet.objects.get(nazov="Telocvik")
>>> print telak.ucitel_set.all()
[<Ucitel: Berta Dobrotiva>, <Ucitel: Karol Neutralny>]
>>> telak.ucitel_set.add(ih)
>>> print telak.ucitel_set.all()
[<Ucitel: Ivan Hrozny>, <Ucitel: Berta Dobrotiva>, <Ucitel: Karol Neutralny>]
>>> print ih.predmety.all()
[<Predmet: Fyzika>, <Predmet: Telocvik>]
>>>
}}}

== Ďalšie modely ==

V prvom rade musíme vymodelovať známky.

{{{#!python
class Znamka(models.Model):
    hodnotenie=models.IntegerField(choices=ZNAMKA_CHOICES)
    predmet=models.ForeignKey(Predmet)
    ziak=models.ForeignKey(Ziak)
    

    def __unicode__(self):
        return u"%d z %s pre %s" % (self.hodnotenie,self.predmet,self.ziak)
}}}

Ešte budeme reprezentovať informáciu, že učiteľ učí danú triedu, a ktorý predmet
vyučuje. Všimnite si, že sa sem priam žiada doplniť nejakú väzbu na neexistujúcu
aplikáciu "rozvrh hodín".

{{{#!python
class PredmetTrieda(models.Model):
    predmet=models.ForeignKey(Predmet)
    trieda=models.ForeignKey(Trieda)
    ucitel=models.ForeignKey(Ucitel)

    def __unicode__(self):
        return u"%s pre %s" % (self.predmet,self.trieda)
}}}

Zložitejšia schéma

Uchovávať dáta v jedinom modeli nie je väčšinou výhodné. Schéma, ktorú sme použili v predošlom prípade má mnoho zásadných nevýhod.

Na prvý pohľad vidno, že dáta sú duplicitné. Teda ak budeme chcieť zmeniť nejaký údaj (meno učiteľa napríklad) musíme to urobiť na mnohých miestach.

Teraz si ukážeme lepší prístup.

Celá schéma je models.py.

Trieda a žiak

Začnime Triedou.

   1 class Trieda(models.Model):
   2     rocnik=models.IntegerField()
   3     pismeno=models.CharField(max_length=5)
   4 
   5     def __unicode__(self):
   6         return u"%d.%s" % (self.rocnik,self.pismeno)

Toto je jednoduché, nič nové sa nedozvedáme.

Trieda Ziak je zaujímavejšia.

   1 class Ziak(models.Model):
   2     meno=models.CharField(max_length=50)
   3     priezvisko=models.CharField(max_length=50)
   4     trieda=models.ForeignKey(Trieda)    
   5     
   6     def __unicode__(self):
   7         return u"%s %s" % (self.meno,self.priezvisko)

Vidíme, že obsahuje referenciu na Triedu. Žiak patrí do jedinej Triedy.

Ukážme si, ako sa s týmito modelmi dá pracovať.

Vytvorme zopár Tried.

   1 >>> from znamky.models import *
   2 >>> t=Trieda(rocnik=3,pismeno="A")
   3 >>> t.save()
   4 >>> t=Trieda(rocnik=3,pismeno="B")
   5 >>> t.save()
   6 >>> t=Trieda(rocnik=3,pismeno="C")
   7 >>> t.save()
   8 >>>

Teraz ideme vytvoriť žiaka a (nevyhnutne) zaradiť ho do Triedy.

   1 >>> tretie_triedy=Trieda.objects.filter(rocnik=3)
   2 >>> print tretie_triedy
   3 [<Trieda: 3.A>, <Trieda: 3.B>, <Trieda: 3.C>]
   4 >>> z=Ziak(meno="Jan",priezvisko="Prvy",trieda=tretie_triedy[0])
   5 >>> z.save()
   6 >>> print z
   7 Jan Prvy
   8 >>> print z.trieda
   9 3.A
  10 >>>

Jan Prvy bol zaradený do 3.A triedy. Všimnite si, že print z.trieda nám volá metódu Trieda.__unicode__. Fakticky, z.trieda je typu trieda:

   1 >>> type(z.trieda)
   2 <class 'skola.znamky.models.Trieda'>

Preraďme žiaka Jan Prvy do tretej B:

   1 >>> tretia_B=Trieda.objects.get(rocnik=3,pismeno="B")
   2 >>> jan_prvy=Ziak.objects.get(meno="Jan",priezvisko="Prvy")
   3 >>> jan_prvy.trieda=tretia_B
   4 >>> jan_prvy.save()
   5 >>>  

Ešte vytvoríme zopár žiakov

   1 >>> Ziak(meno="Jozef",priezvisko="Druhy",trieda=tretia_B).save()
   2 >>> Ziak(meno="Katarina",priezvisko="Tretia",trieda=tretia_B).save()
   3 >>> tretia_A=Trieda.objects.get(rocnik=3,pismeno="A")
   4 >>> Ziak(meno="Milan",priezvisko="Stvrty",trieda=tretia_A).save()
   5 >>> Ziak(meno="Jana",priezvisko="Piata",trieda=tretia_A).save()
   6 >>> Ziak(meno="Anna",priezvisko="Siesta",trieda=tretia_A).save()
   7 >>> 

Vypísanie žiakov patriacich do triedy

Prvý spôsob je jednoducho použiť filter na všetkých žiakov.

   1 >>> tretia_A=Trieda.objects.get(rocnik=3,pismeno="A")
   2 >>> ziaci_3A=Ziak.objects.filter(trieda=tretia_A)
   3 >>> print ziaci_3A
   4 [<Ziak: Milan Stvrty>, <Ziak: Jana Piata>, <Ziak: Anna Siesta>]
   5 >>>   

Druhý spôsob je takto:

   1 >>> ziaci_3A=tretia_A.ziak_set.all()
   2 >>> print ziaci_3A
   3 [<Ziak: Milan Stvrty>, <Ziak: Jana Piata>, <Ziak: Anna Siesta>]
   4 >>>

Otázka je, čo je rýchlejšie. Odpoveď v tejto chvíli nepoznám, závisí to od toho, ako inteligentne django ošetrí prvý spôsob. Som si istý, že druhý spôsob nie je pomalší ako prvý.

Predmety a učitelia

Predmet nemá referencie na nič:

   1 class Predmet(models.Model):
   2     nazov=models.CharField(max_length=50)
   3 
   4     def __unicode__(self):
   5         return self.nazov

Vzťah medzi predmetmi a učiteľmi je iný ako medzi žiakmi a triedami; žiak patrí do jedinej triedy ale predmet je spravidla učený viacerými učiteľmi, a aj učiteľ učí viac predmetov.

   1 class Ucitel(models.Model):
   2     meno=models.CharField(max_length=50)
   3     priezvisko=models.CharField(max_length=50)
   4     predmety=models.ManyToManyField(Predmet)
   5 
   6     def __unicode__(self):
   7         return u"%s %s" % (self.meno,self.priezvisko)

Predpokladajme, že predmety sme už vytvorili.

   1 >>> print Predmet.objects.all()
   2 [<Predmet: Matematika>, <Predmet: Fyzika>, <Predmet: Telocvik>]

Ideme vytvoriť učiteľa.

   1 >>> matika=Predmet.objects.get(nazov="Matematika")
   2 >>> fyzika=Predmet.objects.get(nazov="Fyzika")
   3 >>> telak=Predmet.objects.get(nazov="Telocvik")
   4 >>> ih=Ucitel(meno="Ivan",priezvisko="Hrozny")
   5 >>> type(ih.predmety)
   6 Traceback (most recent call last):
   7   File "<console>", line 1, in <module>
   8   File "/var/lib/python-support/python2.5/django/db/models/fields/related.py", line 563, in __get__
   9     target_col_name=qn(self.field.m2m_reverse_name())
  10   File "/var/lib/python-support/python2.5/django/db/models/fields/related.py", line 375, in __init__
  11     raise ValueError("%r instance needs to have a primary key value before a many-to-many relationship can be used." % instance.__class__.__name__)
  12 ValueError: 'Ucitel' instance needs to have a primary key value before a many-to-many relationship can be used.
  13 >>>

Problém je v tom, že sme nezavolali ih.save(). Teda ih.id ešte neexistuje a ih.predmety ešte nie je funkčné. V pozadí ManyToManyField je totiž nová tabuľka obsahujúca dvojice  (id_ucitel,id_predmet) .

   1 >>> ih.save()
   2 >>> print ih.predmety
   3 <django.db.models.fields.related.ManyRelatedManager object at 0xa13fdac>
   4 >>>

Vidíme, že ih.predmety je akýsi Manager. Robíme s ním podobne, ako s managerom modelu:

   1 >>> ih.predmety.all()
   2 []
   3 >>> ih.predmety.add(matika)
   4 >>> ih.predmety.add(fyzika)
   5 >>> ih.predmety.all()
   6 [<Predmet: Matematika>, <Predmet: Fyzika>]  
   7 >>> ih.predmety.filter(nazov__contains="M")
   8 [<Predmet: Matematika>]
   9 >>>

Podobne pridáme ďalších učiteľov.

Ako vyhľadáme všetkých matematikárov?

   1 >>> matika.ucitel_set
   2 <django.db.models.fields.related.ManyRelatedManager object at 0xa13f2ac>
   3 >>> matika.ucitel_set.all()
   4 [<Ucitel: Ivan Hrozny>, <Ucitel: Berta Dobrotiva>]
   5 >>>

Celé to je poprepájané

Ak Ivan Hrozny prestal byť matikárom, môžeme vyhodiť Matematiku zo zoznamu jeho predmetov metódou remove. Ide to ale aj naopak:

   1 >>> ih=Ucitel.objects.get(meno="Ivan",priezvisko="Hrozny")
   2 >>> matika=Predmet.objects.get(nazov="Matematika")
   3 >>> print matika.ucitel_set
   4 <django.db.models.fields.related.ManyRelatedManager object at 0xa14526c>
   5 >>> matika.ucitel_set.remove(ih)
   6 >>> matika.ucitel_set.all()
   7 [<Ucitel: Berta Dobrotiva>]
   8 >>> ih.predmety.all()
   9 [<Predmet: Fyzika>]

Vidíme, že Matematika zmizla zo zoznamu predmetov vyučovaných Ivanom Hrozným.

Pridajme ih do zoznamu telocvikárov:

   1 >>> telak=Predmet.objects.get(nazov="Telocvik")
   2 >>> print telak.ucitel_set.all()
   3 [<Ucitel: Berta Dobrotiva>, <Ucitel: Karol Neutralny>]
   4 >>> telak.ucitel_set.add(ih)
   5 >>> print telak.ucitel_set.all()
   6 [<Ucitel: Ivan Hrozny>, <Ucitel: Berta Dobrotiva>, <Ucitel: Karol Neutralny>]
   7 >>> print ih.predmety.all()
   8 [<Predmet: Fyzika>, <Predmet: Telocvik>]
   9 >>>      

Ďalšie modely

V prvom rade musíme vymodelovať známky.

   1 class Znamka(models.Model):
   2     hodnotenie=models.IntegerField(choices=ZNAMKA_CHOICES)
   3     predmet=models.ForeignKey(Predmet)
   4     ziak=models.ForeignKey(Ziak)
   5     
   6 
   7     def __unicode__(self):
   8         return u"%d z %s pre %s" % (self.hodnotenie,self.predmet,self.ziak)

Ešte budeme reprezentovať informáciu, že učiteľ učí danú triedu, a ktorý predmet vyučuje. Všimnite si, že sa sem priam žiada doplniť nejakú väzbu na neexistujúcu aplikáciu "rozvrh hodín".

   1 class PredmetTrieda(models.Model):
   2     predmet=models.ForeignKey(Predmet)
   3     trieda=models.ForeignKey(Trieda)
   4     ucitel=models.ForeignKey(Ucitel)
   5 
   6     def __unicode__(self):
   7         return u"%s pre %s" % (self.predmet,self.trieda)

KMaDGWiki: ProgramovanieInternetovychAplikacii/BetterModel (last edited 2009-03-17 17:53:37 by 95)