2013-03-25 125 views
1

我想用Django構建一個消息應用程序。我不使用postman的原因是我需要比用戶之間的其他對象之間的消息傳遞,我不需要郵遞員的大部分功能。根據相關對象查找對象

這裏是我的模型:

class Recipient(models.Model): 
    ... 
    def get_unread_threads(): 
     see below... 


class Thread(models.Model): 
    author = models.ForeignKey(Recipient, related_name='initiated_threads') 
    recipients = models.ManyToManyField(
     Tribe, 
     related_name='received_thread', 
     through='ThreadReading') 
    subject = models.CharField(max_length=64) 

    class Meta: 
     app_label = 'game' 


class Message(models.Model): 
    author = models.ForeignKey(Recipient, related_name='sent_messages') 
    date_add = models.DateTimeField(auto_now_add=True) 
    date_edit = models.DateTimeField(blank=True) 
    content = models.TextField(max_length=65535) 
    thread = models.ForeignKey(Thread) 

    class Meta: 
     get_latest_by = 'date' 


class ThreadReading(models.Model): 
    thread = models.ForeignKey(Thread) 
    recipient = models.ForeignKey(Recipient) 
    date_last_reading = models.DateTimeField(auto_now=True) 

我的問題是關於get_unread_threads。我無法真正瞭解如何做到這一點。這是第一次嘗試:

def get_unread_threads(self): 
    """ 
    return a queryset corresponding to the threads 
    which at least one message is unread by the recipient 
    """ 
    try: 
     query = self.received_thread.filter(
       message__latest__date_add__gt=\ 
         self.threadreading_set.get(thread_id=F('id')).date_last_reading) 
    except ObjectDoesNotExist: 
     query = None 
    return query 

但顯然這是行不通的,因爲查找不能按照方法latest

+0

我可以但它增加了我想避免的信息冗餘。 – Vincent 2013-03-26 08:43:47

回答

2

在這裏你去:

# Get all the readings of the user 
thread_readings = recipient.threadreading_set.all() 

# Build a query object including all messages who's last reading is after the 
# last edit that was made AND whose thread is the thread of the current 
# iteration's thread reading 
q = models.Q() 
for thread_reading in thread_readings: 
    q = q | models.Q(
     models.Q(
      date_edit__lte=thread_reading.date_last_reading 
      & models.Q(
       thread=thread_reading.thread 
      ) 
     ) 
    ) 

# Get a queryset of all the messages, including the threads (via a JOIN) 
queryset = Message.objects.select_related('thread') 

# Now, exclude from the queryset every message that matches the above query 
# (edited prior to last reading) OR that is in the list of last readings 
queryset = queryset.exclude(
    q | models.Q(
     thread__pk__in=[thread_reading.pk for thread_reading in thread_readings] 
    ) 
) 

# Make an iterator (to pretend that this is efficient) and return a generator of it 
iterator = queryset.iterator() 
return (message.thread for message in iterator) 

:)

現在,永遠不要真正做到這一點 - 重新思考你的模型。我會讀一本名爲「面向對象的分析和應用程序設計」的書。當你進行數據建模時,它會教你如何思考。

+0

是啊,它似乎並不如此高效:)無論如何感謝查詢集建議,以及書 – Vincent 2013-03-28 13:56:09

+0

@Vincent - 不客氣 – orokusaki 2013-03-28 20:01:16