Pereiti prie turinio

Django ORM ir SQL JOIN


Rekomenduojami pranešimai

Sveiki,

Esu Django pradedančiųjų kelyje ir susidūriau su tokiu klausimu - kaip Django apjungti kelias lenteles į vieną visumą.

Išnagrinėjau dokumentaciją, perskaičiau daug forumų, bet konkretaus atsakymo į klausimą taip ir neradau. Yra pilna pavyzdžių, kaip apjungti 2 lentas, o man reikia 3 ir daugiau, ir dar iš vienos lentos paimti iškart du įrašus. SQL užklausa yra tokia:

 

SELECT a.id prekes_id, a.pavadinimas pavadinimas, b.id brando_id, b.pavadinimas brendas, c.tekstas prekes_aprasymas, d.tekstas trumpas_aprasymas, e.tikras_vardas nuotrauka

FROM bazes_prekes a

LEFT JOIN bazes_brandai b ON b.id=a.brendo_id

LEFT JOIN bazes_aprasymai c ON c.kalbos_id='1' and c.content_id=a.id and c.lenta='prekes' and c.column='aprasymas'

LEFT JOIN bazes_aprasymai d ON d.kalbos_id='1' and d.content_id=a.id and d.lenta='prekes' and d.column='trump_aprasymas'

LEFT JOIN bazes_bylos e ON e.pagrindine='1' and e.content_id=a.id and e.lenta='prekes'

WHERE b.id = '1'

 

 

Esu radęs, kad SQL`ą galima tiesiogiai rašyti, bet kažkaip nesigauna (klaidos neišmeta, bet rezultatas gaunamas visiškai netoks):

 

def mano_sql():

from django.db import connection, transaction

cursor = connection.cursor()

cursor.execute("""

SELECT a.id prekes_id, a.pavadinimas pavadinimas, b.id brando_id, b.pavadinimas brendas, c.tekstas prekes_aprasymas, d.tekstas trumpas_aprasymas, e.tikras_vardas nuotrauka

FROM bazes_prekes a

LEFT JOIN bazes_brandai b ON b.id=a.brendo_id

LEFT JOIN bazes_aprasymai c ON c.kalbos_id='1' and c.content_id=a.id and c.lenta='prekes' and c.column='aprasymas'

LEFT JOIN bazes_aprasymai d ON d.kalbos_id='1' and d.content_id=a.id and d.lenta='prekes' and d.column='trump_aprasymas'

LEFT JOIN bazes_bylos e ON e.pagrindine='1' and e.content_id=a.id and e.lenta='prekes'

WHERE b.id = '1'""")

row = cursor.fetchone()

 

return row

 

 

Iškvietimas :

masyvas = mano_sql()

Nuoroda į pranešimą
Dalintis kituose puslapiuose

Iš esmės django viskas apsijungia savaime su lazy evaluation, t.y. jei turi:

pr = Preke.objects.get(...)
print pr.brandas # bus generuojama dar viena užklausa

Tai printinant automatiškai dės užklausą į brand lentelę ir suras reikiamą brand'ą (aišku, jei modelyje yra ForeignKey :)). Kad būtų normalūs joinai viena užklausa, reikia naudoti select_related():

pr = Preke.objects.get(...).select_related('brandas') # viskas ištraukiama šia užklausa
print pr.brandas # nieko nebekainuoja

Redagavo Silke
Nuoroda į pranešimą
Dalintis kituose puslapiuose

Dėkui už atrašymą. Bet čia kalba eina apie dvi lenteles :

 

pr = Preke.objects.get(...).select_related('brandas') # viskas ištraukiama šia užklausa

print pr.brandas # nieko nebekainuoja

 

O aš noriu padaryti užklausą iš trijų.

Pas mane yra trys lentos: Brendai, Prekės, Aprašymai ir man reikia, kad pasirinkus brendą, išrinktų atitinkamas prekes,

ir kiekviena prekė dar turi po du įrašus lentoj Aprašymai (vienas trumpam aprašymui, kitas ilgam). Visas rezultatas turėtų būti viena masyvo eilutė. Su SQL`u mano užklausa veikia gražiai, bet Djange nu niekaip neina padaryti . Atsimušiau į sieną.

Man geriau aiškinkit kaip pirmokui :)

Nuoroda į pranešimą
Dalintis kituose puslapiuose

Dėkui už atrašymą. Bet čia kalba eina apie dvi lenteles :

 

pr = Preke.objects.get(...).select_related('brandas') # viskas ištraukiama šia užklausa

print pr.brandas # nieko nebekainuoja

 

O aš noriu padaryti užklausą iš trijų.

Pas mane yra trys lentos: Brendai, Prekės, Aprašymai ir man reikia, kad pasirinkus brendą, išrinktų atitinkamas prekes,

ir kiekviena prekė dar turi po du įrašus lentoj Aprašymai (vienas trumpam aprašymui, kitas ilgam). Visas rezultatas turėtų būti viena masyvo eilutė. Su SQL`u mano užklausa veikia gražiai, bet Djange nu niekaip neina padaryti . Atsimušiau į sieną.

Man geriau aiškinkit kaip pirmokui :)

Viskas tas pats, tik jungimas priklauso nuo to, ant kurio modelio yra ForeignKey į tą brandą. Pvz. jei prekė rodo į brandą, o brandas į aprašymą:

Preke.objects.filter().select_related('brandas').select_related('brandas__aprasymas')

T.y. reikalingi tie du brūkšneliai __ tam, kad parodytum, jog FK yra ant brando (ne prekės).

Nuoroda į pranešimą
Dalintis kituose puslapiuose

Jau pradeda aiškėti. FK aš suprantu reikėtų taip daryti:

Brendas vienas, prekių daug, tai čia reikėtų :

 

class Brandai(models.Model):
   darbinis_pav = models.CharField(max_length=65)
   pavadinimas = models.CharField(max_length=65)

   def __unicode__(self):
       return self.pavadinimas

 

class Prekes (models.Model):
   brendo_id = models.ForeignKey(Brandai)
   kategorija = models.CharField(max_length=15)
   pavadinimas = models.CharField(max_length=100)

 

ir viena prekė turi kelis aprašymus

 

class Aprasymai (models.Model):
   content_id = models.ForeignKey(Prekes)
   kalbos_id = models.IntegerField()
   tekstas = models.TextField()
   lenta = models.CharField(max_length=45)
   column = models.CharField(max_length=65)

Nuoroda į pranešimą
Dalintis kituose puslapiuose
  • po 2 savaičių...

Gal kam bus įdomu:

Naujoj Django versijoj atsirado galimybė daryti užklausą panaudojant prefetch_related,

kuris mano atveju tikriausiai labiau tinka nei select_related.

Pridedu linką:

https://docs.djangoproject.com/en/dev/ref/models/querysets/#prefetch-related

 

O savo temos pradžioje duotame kode ištaisiau row = cursor.fetchone() į

row = cursor.fetchall() ir viskas susitvarkė. Kiek laiko teko paaukoti, kol radau šią mažą klaidelę :) .

Redagavo meshkis
Nuoroda į pranešimą
Dalintis kituose puslapiuose

Gal kam bus įdomu:

Naujoj Django versijoj atsirado galimybė daryti užklausą panaudojant prefetch_related,

kuris mano atveju tikriausiai labiau tinka nei select_related.

Pridedu linką:

https://docs.djangoproject.com/en/dev/ref/models/querysets/#prefetch-related

 

O savo temos pradžioje duotame kode ištaisiau row = cursor.fetchone() į

row = cursor.fetchall() ir viskas susitvarkė. Kiek laiko teko paaukoti, kol radau šią mažą klaidelę :) .

Tiksliau, prefetch_related() atsiras 1.4 versijoje, kuri kol kas yra tik beta :)

Nuoroda į pranešimą
Dalintis kituose puslapiuose
  • po 1 metų...

Sveiki,

Vėl aš stringu su tuo Django ORM.

 

class Skyriai(models.Model):    
   pavadinimas = models.CharField(max_length=64)        
   pozicija = models.SmallIntegerField()

   def __unicode__(self):
       return u'%s %s' % (self.pavadinimas)

 

class Tekstai(models.Model):
   skyrius = models.ForeignKey(Skyriai)    
   tekstas = WYSIWYGField(verbose_name='Aprašymas')
   data = models.DateField()

   def __unicode__(self):
       return u'%s %s %s' % (self.skyrius, self.tekstas, self.data)

 

Taigi turiu tokius modelius. Man reikia elementarios užklausos, kuri išrinktų skyrius su visais jam priklausančiais tekstais.

Apie šitą būdą žinau:

b = Blog.objects.get(id=1)
b.entry_set.all()

Bet man reikia, kad viskas būtų vienoje užklausoje. T.y. man reikia, kad kažkur toliau programoje, aš galėčiau HTML`e, cikle iš masyvo ištraukinėti skyrius po vieną su visais jam priklausančiais tekstais. Su SQL aš tai lengvai padarau, bet norėtųsi naudoti Django galimybes.

Redagavo meshkis
Nuoroda į pranešimą
Dalintis kituose puslapiuose

Prisijunkite prie diskusijos

Jūs galite rašyti dabar, o registruotis vėliau. Jeigu turite paskyrą, prisijunkite dabar, kad rašytumėte iš savo paskyros.

Svečias
Parašykite atsakymą...

×   Įdėta kaip raiškusis tekstas.   Atkurti formatavimą

  Only 75 emoji are allowed.

×   Nuorodos turinys įdėtas automatiškai.   Rodyti kaip įprastą nuorodą

×   Jūsų anksčiau įrašytas turinys buvo atkurtas.   Išvalyti redaktorių

×   You cannot paste images directly. Upload or insert images from URL.

Įkraunama...
  • Dabar naršo   0 narių

    Nei vienas registruotas narys šiuo metu nežiūri šio puslapio.

  • Prisijunk prie bendruomenės dabar!

    Uždarbis.lt nariai domisi verslo, IT ir asmeninio tobulėjimo temomis, kartu sprendžia problemas, dalinasi žiniomis ir idėjomis, sutinka būsimus verslo partnerius ir dalyvauja gyvuose susitikimuose.

    Užsiregistruok dabar ir galėsi:

    ✔️ Dalyvauti diskusijose;

    ✔️ Kurti naujas temas;

    ✔️ Rašyti atsakymus;

    ✔️ Vertinti kitų žmonių pranešimus;

    ✔️ Susisiekti su bet kuriuo nariu asmeniškai;

    ✔️ Naudotis tamsia dizaino versija;

    ir dar daugiau.

    Registracija trunka ~30 sek. ir yra visiškai nemokama.

  • Naujausios temos

  • Karštos temos

×
×
  • Pasirinkite naujai kuriamo turinio tipą...