İçeriğe geç

Django ORM Model İlişkileri

Django ilişkisel veritabanlari(PostgreSql,Mysql vb) ile çalışır ve modelleriniz arasında ilişkiler kurarak istediğiniz veriye ulaşmanızda size fazlasıyla yardımcı olabilir.

Kısacası ilişkilendirdiğiniz modeller ile ilişki kurduğunuz modellerden türettiğiniz nesnelerin verilerine derli toplu ve kolay bir biçimde ulaşmanızı sağlar. Bütün mantık bu.

Kurabileceğiniz İlişkiler

  • One to One
  • Many to one
  • Many to many

One to One

Elimizde Kullanıcı, Notebook olmak üzere 2 model bulunacak.

Senaryo : 

  • Bir notebookun yalnızca bir sahibi olabilir.
  • Bir kullanıcının sadece bir notebook’u olabilir.

Modellerimizi tanımlayarak başlayalım.

from django.db import models

class Owner(models.Model):
    first_name = models.CharField(max_length=20)
    last_name = models.CharField(max_length=20)

    def __str__(self):
        return f"{self.first_name} {self.last_name}"

class Notebook(models.Model):
    owner = models.OneToOneField(Owner, on_delete=models.CASCADE)
    brand = models.CharField(max_length=20)
    model = models.CharField(max_length=20)

    def __str__(self):
        return f"The owner of the {self.brand} {self.model} {self.owner}"

Daha sonra iki adet kullanıcı  oluşturalım ve kaydedelim.

owner = Owner(first_name="Egehan",last_name="Gundogdu")
owner2 = Owner(first_name="Alan",last_name="Walker")
owner1.save(),owner2.save()

İki adet de notebook oluşturalım ve kaydedelim.

notebook = Notebook(owner=owner,brand="Lenovo",model="Thinkpad X250")
notebook2 = Notebook(owner=owner2,brand="Apple",model="Macbook Pro")
notebook.save(), notebook2.save()

Yukarıda 2 adet kullanıcı oluşturduktan sonra dikkat ettiyseniz oluşturduğumuz nesneleri sırasıyla notebook nesnelerinin kullanıcısına ilişkilendirdik.

notebook
//<Notebook: The owner of the Lenovo Thinkpad X250 Egehan Gundogdu>
notebook.owner
// <Owner: Egehan Gundogdu>
notebook.owner.id
// 1

Bu gibi kullanımlar ile tanımladığınız modeldeki field ve method’lara ulaşabilirsiniz.

İlişkilendirilen modellerden türetilen nesneler ile veritabanıza sorgular atabilirsiniz.

owner = Owner.objects.get(id=1)
nt = Notebook.objects.get(owner=owner)
nt
<Notebook: The owner of the Lenovo Thinkpad X250 Egehan Gundogdu>

Fakat kurduğunuz ilişkinin mantığını unutmamalısınız ki hatalar ile karşılaşmayın. Senaryo kısmındada yazdığı üzere her notebook sadece bir kullanıcıya bir kullanıcı da sadece bir notebook’a sahip olabilir. Bu yüzden halihazırda bir notebooku olan bir kullanıcıya yeni bir notebook tanımlamaya çalışırsanız hata alırsınız.

notebook = Notebook.objects.get(id=1)
owner =Owner.objects.get(id=2)
notebook.owner = owner
notebook.save()
//integrity error

Many to One

Makale ve Yazar olmak üzere 2 modelimiz bulunacak.

Senaryo:

  • Bir yazar birden fazla makale yazabilir.
  • Bir makale yalnızca bir yazar tarafından yazılabilir.

Herhalde dünyada en fazla tanımlanan iki Django modelini sorsalar direkt söyleceğim modeller bunlar olur. (Acaba neden?  🙂 ) Hızlıca modelleri tanımlayalım.

class Author(models.Model):
    first_name = models.CharField(max_length=20)
    last_name = models.CharField(max_length=20)

    def __str__(self):
        return f"{self.first_name} {self.last_name}"
    
class Article(models.Model):
    header = models.CharField(max_length=40)
    content = models.TextField(max_length=600)
    publish_date = models.DateTimeField(auto_now_add=True)
    author = models.ForeignKey(Author,on_delete=models.CASCADE,related_name='articles')
    
    def __str__(self):
        return self.header

Hızlıca bir kaç nesne oluşturuyorum.

author = Author.objects.create(first_name="Egehan",last_name="Gundogdu")
author1 = Author.objects.create(first_name="Alan",last_name="Walker")
article = Article.objects.create(header="Django",content="Django ORM",author=author)
article1 = Article.objects.create(header="Flask",content="Flask Templates",author=author)
article1
//<Article: Flask>

İlk oluşturduğum yazara iki adet makale atadım. Kullanıcı makalelerine ulaşmak için.

author.articles.all()
//<QuerySet [<Article: Django>, <Article: Flask>]>

Burada related_name değişkenini kullanıyoruz. Bunun sebebi benim yazar üstünden sorgulamalarımda ‘articles’ keywordü ile makalelere ulaşmak istemem. Örnek olarak.

author.articles.count()
// 2
author1.articles.count()
// 0

Bir makalenin yazarını takaslamak istersek.

author1.articles.add(article)
author.articles.count()
//1
author1.articles.count()
//1

Makale modeline author nesnesi üzerinden sorgu işlemleri. ( Author pk)

articles= Article.objects.filter(author__pk=1)
articles
//<QuerySet [<Article: Django>]>

Author first name.

articles = Article.objects.filter(author__first_name="Egehan")
articles
<QuerySet [<Article: Django>]>

Yazar modeline makale nesnesi üzerinden sorgular.

article_dump = Author.objects.filter(articles__header__startswith='Django')
// <QuerySet [<Author: Egehan Gundogdu>]>
article_dump.delete()
author.articles.all()
//<QuerySet []>

Örnekler çoğaltılabilir. Bir çok farklı sorgu Django birbirine zincir şeklinde bağlanarak kullanılabilir.

Many to Many

Elimizde Makale ve Kategori adında 2 model bulunacak.

Senaryo:

  • Bir makale birden fazla kategoriye ait olabilir.
  • Bir kategori birden fazla makaleyi kapsayabilir.

Modellerimizi yazalım.

class Category(models.Model):
    name = models.CharField(max_length=20)
    def __str__(self):
        return self.name

class Articles(models.Model):
    header = models.CharField(max_length=40)
    content = models.TextField(max_length=600)
    category = models.ManyToManyField(Category,related_name='articles') #reverse relation
    def __str__(self):
        return self.header

Diğer ilişkilerden farklı olarak burada da  iki modelimiz var fakat oluşacak tablo sayımız üç. Üçüncü tablo bir ara tablo görevi ise ilişkilendirilen kategori ve makaleler birden fazla olabileceği için kategori_id ve makale_id lerini tutmak.

Bir kaç kategori oluşturalım.

cat = Category.objects.create(name="Tech")
cat1 = Category.objects.create(name="Development")
cat2 = Category.objects.create(name="Web")

Ardından bir makale oluşturalım.

article = Articles.objects.create(header="Django Web Framework",content="Django web")

Kategorilerimizde ekleyelim. Fakat hatırlarsanız ForeignKey kullanarak oluşturduğumuz ilişkilerde related_name değişkeni ile many olarak belirlediğimiz nesnelere erişiyorduk. Burada ilişkilendirilen iki tarafta many. related_name değişkenini bu sefer ters ilişki sorgusu yapmak için kullanacağız. Az sonra anlayacaksınız devam edelim 🙂

article.category.add(cat,cat1,cat2)
article.category.all()
// <QuerySet [<Category: Tech>, <Category: Development>, <Category: Web>]>

Kategoriler eklendi. Fakat nasıl eriştiğimize dikkat edin lütfen.

Ters ilişki sorgusu.

new_article = Articles.objects.create(header="Flask",content="Minimalist Python Web Framework")
new_article.category.add(cat1,cat2)
cat1.articles.all()
// <QuerySet [<Articles: Django Web Framework>, <Articles: Flask>]>

Zincir sorgular.

cat1.articles.get(header__startswith="Flask").header
'Flask'
cat1.articles.get(header__startswith="Flask").content.islower()
//False
cat1.articles.get(header__startswith="Flask").header.count("f")
// 0

Tamam gözüküyor.

ÖZET

Doğru IR diyagramları ile Django’da veritabanınızı modellemek gördüğünüz gibi çok kolay. Sadece neyi nerede ne şekilde tutacağınızı iyi planlamanız gerek gerisini Django hallediyor.

Daha ayrıntılı bilgi almak isteyenler için buraya link bırakıyorum.

Kolay gelsin 🙂

 

 

 

 

Tarih:BlogPython

Tek Yorum

  1. Kardeşim eline emeğine sağlık teşekkür ediyorum.

    category = models.ManyToManyField(Category,related_name=’articles’)

    Bu satırın kullanılmasının ne gereği var? ben bu satırı kullanmadan ara tabloyu oluşturup many to many veri yapısını kullanabiliyorum. Bu satırı neden kullanmalıyım?

Bir cevap yazın

E-posta hesabınız yayımlanmayacak.

Göster
Gizle