#python #django #django-models
#python #django #django-модели
Вопрос:
У меня есть следующие модели для внутреннего приложения обмена сообщениями:
class MessageThread(models.Model):
subject = models.CharField(max_length=256, blank=False)
class Message(models.Model):
thread = models.ForeignKey(MessageThread)
content = models.CharField(max_length=5000, blank=False)
timestamp = models.DateTimeField(auto_now_add=True, blank=False)
sender = models.ForeignKey(User)
class MessageRecipient(models.Model):
message = models.ForeignKey(Message)
thread = models.ForeignKey(MessageThread)
recipient = models.ForeignKey(User)
status = models.CharField(max_length=20, choices=MESSAGE_STATUS, default="unread")
Для данного пользователя, чтобы получить список потоков, которые я делаю:
distinct_threads=MessageThread.objects.filter(messagerecipient__recipient=user)
.order_by('-message__timestamp').distinct()
Как мне избавиться от всех потоков с сообщением, содержащим статус «удалено» в ORM? (Другими словами, я хочу получить список всех потоков без потока, содержащего сообщение со статусом =»удалено».)
Комментарии:
1. Это одна из дыр в ORM Django.
Ответ №1:
Для этого я добавил метод в диспетчере моделей:
def get_active_threads(self, user):
all_threads = MessageRecipient.objects.filter(recipient=user).order_by('-message__timestamp')
deleted_threads = []
final_threads = []
for thread in all_threads:
if thread.thread not in (deleted_threads or final_threads):
if thread.status == "deleted":
deleted_threads.append(thread.thread)
else:
final_threads.append(thread)
return final_threads
Ответ №2:
Вы можете либо сделать это на python (как предложено выше), либо позволить БД выполнять грязную работу за вас.
Вам нужно будет создать набор запросов, содержащий все потоки с удаленным сообщением для определенного пользователя, а затем второй набор запросов, который получает все потоки, не содержащиеся в первом:
delthreads = MessageThread.objects.filter(messagerecipient__recipient=user,
messagerecipient__status='deleted').distinct()
result = MessageThread.objects.filter(messagerecipient_recipient=user)
.exclude(messagethread_in=delthreads).distinct()
Однако с точки зрения производительности (особенно для больших таблиц) это повредит вам. Ваша модель нуждается в некоторой реструктуризации, чтобы обеспечить более эффективные запросы. Рассмотрим:
class MessageThread(models.Model):
subject = models.CharField(max_length=256, blank=False)
class Message(models.Model):
thread = models.ForeignKey(MessageThread)
content = models.CharField(max_length=5000, blank=False)
timestamp = models.DateTimeField(auto_now_add=True, blank=False)
sender = models.ForeignKey(User)
recipient = models.ForeignKey(User)
status = models.CharField(max_length=20, choices=MESSAGE_STATUS, default="unread")
Если вы предполагаете, что будете часто выполнять этот запрос, вы можете добавить поле кэша в MessageThread, которое вы можете обновлять всякий раз, когда кто-то удаляет сообщение в этом потоке:
class MessageThread(models.Model):
subject = models.CharField(max_length=256, blank=False)
dirty = models.BooleanField(default=False)
Тогда было бы очень легко извлечь список потоков без удаленных сообщений.
nondelthreads = MessageThread.objects.filter(message__recipient=user, dirty=True).distinct()
Ответ №3:
Вкратце, почему у вас есть thread
поле as внутри MessageRecipient
? Вы можете перейти к thread
через message
.
В любом случае, вам нужно использовать exclude()
# breaking up onto multiple lines for readability, not valid python though
MessageThread.objects.filter(messagerecipient__recipient=user)
.exclude(messagerecipient__status='deleted')
.order_by('-message__timestamp').distinct()
Комментарии:
1. Разве это не позволило бы потоку оставаться в запросе, если, например, в потоке 5 сообщений, и только одно из этих сообщений помечено как удаленное? Ему необходимо удалить поток, если какое- либо сообщение в этом потоке удалено, а не если все.