Django ORM ile çoklu ilişki kurmak ve veri çekmek


#1

Arkadaşlar kolay gelsin,
Django ile geliştirdiğim projemde bir konuda fena takıldım bir kaç gündür üzerine düşünüyorum ancak artık sizlere danışma vaktim geldi sanırım.

Durumu şöyle izah etmeye çalışayım, bir kullanıcının okuduğu kitapların sayfa sayılarını tuttuğum tablom var, kitap bilgileri için ayrı bir tablom var, kitap türlerini tuttuğum ayrı bir tablom var(ayrı derken kitap ve tür arasında manytomany ilişki var). Kitap tablosunda sadece kendi id’leri var, okumaları tuttuğum tabloda kullanici_id ve kitap_id yani foreginkey ile bir ilişki var. Şimdi kullanıcının profil sayfasında okuduğu kitapların bilgilerini, türünü, sayfa sayılarını listeletmek istiyorum. Kullanıcı profil sayfasına giderken id gönderdiğim için okuma tablosundaki kullanici_id’yi kullanarak kitap_id, sayfa _numarasi vs. alabiliyorum ancak bundan sonra işler karışıyor. Geri kalanında kitapları ve türleri listeletmek için önce okuma listesini döngüye sokup kitap_id yi almalıyım sonra onu kitap tablosuna gönderip eşleştirmeli bilgileri çekmeliyim ve türler tablosu içinde benzer bişey yapmalıyım ki buna yakın bişeyler denedim ancak pek işe yaramadı, sadece son kayıtları aldım vs. ben bunun djangoda daha kolay olduğunu düşünüyorum ama nasıl bir yapı kurmam gerektiğini kavrayamadım hatta şu linkte istediğime yakın birşeylerden bahsedilmiş ancak çözemedim. Eğer django ORM yapılarına hakim birileri konuyu yeşillendirirse çok memnun olurum. Herkese iyi çalışmalar.


#2

İlginç bir şekilde buraya konu açtıktan sonra sorunu çözdüm :grinning: sorunun çözümünü ayrıntılı bir şekilde yazacağım başka arkadaşlar yaşayabilir diye ancak şimdi başka bir sorun var gelen türleri template kısmında kitaplarla eşleştirerek göstermem gerekiyor ancak aralarında doğrudan bir id veya başka türlü ilişki yok. :confused:


#3

Eğer böyle sorunlar yaşıyorsanız tablo yapınızda bir sorun vardır; öncelikle bunun üzerinde çalışmanız gerek. Öncelikle bir kağıda çizmek işinizi kolaylaştırabilir. Bence ilk başta kitap diye bir tablo oluşturun ve alanlarını yazın. Eğer birden fazla alan kendileri bir bütün oluşturuyorsa bunu ayrı bir tablo yapın. Gerekli ilişkiyi de doğru kurduğunuza emin olun. Ayrıca her tablo bir ID alanına sahip olsun. Django ORM konusunda yardımcı olamıyorum ancak tabloları ve ilişkileri doğru oluşturduktan sonra Django ORM ihtiyacınız olan her şeyi size kendiliğinden sağlayacaktır.


#4

Evet haklısınız hocam ancak mantık olarak düşündüğümde örneğin yapmak istediğim şey için konuşursak ben kullanıcı profil sayfasında okuduğu kitabın sayfa sayısını, kitap bilgilerini, tür bilgisini, yazar bilgisini göstermek istiyorum diyelim. İlişkilerim şu şekilde,

Bu şemaya göre benim bir kullanıcının okuduğu kitabın bilgilerini, türünü, yazarını çekmek için izlediğim yol kullanıcıyı kitapokuma tablosunda eşleştirip karşısındaki kitap idlerini getirmek sonrasında bunları kitap tablosuna göndermek kitapları çekmek. Bu noktada ORM ile kolayca halledebiliyorum. Sıkıntı kitap tablosuna bağlı olan tür ve yazar ilişkisini çekmeye çalıştığımda kitap bazlı sorgularsam kullanıcı ilişkisini kuramıyorum.

Aslında daha önce kitap tablosuna da bir kullanıcı id koymak aklıma geldi ancak bunun verimsiz olacağını düşündüm. Bu şekilde tekrar bir değerlendirip yardımcı olursanız sevinirim hocam, iyi çalışmalar.


#5

Bence de bu doğru bir yol değil.

Siz belirli bir kitabı okuyan kullanıcıları almak istiyorsunuz, değil mi? “Kitap_kitapokuma” tablosundan bu bilgileri alabilirsiniz sanki.

Tablo yapınızın hepsini göremediğim bu konuda bir yorum yapamıyorum ancak gördüğüm kadarıyla iyi; ben de olsam böyle yapardım heralde. Daha iyi nasıl yapılabilir, bilmiyorum. Bu konuda daha tecrübeli arkadaşlar hem tablo yapısı hem de sorunuza daha iyi cevaplar verebilir.


#6

kitap tur yardımcı tablolar
bir tane master kitap tablosu olacak
bu mastera bağlı kitap_okuma_slave tablosu olacak
masterda kullanıcı id kolonu olacak
user > id = user_id master_kitap
master_kitap > id= kitap_id> slave_kitap
üç tabloyu birbirine join ettiginizde istedigniz sonuca ulaşabilirsiniz
auth.id = kitap.user_id
kitap.id = kitap_okuma.kitap_id


#7

Arkadaşlar birçok referansı inceledim ve artık gittiğim yolun doğru olduğuna nerdeyse şüphem kalmadı sadece neden çalışmadığına bir türlü anlam veremiyorum. Normalde benim getirmek istediğim nesneler için yazmam gereken kod şu

KitapOkuma.objects.select_related('kitap').prefetch_related('kitap__tur').filter(kullanici_id = pk)

Bu sorgunun çıktısı şu şekilde

SELECT "Kitap_kitapokuma"."id", "Kitap_kitapokuma"."sayfa_numarasi", "Kitap_kitapokuma"."aciklama", "Kitap_kitapokuma"."kitap_id", "Kitap_kitapokuma"."kullanici_id", "Kitap_kitapokuma"."oku
nma_tarihi", "Kitap_kitapokuma"."kayit_zamani", "Kitap_kitap"."id", "Kitap_kitap"."adi", "Kitap_kitap"."alt_baslik", "Kitap_kitap"."ISBN", "Kitap_kitap"."sayfa_sayisi", "Kitap_kitap"."acikl
ama", "Kitap_kitap"."kayit_zamani" FROM "Kitap_kitapokuma" INNER JOIN "Kitap_kitap" ON ("Kitap_kitapokuma"."kitap_id" = "Kitap_kitap"."id") WHERE "Kitap_kitapokuma"."kullanici_id" = 1

ama benim beklediğim tür bilgisi burada yok. Normalde baktığım referansların çoğunda aynen benim kurduğum türdeki ilişkinin sorgusunu bu şekilde tanımlamışlar. Nerde yanlış yapıyorum :thinking:

bazı yerlerde prefetch_related’ın filter ile kullanılamadığı yazmış o yüzden query’i şu şekilde değiştirdim fakat sonuç yine aynı

>>> KitapOkuma.objects.select_related('kitap').filter(kullanici_id = pk).prefetch_related('kitap__tur').all()

#8

Arkadaşlar istediğim şeyi farklı bir yollada olsa sonunda yaptım. Yukarıdaki kod veya benzeri kodların neden istediğim sonucu vermediğini henüz çözebilmiş değilim o yüzden bu konuda aydınlatılmaya hâla ihtiyacım var. Diğer taraftan kodlar aşağıdaki gibidir,

class KullaniciProfil(LoginRequiredMixin, TemplateView):
	model = KitapOkuma()
	template_name = 'Profil/kullanici_profil.html'

def get_context_data(self, **kwargs):
	context = super().get_context_data(**kwargs)
	context['kullanici'] = User.objects.filter(id = self.request.user.pk)
	context['okunan_kitap'] = self.okuma_list()
	return context

def okuma_list(self):
	okuma_qs = KitapOkuma.objects.select_related('kitap').filter(kullanici_id = self.request.user).order_by('-okunma_tarihi')

	okunanlar = []

	for okunan in okuma_qs:
        #okunan kitaba ait tür bilgisini getirdiğim kodlar.
		tur_qs = Tur.objects.filter(kitap__id = okunan.kitap.pk)
		turler = [tur for tur in tur_qs]

		okunanlar.append(
			{
				'okunan_id': okunan.id,
				'kitap_id': okunan.kitap.pk,
				'aciklama': okunan.aciklama,
				'sayfa_numarasi': okunan.sayfa_numarasi,
				'kitap': okunan.kitap,
				'kitap_tur': turler,
				'kitap_sayfa':okunan.kitap.sayfa_sayisi,
				'okunma_tarihi': okunan.okunma_tarihi,
			}
		)

	return okunanlar

bu şekilde. Tabi bu kodların veritabanında kaç sorgu gerçekleştirdiği, ne kadar verimli olduğu konuları ayrı bir konu ancak şuan çalışıyor olması benim için yeterli. Herkese yardımlarından dolayı teşekkür ederim, iyi çalışmalar.:slightly_smiling_face: