Django – How to use delete() in ManyToMany relationships to only delete a single relationship

Question:

I have a model Voucher that can be allocated to several users.

I used a M2M relationship for it.

I want, in the template, the possibility to delete the voucher allocated to the logged in user, and the logged in user only (not all relationships).

The problem I have is that the current model deletes the entire model for all users, instead of the single user requesting "delete".

The alternative would obvioulsy be to simply create a model Voucher on a ForeignKey, but something tells I can probably do it with a M2M in the views.

Is there a way to focus my delete function specific to the user? In the example below, I tried to filter based on user.request which is not working. Looking at the data inside the model, users IDs are listed. Is it not what request.user does?

models

class Voucher(models.Model):
    user = models.ManyToManyField(User, blank=True)

views

def delete_voucher(request, voucher_id):
    voucher = Voucher.objects.filter(pk=voucher_id).filter(user=request.user)
    voucher.delete()
    return redirect('account')

template

<a class="button3 btn-block mybtn tx-tfm" href="{% url 'delete-voucher' voucher.id %}">Delete</a>

url

path('delete_voucher/<voucher_id>', views.delete_voucher, name='delete-voucher'),
Asked By: PhilM

||

Answers:

Use the .remove method. See the M2M documentation.

So

def delete_voucher(request, voucher_id):
    voucher = Voucher.objects.filter(pk=voucher_id).filter(user=request.user)
    voucher.user.remove( request.user) 
    # note, more readable if the M2M field has a plural name voucher.users
    return redirect('account')

It’s symmetrical so you could also do request.user.voucher_set.remove( voucher)

It may help to know that there’s an intermediate table maintaining the relationship between a voucher object (row in the vouchers table) and a user object. Each row in this table contains a foreign key to one user and a foreign key to one voucher. .remove deletes the row in this intermediate table, leaving the user and voucher objects unchanged.

Answered By: nigel222