Как удалить объект модели только для одного из двух пользователей, когда оба они принадлежат этой модели как ManyToOneField?

Я просто делаю веб-приложение "Простая почта". Это просто для тренировки, это будет как ОЧЕНЬ упрощенный почтовый сервис, где вы сможете отправлять письма и получать их тоже.

Я хотел бы представить пример с двумя пользователями моего сервиса (их имена "Pop" и "Mob"):

1. Pop отправляет письмо Mob. 2. Через некоторое время Pop решает удалить это письмо, но, конечно, оно должно быть удалено только из списка писем Pop, но не Mob. Или Mob хочет удалить это письмо от Pop, и, как и в вышеприведенном примере, оно должно быть удалено только из почты Mob.

Как реализовать это в моем случае?

Есть необходимые файлы:

  1. models.py
class Mail(models.Model):

    from_user = models.ForeignKey(
        User,
        related_name="FromUser",
        on_delete=models.CASCADE,
        verbose_name="User who sent"
    )

    to_user = models.ForeignKey(
        User,
        related_name="ToUser",
        on_delete=models.SET_NULL,
        null=True,
        verbose_name="User who received"
    )

    title = models.CharField(max_length=128, verbose_name="Title")
    body = models.CharField(max_length=9999, verbose_name="Body")
    datetime_created = models.DateTimeField(auto_now_add=True)
  1. Functions in views.py that have to delete mail from only one(that one who deletes) of two users.
@login_required
def sent_mail(request, pk):
    try:
        mail = Mail.objects.get(id=pk)
    except ObjectDoesNotExist:
        return redirect("all-sent-mails")

    if request.method == "POST":   
        if request.POST.get("Delete"):
            mail.delete()
        return redirect("all-sent-mails")
        

    form = SendMailForm(instance=mail)
    context = {"form": form}
    return render(request, "sent_mail.html", context=context)

#
#

@login_required
def received_mail(request, pk):
    try:
        mail = Mail.objects.get(id=pk)
    except ObjectDoesNotExist:
        return redirect("all-received-mails")

    if request.method == "POST":   
        if request.POST.get("Delete"):
            mail.delete() ### What do i need :)))
        return redirect("all-received-mails")

P.s. Если вам нужен еще какой-то код, просто скажите, я вышлю.

Глядя на вашу модель Mail, я полагаю, что под словом delete вы пытаетесь не показывать это письмо соответствующему пользователю, который его удалил ....

некоторыми простыми способами заставить его работать без переделки вашего кода будут,

1 добавление флага удаления (со значениями 1 для отправителя удалено или 2 для получателя удалено ) или отдельных флагов удаления (на ваш выбор) и рендеринг папки входящих сообщений в соответствии с флагом удаления

inbox = Mail.objects.all().filter( other conditions , **reciever_delete_flag = False** )

аналогично для отправленных писем,

sentmail = Mail.objects.all().filter( other conditions , **sender_delete_flag = False** )

Таким образом, по сути, не отображается почта, которая находится в БД на основании условия удаления, так что она не будет видна удаляемой стороне.


2 Поскольку у вас есть внешние ключи для установки null при удалении, вы можете установить Null для отправителя или получателя в зависимости от того, кто удаляет его

delete_mail(request,pk):    
    deleting_mail = Mails.objects.get(id = pk , from_user = request.user)
    #lets delete sender in this case
    **#you can use the same code below to delete on POST-request too**
    deleting_mail.from_user = None
    deleting_mail.save()

Частично вы столкнулись с этой проблемой потому, что большинство систем электронной почты вообще не используют централизованную структуру базы данных. Если немного упростить, но когда вы отправляете электронное письмо, вы обычно просто посылаете Http-запрос на адрес получателя. Когда письмо отправляется, оно обновляет папку "Исходящие" отправителя, а когда оно получено, оно обновляет папку "Входящие" получателя. На разных серверах хранятся две записи электронного письма, которые являются идеальными зеркалами друг друга.

Вот почему вы можете отправить письмо с адреса gmail на адрес yahoo и почему можно создать частный почтовый сервер. Именно поэтому принимающий клиент должен включить уведомления о прочтении и удалении. Централизованной записи почты нет, поэтому все, что есть у пользователей, - это сигналы, которые они посылают туда-сюда через Интернет.

Итак, лучший способ смоделировать реальную систему электронной почты в вашем веб-приложении, вероятно, заключается в том, чтобы каждый пользователь имел как входящие, так и исходящие сообщения, а затем отправлял запросы туда и обратно для обновления информации в каждом из них. Что-то вроде этого:

class Inbox(models.Model):
    user = models.OneToOneField(User)

class Outbox(models.Model):
    user = models.OneToOneField(User)

class Mail(models.Model):
    title = models.CharField()
    body = models.CharField()

class OutboxItem(Mail):
    outbox = models.ForeignKey(Outbox)
    receiver = models.ForeignKey(User)
    sent_at = models.DateTimeField(auto_now_add=True)

class InboxItem(Mail):
    inbox = models.ForeignKey(Inbox)
    sender = models.ForeignKey(User)
    received_at = models.DateTimeField(auto_now_add=True)

А затем у вас будет некоторое представление, которое обновляет элемент "Исходящие" и элемент "Входящие" на основе заполнения отправителем формы и ее отправки. Это более точный способ моделирования того, как на самом деле работает электронная почта (хотя мы, очевидно, все еще используем центральную базу данных, так что не совсем).

Если вы хотите быть очень тщательным, вы можете создать базу данных для каждого пользователя и заставить их общаться друг с другом, но это немного выходит за рамки данной темы.

Однако, если вы привязаны к текущей модели данных, то НАВЕРНОЕ, самым простым решением будет сделать поля from_user и to_user необязательными. Тогда, когда пользователь удаляет что-то из своих входящих или исходящих, вы не удаляете сообщение, а просто делаете поле нулевым. Затем вы удалите его, если и отправитель, и получатель удалили его, переопределив метод сохранения.

class Mail(models.Model):
    ...
    def save(self, *args, **kwargs):
        if not self.to_user and not self.from_user:
            self.delete()
        else:
            super(GeeksModel, self).save(*args, **kwargs)

Я знаю, что это было много, но я надеюсь, что это поможет!

Вернуться на верх