Differences between revisions 1 and 14 (spanning 13 versions)
Revision 1 as of 2009-03-17 11:10:55
Size: 1132
Editor: 95
Comment:
Revision 14 as of 2009-03-17 12:43:33
Size: 5871
Editor: 95
Comment:
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
= Zložitejší model =  = Zložitejší model =
Line 11: Line 11:
== Model == == Trieda a žiak ==
Line 34: Line 34:
Line 43: Line 42:

Vytvorme zopár Tried.

{{{#!python
>>> from znamky.models import *
>>> t=Trieda(rocnik=3,pismeno="A")
>>> t.save()
>>> t=Trieda(rocnik=3,pismeno="B")
>>> t.save()
>>> t=Trieda(rocnik=3,pismeno="C")
>>> t.save()
>>>
}}}

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

{{{#!python
>>> tretie_triedy=Trieda.objects.filter(rocnik=3)
>>> print tretie_triedy
[<Trieda: 3.A>, <Trieda: 3.B>, <Trieda: 3.C>]
>>> z=Ziak(meno="Jan",priezvisko="Prvy",trieda=tretie_triedy[0])
>>> z.save()
>>> print z
Jan Prvy
>>> print z.trieda
3.A
>>>
}}}
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:

{{{#!python
>>> type(z.trieda)
<class 'skola.znamky.models.Trieda'>
}}}

Preraďme žiaka Jan Prvy do tretej B:

{{{#!python
>>> tretia_B=Trieda.objects.get(rocnik=3,pismeno="B")
>>> jan_prvy=Ziak.objects.get(meno="Jan",priezvisko="Prvy")
>>> jan_prvy.trieda=tretia_B
>>> jan_prvy.save()
>>>
}}}

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í celej veci 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.
  

Zložitejší model

Uchovávať dáta v jedinom modeli nie je väčšinou výhodné. 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ý údaj (meno učiteľa napríklad) musíme to urobiť na mnohých miestach.

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

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í celej veci 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.

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