2012-10-12 15 views
6

Python ve Django'ya yeni yaşıyorum, lütfen bana sabırlı olun.Django ile karmaşık sorgulama (tüm arkadaşlardan gelen mesajlar)

Aşağıdaki modelleri var: Bu Django ile üstesinden en iyi/en kolay yolu olmayabilir biliyoruz

class User(models.Model): 
    name = models.CharField(max_length = 50) 
    ... 

class Post(models.Model): 
    userBy = models.ForeignKey(User, related_name='post_user') 
    userWall = models.ForeignKey(User, related_name='receive_user') 
    timestamp = models.DateTimeField() 
    post = models.TextField() 

class Friend(models.Model): 
    user1 = models.ForeignKey(User, related_name='request_user') 
    user2 = models.ForeignKey(User, related_name='accept_user') 
    isApproved = models.BooleanField() 
    class Meta: 
     unique_together = (('user1', 'user2'),) 

ama bu şekilde öğrendim ve böyle kalmasını istiyorum.

Şimdi, tüm yapmak istediğim kişi bir kişiden tüm mesajları al ve arkadaşları. Şimdi soru, Django filtreleriyle nasıl yapılacağıdır?

SELECT p.* FORM Post p, Friend f 
WHERE p.userBy=THEUSER OR (
    (f.user1=THEUSER AND f.user2=p.userBy) OR 
    (f.user2=THEUSER AND f.user1=p.userBy) 
) 

doğruluğu hiçbir garantisi ile, sadece aradığım sonucu hakkında bir fikir vermek için:

Ben böyle bir şey olmazdı SQL düşünüyorum.

cevap

8
from django.db.models import Q 

Post.objects.filter(\ 
    Q(userBy=some_user) | \ 
    Q(userBy__accept_user__user1=some_user) | \ 
    Q(userBy__request_user__user2=some_user)).distinct() 

GÜNCELLEME

Maalesef bu benim hatamdı. related_name değerlerine dikkat etmedim. Yukarıdaki güncellenmiş kodlara bakın. Tek başına userBy__accept_user veya userBy__request_user kullanmak, için User ile karşılaştırılamayacağınız bir başvuru olacağından çalışmaz. Burada yaptığımız şey, Friend ile ters ilişkiyi takip ediyor ve bir kez oradayız, arkadaş isteğindeki diğer kullanıcısının söz konusu kullanıcı olup olmadığını görüyoruz. Bu, aynı zamanda, ters ilişkilerin uygun şekilde tanımlanmasının önemini de göstermektedir. Birçok kişi burada yaptığınız yanılgıyı yapıyor ve FK'yi (User) oluşturdukları modelden sonra related_name ismini yazıyorlar. Aslında, FK'yi geri çevirmekten bahsederken, şimdi Friend hakkında konuşuyoruz. Basitçe, ilgili isimler: friend_requests ve accepted_friends gibi bir şey daha mantıklı olurdu.

+0

Kullanıcının işaret etmesi gereken Kullanıcıdan yabancı bir anahtar var mı? – cesar09

+0

Hayır. "Arkadaş" ın "Kullanıcı" için FK olduğu için "__friend" biti, ilişkiyi geriye doğru takip eder. –

+0

Daha fazla bilgi için [ilişkileri kapsayan aramalar] için belgelere bakın (https://docs.djangoproject.com/en/dev/topics/db/queries/#lookups-that-span-relationships). –

0
(with User u) 
friends_u1 = Friend.objects.filter(user1 = u).getlist('user2_id', flat=True) 
friends_u2 = Friend.objects.filter(user2 = u).getlist('user1_id', flat=True) 
friends_and_user = friends_u1+friends_u2+u.id 

Post.objects.filter(userBy__id__in = friends_and_user) 
+0

Standart yaklaşım, Q' nesnesini kullanmaktır. Farklı bir yaklaşım seçtiniz mi? – Tadeck

+0

Nerede "standart yaklaşım bir Q nesnesini kullanmaktır" alıyorsunuz? Belgelerin hiçbir yerinde öyle değil. Ayrıca, bir django acemi için bu bozuk yaklaşım daha kolay anlaşılabilir olabilir. – Colleen

+4

Deneyimden. Önce tüm kimlikleri topluyorsunuz, sonra bir sorgu için kullanıyorsunuz. 500 arkadaşın olacağı durumu düşünün, sorgu çok büyük olabilir. Evet, bu çözüm Django newbie (ya da _why_ ve _when_ hakkında daha iyi olabileceğini bilen biri tarafından) tarafından kullanılabilir, ancak bu, anlaşılması kolay olandan ziyade, en iyi (ya da en azından "iyi") olanla ilgili değildir. "Standart yaklaşım" bölümüne gelince: [Django'daki karmaşık sorguların belgelerini okuyun] (https://docs.djangoproject.com/en/dev/topics/db/queries/#complex-lookups-with-q- nesneleri). – Tadeck

İlgili konular