Home > Back-end >  How to delete a model object only for a one of two users, when both of them are belonged to this mod
How to delete a model object only for a one of two users, when both of them are belonged to this mod

Time:10-29

I just make a web application "Simple Mail". This is just for a practice, it will be like a VEEERY simplified mail service, where you can send letters and receive them too.

I'd like to introduce an example with two users of my service(Their names are "Pop" and "Mob"):

1. Pop sends a mail to Mob. 2. After some time, Pop decides to delete this letter, but, of course, it must be deleted only from Pop's list of mails, but not Mob. Or Mob wants to delete this letter from Pop, and just like in above example it must me be deleted only from Mob's mails.

How to realize it in my case ?

There are necessary files:

  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. If u need some more code, just say, i'll post.

CodePudding user response:

Looking at your Mail model, by delete I beleieve what you are trying to do is not to show that mail to the corresponding user who deleted it ....

some simple ways to make it work without re-modelling your code will be,

1 adding a deleted flag (with values 1 for sender deleted or 2 for receiver deleted ) or separate delete flags (which is your choice) and rendering your inbox according to the delete flag

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

similarly for sent mails,

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

Thus basically not rendering the mails which is in the DB based on delete condition so that it will not be seen by the deleted party.


2 Since you have the foreign keys to set null on delete, you can set Null to the sender or reciever based on who is deleting it

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()

CodePudding user response:

Part of the reason that you're running into this issue is because most email systems don't use a centralized database structure at all. Simplifying a bit, but when you send an email, you're generally just sending an Http Request to the receiver's address. When it's sent, it updates the sender's outbox, and when it's received it updates the receiver's inbox. There are two records of the email kept, perfect mirrors of each other, on different servers.

This is why you can send an email from a gmail address to a yahoo address, and why it's possible to set up a private email server. This is also why the receiving client needs to enable read and delete notifications. There's not central record of the mail, so all the users have are the signals that they send back and forth over the internet.

So, the best way to model a real life email system in your web app would probably be to have every user have both an inbox and outbox, and then send requests back and forth to update the information in each. Something like this:

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)

And then you'd have some view that updated both an outbox item and an inbox item based on the sender filling out a form and submitting it. This is the more accurate way to model how email actually works (although we're obviously still using a central database, so not quite).

If you wanted to be very thorough, you could set up a database for every user and have them talk to each other, but that's a bit beyond the scope of this.

However, if you're married to your current data model, BY FAR the easiest solution would be to make the from_user and to_user fields optional. Then when a user delete's something from his inbox or outbox, you don't actually delete the message, you just make the field null. Then you delete it if both sender and receiver have deleted it by overriding the save method.

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)

I know that was a lot, but I hope this helps!

  • Related