Reputation: 736
For example, I have a Book model, each book has its author and tag.
def get_authors_first_tag(book):
try:
tag = book.author.tags.first()
except:
return None
else:
return tag.id
class Author(models.Model):
name = models.CharField(max_length=50)
tags = models.ManyToManyField('Tag')
class Book(models.Model):
name = models.CharField(max_length=50)
author = models.ForeignKey(Author)
tag = models.ForeignKey('Tag', null=True, on_delete=models.SET(get_authors_first_tag))
I want, when deleting a Tag item, book's tag will be set to its author's first tag. How to do this? Thanks. Doc page - https://docs.djangoproject.com/en/1.9/ref/models/fields/#django.db.models.SET
UPDATE. signals didn't help
from django.db.models.signals import post_delete
from django.dispatch import receiver
class Book(models.Model):
# temporaryly set to NULL on delete,
# becouse for my neds I cannot use default behavior (models.CASCADE)
tag = models.ForeignKey('Tag', null=True, on_delete=models.SET_NULL)
@receiver(post_delete, sender=Tag)
def delete_tag(instance, **kwargs):
for book in instance.book_set.all():
try:
book.tag = book.author.tags.first()
book.save()
except:
pass
UPDATE2 final working solution is: (dirty, but works)
@receiver(post_delete, sender=Tag)
def delete_tag(instance, **kwargs):
books = Book.objects.all()
for book in books:
# after Tag item deleting, book.tag is set to None
# so if boook's tag is null, get it's author's first tag
if not book.tag:
book.tag = book.author.tags.first()
book.save()
Upvotes: 3
Views: 4159
Reputation: 5993
The SET()
doesn't accept any arguments, so you should use the signal receiver:
from django.db.models.signals import pre_delete
from django.dispatch import receiver
@receiver(pre_delete, sender=Tag)
def reset_tag(sender, **kwargs):
tag = kwargs['instance']
for book in books.filter(tag=tag):
book.tag = book.author.tags.first()
book.save()
Put this code into your models.py
or make sure the file you put the receiver into is imported at the startup, so that the receiver is actually connected.
Upvotes: 2