Mundarija (22)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. ForeignKey (bir-ko'p)
- 2.2. Oldinga va orqaga bog'lanish
- 2.3. related_name
- 2.4. ManyToManyField (ko'p-ko'p)
- 2.5. OneToOneField (bir-bir)
- 2.6. Bog'langan filtr (join)
- 2.7. on_delete (o'chirish xatti-harakati)
- 2.8. Bog'lanishlar — ma'lumot yaxlitligi
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — ForeignKey va oldinga/orqaga
- Misol 2 — ManyToManyField
- Misol 3 — OneToOneField va on_delete
- Misol 4 — Amaliy: to'liq bog'langan modellar
- 5. To'g'ri va noto'g'ri tushunishlar
- 6. Keng tarqalgan xatolar va yechimlari
- 7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 8. Eng yaxshi amaliyotlar
- 9. Amaliy topshiriq
- Xulosa
21.10-dars: ORM: bog'lanishlar
21-QISM — DJANGO · 10-dars
1. Kirish va motivatsiya
Real ma'lumot bog'langan: kurs bir muallifga tegishli, izoh bir kursga, kurs ko'p teglarga ega. Bu aloqalarni qanday ifodalami? Django ORM uch xil bog'lanish beradi: ForeignKey (bir-ko'p), ManyToManyField (ko'p-ko'p), OneToOneField (bir-bir). Bog'lanishlar — real dunyoning tuzilishini bazada aks ettiradi.
Bog'lanishlar — ma'lumot modelining yuragi: kam narsa mustaqil (hammasi bir-biriga bog'liq). To'g'ri bog'lanish — toza baza, oson so'rovlar (kurs.muallif.ism), izchil ma'lumot. Bu darsda bog'lanishlarni e'lon qilishni, oldinga/orqaga so'rovlarni va bog'langan filtrlarni o'rganamiz.
Real vaziyat. Bir jamoa muallif ma'lumotini har kursda takrorlab saqlardi (muallif_ism, muallif_email — har kursda) — muallif o'zgarsa, barcha kursni yangilash kerak, ba'zilari unutildi, ma'lumot nomuvofiq bo'ldi. Ular ForeignKey ishlatdi: muallif alohida jadval, kurs unga havola. Endi muallif bir joyda, kurslar unga bog'langan (kurs.muallif). O'zgarish bir joyda, ma'lumot izchil. Bog'lanishlar takrorni va nomuvofiqlikni yo'qotdi.
Bu darsda bog'lanishlarni — ForeignKey, ManyToManyField va bog'langan so'rovlarni o'rganamiz.
Bu darsda:
-
ForeignKey(bir-ko'p) - Oldinga va orqaga bog'lanish
related_name(orqaga havola)ManyToManyField(ko'p-ko'p)OneToOneField(bir-bir)- Bog'langan filtr (
__bilan join) on_delete(o'chirish xatti-harakati)- Amaliy: to'liq bog'langan modellar
ℹ Misollarda Django standalone ORM bilan sinaladi.
2. Nazariya — chuqur tushuntirish
2.1. ForeignKey (bir-ko'p)
ForeignKey — bir-ko'p bog'lanish (bir muallif — ko'p kurs):
class Muallif(models.Model):
ism = models.CharField(max_length=100)
class Kurs(models.Model):
nom = models.CharField(max_length=100)
muallif = models.ForeignKey(Muallif, on_delete=models.CASCADE, related_name="kurslar")| Element | Ma'no |
|---|---|
ForeignKey(Muallif) |
Muallifga havola |
on_delete |
Muallif o'chirilsa nima bo'ladi |
related_name |
Orqaga havola nomi |
ForeignKey — "ko'p" tomonda (har kurs bir muallifga). Bazada muallif_id ustuni (havola). Bir muallif ko'p kursga ega bo'lishi mumkin (bir-ko'p). Bu eng keng tarqalgan bog'lanish.
2.2. Oldinga va orqaga bog'lanish
Bog'langan ma'lumotga ikki yo'nalishda kirish:
# oldinga (kurs → muallif):
kurs.muallif.ism # kursning muallifi
# orqaga (muallif → kurslar):
muallif.kurslar.all() # muallifning kurslari (related_name) Oldinga — ForeignKey yo'nalishida (kurs.muallif). Orqaga — teskari (muallif.kurslar) — related_name bilan. Bir bog'lanish, ikki yo'nalish. Bu ma'lumotni ikki tomondan ko'rish imkonini beradi.
2.3. related_name
related_name — orqaga havola nomi:
muallif = models.ForeignKey(Muallif, on_delete=..., related_name="kurslar")
# orqaga:
ali.kurslar.all() # ali muallifning barcha kurslari
ali.kurslar.filter(narx__gt=100) # filtrlash ham related_name — orqaga so'rov uchun nom (muallif.kurslar). Usiz Django kurs_set ishlatadi (chalkash). Aniq nom (kurslar) — o'qiladigan. Orqaga havola ham QuerySet (filtr, count qo'llanadi).
2.4. ManyToManyField (ko'p-ko'p)
ManyToManyField — ko'p-ko'p (bir kurs ko'p teg, bir teg ko'p kurs):
class Teg(models.Model):
nom = models.CharField(max_length=50)
kurslar = models.ManyToManyField(Kurs, related_name="teglar")
# qo'shish:
teg.kurslar.add(python, go)
# so'rov:
teg.kurslar.all() # tegning kurslari
kurs.teglar.all() # kursning teglari ManyToManyField — har ikki tomon ko'p (kurs↔teg). Django oraliq jadval yaratadi (avtomatik). add/remove bilan bog'lash. Ikki tomondan so'rov (teg.kurslar, kurs.teglar).
2.5. OneToOneField (bir-bir)
OneToOneField — bir-bir (bir foydalanuvchi — bir profil):
class Profil(models.Model):
foydalanuvchi = models.OneToOneField(Foydalanuvchi, on_delete=models.CASCADE)
bio = models.TextField()
foydalanuvchi.profil # bitta profil OneToOneField — bir-bir aloqa (har foydalanuvchi bitta profil). ForeignKeyga o'xshaydi, lekin unique (bir tomon faqat bittaga). Modelni kengaytirish (masalan, Userga qo'shimcha ma'lumot) uchun ishlatiladi.
2.6. Bog'langan filtr (join)
Bog'langan maydon bo'yicha filtr — __ bilan:
# muallif ismi bo'yicha kurslar (join):
Kurs.objects.filter(muallif__ism="Ali")
# muallif kurslari narxi bo'yicha:
Muallif.objects.filter(kurslar__narx__gt=100) __ bog'langan modelga o'tadi (SQL JOIN): muallif__ism — kursning muallifi ismi. Bu bog'langan ma'lumot bo'yicha qidiruv (Python'da join qilmasdan). Chuqur ham mumkin (muallif__mamlakat__nom).
2.7. on_delete (o'chirish xatti-harakati)
on_delete — bog'langan obyekt o'chirilsa nima bo'ladi:
on_delete |
Xatti-harakat |
|---|---|
CASCADE |
Birga o'chiriladi (kurs → izohlar) |
PROTECT |
O'chirishni taqiqlaydi |
SET_NULL |
NULL qiladi (null=True kerak) |
SET_DEFAULT |
Standartga o'rnatadi |
muallif = models.ForeignKey(Muallif, on_delete=models.CASCADE)
# muallif o'chirilsa — uning kurslari ham o'chiriladi on_delete majburiy — bog'langan obyekt o'chirilganda nima bo'lishni belgilaydi. CASCADE (birga o'chirish), PROTECT (himoya), SET_NULL (bo'shatish). To'g'ri tanlov — ma'lumot yaxlitligini saqlaydi.
2.8. Bog'lanishlar — ma'lumot yaxlitligi
| Bog'lanish | Aloqa | Misol |
|---|---|---|
ForeignKey |
Bir-ko'p | Muallif — kurslar |
ManyToManyField |
Ko'p-ko'p | Kurs — teglar |
OneToOneField |
Bir-bir | Foydalanuvchi — profil |
Bog'lanishlar takrorni yo'qotadi (muallif bir joyda, kurslar havola) va yaxlitlikni ta'minlaydi (on_delete, referential integrity). Bu 23-qism (baza dizayni) ning asosi — real dunyo aloqalarini modellash.
3. Tez ma'lumotnoma
from django.db import models
# ForeignKey (bir-ko'p):
class Kurs(models.Model):
muallif = models.ForeignKey(Muallif, on_delete=models.CASCADE, related_name="kurslar")
# ManyToMany (ko'p-ko'p):
class Teg(models.Model):
kurslar = models.ManyToManyField(Kurs, related_name="teglar")
# OneToOne (bir-bir):
class Profil(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
# so'rovlar:
kurs.muallif.ism # oldinga
muallif.kurslar.all() # orqaga (related_name)
Kurs.objects.filter(muallif__ism="Ali") # bog'langan filtr (join)
teg.kurslar.add(kurs) # M2M qo'shishBog'lanishlar
ForeignKey — bir-ko'p · ManyToManyField — ko'p-ko'p · OneToOneField — bir-bir
__ — bog'langan filtr (join) · related_name — orqaga havola4. Batafsil misollar
Misollarda Django standalone ORM bilan sinaladi.
Misol 1 — ForeignKey va oldinga/orqaga
"""ForeignKey (bir-ko'p); oldinga (kurs.muallif); orqaga (muallif.kurslar, related_name); bog'langan filtr (join)."""
import warnings
warnings.filterwarnings("ignore")
import sys
import tempfile
import types
import django
from django.conf import settings
settings.configure(
DEBUG=False,
DATABASES={"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}},
INSTALLED_APPS=["wisar"],
DEFAULT_AUTO_FIELD="django.db.models.BigAutoField",
)
_app = types.ModuleType("wisar")
_app.__path__ = [tempfile.gettempdir()]
sys.modules["wisar"] = _app
django.setup()
from django.db import connection, models
class Muallif(models.Model):
ism = models.CharField(max_length=100)
class Meta:
app_label = "wisar"
def __str__(self):
return self.ism
class Kurs(models.Model):
nom = models.CharField(max_length=100)
narx = models.IntegerField()
muallif = models.ForeignKey(Muallif, on_delete=models.CASCADE, related_name="kurslar")
class Meta:
app_label = "wisar"
def main() -> None:
for m in (Muallif, Kurs):
with connection.schema_editor() as se:
se.create_model(m)
ali = Muallif.objects.create(ism="Ali")
vali = Muallif.objects.create(ism="Vali")
Kurs.objects.create(nom="Python", narx=100, muallif=ali)
Kurs.objects.create(nom="Go", narx=120, muallif=ali)
Kurs.objects.create(nom="Rust", narx=150, muallif=vali)
print("=== 1. Oldinga (kurs → muallif) ===")
py = Kurs.objects.get(nom="Python")
print(f" Python kursi muallifi: {py.muallif.ism}")
print("\n=== 2. Orqaga (muallif → kurslar) ===")
print(f" Ali kurslari: {list(ali.kurslar.values_list('nom', flat=True))}")
print("\n=== 3. Orqaga + filtr ===")
print(f" Ali qimmat (>100) kurslari: {list(ali.kurslar.filter(narx__gt=100).values_list('nom', flat=True))}")
print("\n=== 4. Bog'langan filtr (join) ===")
print(f" muallif__ism='Ali': {list(Kurs.objects.filter(muallif__ism='Ali').values_list('nom', flat=True))}")
print(" ⭐ ForeignKey — oldinga (kurs.muallif), orqaga (muallif.kurslar)")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Oldinga (kurs → muallif) ===
Python kursi muallifi: Ali
=== 2. Orqaga (muallif → kurslar) ===
Ali kurslari: ['Python', 'Go']
=== 3. Orqaga + filtr ===
Ali qimmat (>100) kurslari: ['Go']
=== 4. Bog'langan filtr (join) ===
muallif__ism='Ali': ['Python', 'Go']
⭐ ForeignKey — oldinga (kurs.muallif), orqaga (muallif.kurslar)Nima ko'rsatdi: 2.1, 2.2, 2.3, 2.6-bo'limlar.
Misol 2 — ManyToManyField
"""ManyToManyField (ko'p-ko'p); add bilan bog'lash; ikki tomondan so'rov; oraliq jadval."""
import warnings
warnings.filterwarnings("ignore")
import sys
import tempfile
import types
import django
from django.conf import settings
settings.configure(
DEBUG=False,
DATABASES={"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}},
INSTALLED_APPS=["wisar"],
DEFAULT_AUTO_FIELD="django.db.models.BigAutoField",
)
_app = types.ModuleType("wisar")
_app.__path__ = [tempfile.gettempdir()]
sys.modules["wisar"] = _app
django.setup()
from django.db import connection, models
class Kurs(models.Model):
nom = models.CharField(max_length=100)
class Meta:
app_label = "wisar"
class Teg(models.Model):
nom = models.CharField(max_length=50)
kurslar = models.ManyToManyField(Kurs, related_name="teglar")
class Meta:
app_label = "wisar"
def main() -> None:
for m in (Kurs, Teg):
with connection.schema_editor() as se:
se.create_model(m)
py = Kurs.objects.create(nom="Python")
go = Kurs.objects.create(nom="Go")
rust = Kurs.objects.create(nom="Rust")
backend = Teg.objects.create(nom="backend")
tez = Teg.objects.create(nom="tez")
backend.kurslar.add(py, go, rust) # 3 kurs
tez.kurslar.add(go, rust) # 2 kurs
py.teglar.add(tez) # boshqa tomondan ham
print("=== 1. Teg → kurslar (oldinga) ===")
print(f" 'backend' teg kurslari: {sorted(backend.kurslar.values_list('nom', flat=True))}")
print("\n=== 2. Kurs → teglar (orqaga) ===")
print(f" Go teglari: {sorted(go.teglar.values_list('nom', flat=True))}")
print(f" Python teglari: {sorted(py.teglar.values_list('nom', flat=True))}")
print("\n=== 3. Ko'p-ko'p aloqa ===")
print(f" 'tez' teg kurslari: {sorted(tez.kurslar.values_list('nom', flat=True))}")
print("\n=== 4. Bog'langan filtr (M2M join) ===")
natija = Kurs.objects.filter(teglar__nom="tez")
print(f" 'tez' tegli kurslar: {sorted(natija.values_list('nom', flat=True))}")
print(" ⭐ ManyToManyField — ko'p-ko'p; add bilan bog'lash; ikki tomondan")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Teg → kurslar (oldinga) ===
'backend' teg kurslari: ['Go', 'Python', 'Rust']
=== 2. Kurs → teglar (orqaga) ===
Go teglari: ['backend', 'tez']
Python teglari: ['backend', 'tez']
=== 3. Ko'p-ko'p aloqa ===
'tez' teg kurslari: ['Go', 'Python', 'Rust']
=== 4. Bog'langan filtr (M2M join) ===
'tez' tegli kurslar: ['Go', 'Python', 'Rust']
⭐ ManyToManyField — ko'p-ko'p; add bilan bog'lash; ikki tomondanNima ko'rsatdi: 2.4-bo'lim.
Misol 3 — OneToOneField va on_delete
"""OneToOneField (bir-bir); modelni kengaytirish; on_delete=CASCADE (birga o'chirish); yaxlitlik."""
import warnings
warnings.filterwarnings("ignore")
import sys
import tempfile
import types
import django
from django.conf import settings
settings.configure(
DEBUG=False,
DATABASES={"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}},
INSTALLED_APPS=["wisar"],
DEFAULT_AUTO_FIELD="django.db.models.BigAutoField",
)
_app = types.ModuleType("wisar")
_app.__path__ = [tempfile.gettempdir()]
sys.modules["wisar"] = _app
django.setup()
from django.db import connection, models
class Foydalanuvchi(models.Model):
ism = models.CharField(max_length=100)
class Meta:
app_label = "wisar"
class Profil(models.Model):
foydalanuvchi = models.OneToOneField(Foydalanuvchi, on_delete=models.CASCADE, related_name="profil")
bio = models.TextField(default="")
class Meta:
app_label = "wisar"
class Izoh(models.Model):
matn = models.CharField(max_length=200)
muallif = models.ForeignKey(Foydalanuvchi, on_delete=models.CASCADE, related_name="izohlar")
class Meta:
app_label = "wisar"
def main() -> None:
for m in (Foydalanuvchi, Profil, Izoh):
with connection.schema_editor() as se:
se.create_model(m)
ali = Foydalanuvchi.objects.create(ism="Ali")
Profil.objects.create(foydalanuvchi=ali, bio="Python dasturchi")
Izoh.objects.create(matn="Zo'r!", muallif=ali)
Izoh.objects.create(matn="Rahmat", muallif=ali)
print("=== 1. OneToOne (bir-bir) ===")
print(f" Ali profili bio: {ali.profil.bio}")
print("\n=== 2. Profildan foydalanuvchiga ===")
profil = Profil.objects.first()
print(f" profil egasi: {profil.foydalanuvchi.ism}")
print("\n=== 3. Foydalanuvchi izohlari (FK orqaga) ===")
print(f" Ali izohlari: {list(ali.izohlar.values_list('matn', flat=True))}")
print("\n=== 4. ⚠️ on_delete=CASCADE ===")
print(f" o'chirishdan oldin: profil={Profil.objects.count()}, izoh={Izoh.objects.count()}")
ali.delete()
print(f" Ali o'chirilgach: profil={Profil.objects.count()}, izoh={Izoh.objects.count()} (birga o'chdi)")
print(" ⭐ OneToOne — bir-bir (kengaytirish); on_delete — yaxlitlik")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. OneToOne (bir-bir) ===
Ali profili bio: Python dasturchi
=== 2. Profildan foydalanuvchiga ===
profil egasi: Ali
=== 3. Foydalanuvchi izohlari (FK orqaga) ===
Ali izohlari: ["Zo'r!", 'Rahmat']
=== 4. ⚠️ on_delete=CASCADE ===
o'chirishdan oldin: profil=1, izoh=2
Ali o'chirilgach: profil=0, izoh=0 (birga o'chdi)
⭐ OneToOne — bir-bir (kengaytirish); on_delete — yaxlitlikNima ko'rsatdi: 2.5, 2.7-bo'limlar.
Misol 4 — Amaliy: to'liq bog'langan modellar
Real ilova modellarini bog'lanishlar bilan quramiz: muallif, kurs (FK), teg (M2M) va bog'langan so'rovlar, agregatlar. Bu — Django ma'lumot modelining namunasi.
"""to'liq bog'langan modellar: muallif-kurs (FK), kurs-teg (M2M); bog'langan filtr, annotate; real model."""
import warnings
warnings.filterwarnings("ignore")
import sys
import tempfile
import types
import django
from django.conf import settings
settings.configure(
DEBUG=False,
DATABASES={"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}},
INSTALLED_APPS=["wisar"],
DEFAULT_AUTO_FIELD="django.db.models.BigAutoField",
)
_app = types.ModuleType("wisar")
_app.__path__ = [tempfile.gettempdir()]
sys.modules["wisar"] = _app
django.setup()
from django.db import connection, models
from django.db.models import Count
class Muallif(models.Model):
ism = models.CharField(max_length=100)
class Meta:
app_label = "wisar"
class Kurs(models.Model):
nom = models.CharField(max_length=100)
narx = models.IntegerField()
muallif = models.ForeignKey(Muallif, on_delete=models.CASCADE, related_name="kurslar")
class Meta:
app_label = "wisar"
class Teg(models.Model):
nom = models.CharField(max_length=50)
kurslar = models.ManyToManyField(Kurs, related_name="teglar")
class Meta:
app_label = "wisar"
def main() -> None:
for m in (Muallif, Kurs, Teg):
with connection.schema_editor() as se:
se.create_model(m)
ali = Muallif.objects.create(ism="Ali")
vali = Muallif.objects.create(ism="Vali")
py = Kurs.objects.create(nom="Python", narx=100, muallif=ali)
go = Kurs.objects.create(nom="Go", narx=120, muallif=ali)
rust = Kurs.objects.create(nom="Rust", narx=150, muallif=vali)
backend = Teg.objects.create(nom="backend")
backend.kurslar.add(py, go, rust)
print("=== 1. FK: muallif kurslari ===")
print(f" Ali kurslari: {list(ali.kurslar.values_list('nom', flat=True))}")
print("\n=== 2. M2M: teg kurslari ===")
print(f" 'backend' kurslari: {sorted(backend.kurslar.values_list('nom', flat=True))}")
print("\n=== 3. Bog'langan filtr (chuqur join) ===")
natija = Kurs.objects.filter(muallif__ism="Ali", teglar__nom="backend")
print(f" Ali + backend: {sorted(natija.values_list('nom', flat=True))}")
print("\n=== 4. Annotate (har muallif kurslari soni) ===")
stat = Muallif.objects.annotate(soni=Count("kurslar")).order_by("ism")
print(f" {list(stat.values_list('ism', 'soni'))}")
print(" ⭐ FK + M2M + bog'langan filtr + annotate — to'liq model")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. FK: muallif kurslari ===
Ali kurslari: ['Python', 'Go']
=== 2. M2M: teg kurslari ===
'backend' kurslari: ['Go', 'Python', 'Rust']
=== 3. Bog'langan filtr (chuqur join) ===
Ali + backend: ['Go', 'Python']
=== 4. Annotate (har muallif kurslari soni) ===
[('Ali', 2), ('Vali', 1)]
⭐ FK + M2M + bog'langan filtr + annotate — to'liq modelNima ko'rsatdi: 2.1–2.8-bo'limlar.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
| "Ma'lumotni takrorlab saqlash" | Bog'lanish (havola) |
"ForeignKey — ikki tomonda" |
"Ko'p" tomonda (kurs) |
| "Orqaga so'rov yo'q" | related_name |
| "Ko'p-ko'p qo'lda jadval" | ManyToManyField |
| "Bog'langan filtr Python'da" | __ (join) |
"on_delete ixtiyoriy" |
Majburiy (FK) |
"OneToOne = ForeignKey" |
Bir-bir (unique) |
| "Bog'langan ma'lumot alohida so'rov" | select_related (optimizatsiya) |
6. Keng tarqalgan xatolar va yechimlari
1. Ma'lumotni takrorlash (bog'lanish o'rniga)
class Kurs:
muallif_ism = models.CharField(...) # ⚠️ takror, nomuvofiq
muallif = models.ForeignKey(Muallif, ...) # ✅ havola2. on_delete unutish
muallif = models.ForeignKey(Muallif) # ❌ on_delete kerak
muallif = models.ForeignKey(Muallif, on_delete=models.CASCADE) # ✅3. related_namesiz chalkash orqaga
muallif = models.ForeignKey(Muallif, on_delete=...) # muallif.kurs_set
related_name="kurslar" # ✅ muallif.kurslar4. Bog'langan ma'lumotni Python'da join
[k for k in Kurs.objects.all() if k.muallif.ism == "Ali"] # ⚠️
Kurs.objects.filter(muallif__ism="Ali") # ✅ join5. M2M'ga = bilan qo'shish
teg.kurslar = [py, go] # ❌ ishlamaydi
teg.kurslar.add(py, go) # ✅6. N+1 so'rov (bog'lanishda)
for k in Kurs.objects.all(): print(k.muallif.ism) # ⚠️ har kurs +1 so'rov
Kurs.objects.select_related("muallif") # ✅ bir so'rov (23.9)7. OneToOne o'rniga ForeignKey
profil = models.ForeignKey(User, ...) # ⚠️ ko'p profil mumkin
profil = models.OneToOneField(User, ...) # ✅ bitta7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 21.9-dars (o'tilgan): ORM so'rovlar — bog'langan filtr
- 21.3-dars (o'tilgan): model — bog'lanish maydonlari
- 23.2-dars: SQL JOIN — bog'lanish asosi
- 23.9-dars: N+1 —
select_related,prefetch_related - 23.12-dars: baza dizayni — aloqalar
8. Eng yaxshi amaliyotlar
Ma'lumotni takrorlamang — bog'lanish (havola) ishlating.
ForeignKeydaon_deletebering (majburiy).related_namebilan aniq orqaga havola.Ko'p-ko'p uchun
ManyToManyField(qo'lda jadval emas).Bog'langan filtr uchun
__(Python'da join emas).Bir-bir uchun
OneToOneField(kengaytirish).N+1 uchun
select_related/prefetch_related23.9-bob.on_deleteni to'g'ri tanlang (CASCADE/PROTECT/SET_NULL).
9. Amaliy topshiriq
Vazifa 1: Bashorat qiling
1. # ForeignKey nima?
2. # ForeignKey qaysi tomonda?
3. # oldinga bog'lanish nima?
4. # orqaga bog'lanish nima?
5. # related_name nima?
6. # ManyToManyField nima?
7. # OneToOneField nima?
8. # __ (join) nima?
9. # on_delete nima?
10. # CASCADE nima qiladi?
11. # M2M qanday qo'shiladi?
12. # takror yoki bog'lanish?Javoblar
- Bir-ko'p bog'lanish (havola)
- "Ko'p" tomonda (kurs → muallif)
- FK yo'nalishi (
kurs.muallif) - Teskari (
muallif.kurslar) - Orqaga havola nomi
- Ko'p-ko'p bog'lanish
- Bir-bir bog'lanish (unique)
- Bog'langan filtr (SQL JOIN)
- Bog'langan obyekt o'chirilganda nima bo'ladi
- Birga o'chiradi (bog'langanlar)
.add(...)bilan- Bog'lanish (takror — nomuvofiq)
Vazifa 2: Xatolarni tuzating
1. muallif_ism = models.CharField(...) # takror
2. muallif = models.ForeignKey(Muallif) # on_delete
3. [k for k in ... if k.muallif.ism=="Ali"] # join
4. teg.kurslar = [py, go] # M2M
5. profil = models.ForeignKey(User, ...) # bir-birJavoblar
1. muallif = models.ForeignKey(Muallif, on_delete=models.CASCADE)
2. muallif = models.ForeignKey(Muallif, on_delete=models.CASCADE)
3. Kurs.objects.filter(muallif__ism="Ali")
4. teg.kurslar.add(py, go)
5. profil = models.OneToOneField(User, on_delete=models.CASCADE)Vazifa 3: Blog modellari
Blog bog'lanishlari:
Muallif—Maqola(FK)Maqola—Teg(M2M)Maqola—Izoh(FK)- Bog'langan so'rovlar test
Vazifa 4: Oldinga/orqaga
Bog'langan so'rovlar:
- Oldinga (
maqola.muallif) - Orqaga (
muallif.maqolalar) - Orqaga + filtr
- Har birini test
Vazifa 5: Ko'p-ko'p
M2M tizimi:
Talaba—Kurs(M2M)add/remove- Ikki tomondan so'rov
- Bog'langan filtr
Vazifa 6: on_delete xatti-harakatlari
on_delete variantlari:
CASCADE,PROTECT,SET_NULL- Har biri uchun holat
- O'chirishni test
- Yaxlitlik tahlili
Vazifa 7: O'ylash
Bog'lanishlar ma'lumotni bir marta saqlash imkonini beradi: muallif bir joyda (alohida jadval), kurslar unga havola (ForeignKey). Bu takrorni (har kursda muallif ismi) va nomuvofiqlikni (muallif o'zgarsa, bir joy unutiladi) yo'qotadi — bu ma'lumot bazasidagi "normalizatsiya" tamoyili. Ma'lumotni bir joyda saqlab, havola bilan bog'lashning afzalligi nima, va bu "takrorni yo'qotish" (DRY) tamoyili ma'lumot modelida qanday muhim?
Javob
Qisqa javob: Bog'lanishlar ma'lumotni bir marta saqlaydi: muallif alohida jadvalda, kurslar unga havola (muallif_id). Bu "normalizatsiya" — takrorlangan ma'lumotni (har kursda muallif ismi) bir joyga yig'ish. Afzalligi: izchillik (muallif bir joyda — o'zgarish bir joyda, hamma kursda aks etadi), kam joy (takror yo'q), yaxlitlik (on_delete bilan bog'langan ma'lumot boshqariladi). Takrorlangan ma'lumot (denormalizatsiya) — nomuvofiqlik xavfi (bir joy yangilanadi, boshqasi unutiladi). "Takrorni yo'qotish" (DRY) ma'lumot modelida ayniqsa muhim, chunki nomuvofiq ma'lumot — ishonchsiz tizim.
1. Normalizatsiya (bir marta saqlash)
| Takror (yomon) | Bog'lanish (yaxshi) |
|---|---|
| Har kursda muallif ismi | Muallif alohida jadval |
| O'zgarish ko'p joyda | O'zgarish bir joyda |
| Nomuvofiq xavfi | Izchil |
2. Afzalliklar
| Afzallik | Sabab |
|---|---|
| Izchillik | Ma'lumot bir joyda |
| Kam joy | Takror yo'q |
| Yaxlitlik | on_delete, havola |
| Saqlash | O'zgarish bir joyda |
3. Nomuvofiqlik xavfi (takror)
Muallif ismi 100 kursda takrorlansa — muallif ismi o'zgarsa, 100 joyni yangilash kerak. Biror joy unutilsa — nomuvofiq (bir kursda eski ism). Bog'lanishda — bir joy (muallif jadvali).
4. "Takrorni yo'qotish" boshqa joyda
| Soha | DRY |
|---|---|
| Ma'lumot | Normalizatsiya (bog'lanish) |
| Kod | Funksiya (takror yo'q) |
| URL | reverse (21.6) |
| Konstanta | Bir joyda e'lon |
5. Muhandislik saboqlari
- Ma'lumotni bir marta saqla (bog'lanish)
- Takror — nomuvofiqlik xavfi
- Normalizatsiya — izchil, yaxlit ma'lumot
- DRY — ma'lumot modelida ham (kod kabi)
6. Xulosa
- Bog'lanish — ma'lumot bir joyda (havola)
- Normalizatsiya — takrorni yo'qotish
- Izchillik, yaxlitlik, kam joy
- DRY — ma'lumot modelida muhim
Nimani mustahkamlaydi: 2.1–2.8-bo'limlar.
Xulosa
Bu darsda Django ORM bog'lanishlarini o'rgandik.
Eng muhim uch fikr:
ForeignKey(bir-ko'p).ForeignKey— eng keng tarqalgan bog'lanish (bir muallif — ko'p kurs); u "ko'p" tomonda (kurs) e'lon qilinadi, bazadamuallif_idhavola ustuni yaratadi. Ma'lumotga ikki yo'nalishda kirish: oldinga (kurs.muallif— kursning muallifi), orqaga (muallif.kurslar—related_namebilan). Orqaga havola ham QuerySet (filtr, count qo'llanadi). Bu ma'lumotni takrorlamasdan bog'langan saqlaydi.ManyToManyFieldvaOneToOneField.ManyToManyField— ko'p-ko'p (kurs↔teg): Django avtomatik oraliq jadval yaratadi,add/removebilan bog'lanadi, ikki tomondan so'rov (teg.kurslar,kurs.teglar).OneToOneField— bir-bir (foydalanuvchi — profil, unique): modelni kengaytirish uchun.on_delete(ForeignKey/OneToOneda majburiy) — bog'langan obyekt o'chirilganda nima bo'lishni belgilaydi:CASCADE(birga o'chirish),PROTECT(himoya),SET_NULL(bo'shatish).Bog'langan filtr va yaxlitlik. Bog'langan maydon bo'yicha filtr
__bilan (SQL JOIN):muallif__ism="Ali"— kursning muallifi ismi bo'yicha (Python'da join qilmasdan, chuqur ham mumkin). Bog'lanishlar takrorni yo'qotadi (muallif bir joyda, kurslar havola) va yaxlitlikni ta'minlaydi — bu "normalizatsiya" tamoyili: ma'lumotni bir marta saqlab, havola bilan bog'lash. Takror — nomuvofiqlik xavfi; bog'lanish — izchil, yaxlit ma'lumot (DRY ma'lumot modelida).
Keyingi darsda autentifikatsiya tizimi ni o'rganamiz: Django'ning tayyor User modeli, kirish/chiqish, parol boshqaruvi va ruxsatlar (permissions).
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!