Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django foreign key on_delete: how to pass argument to callable when using models.SET

This is my models.py:

def set_image(instance):
    return Image.objects.filter(user=instance.user)[0]

class User(models.Model):
    user = models.CharField(max_length=50)

class Image(models.Model):
    user = models.ForeignKey(User)
    image = models.ImageField(upload_to='media')

class Item(models.Model):
    user = models.ForeignKey(User)
    image = models.ForeignKey(
        Image,
        blank=True,
        null=True,
        on_delete=models.SET(set_image)
    )

When I delete an 'Image', it's related 'Item' calls set_image, which returns an error, because models.SET doesn't pass the instance to the callable. How can I change this behavior? Should I override models.SET or is there any other way around it?

like image 820
kaveh Avatar asked Mar 17 '14 20:03

kaveh


People also ask

What does Django DB models model ForeignKey On_delete protect do?

The PROTECT argument of the ForeignKey on_delete option prevents the referenced object from being deleted if it already has an object referencing it in the database. Put simply, Django will prevent a post from deletion if it already has comments.

Can a model have two foreign keys in Django?

Your intermediate model must contain one - and only one - foreign key to the source model (this would be Group in our example), or you must explicitly specify the foreign keys Django should use for the relationship using ManyToManyField.

What does On_delete models Cascade do?

1. CASCADE. When the on_delete argument is set to cascade then deleting the referenced object will have substantial effect on the referred objects. This means when the referenced object is deleted from the database then all the entries of the object will also be deleted from the entire database.

How will you declare a foreign key which should delete itself as soon as the related field data is deleted?

SET_NULL. First, we need to set the null option on the foreign key as True; we can use the SET_NULL option on the on_delete option. When we delete the referenced object, the referencing value will be updated as NULL. In simple words, a post is deleted without deleting associated comments and set to be NULL.


1 Answers

Override the Image delete method to remove the Item ForeignKey

The following can be used as an intermediary model base class to add this functionality to all of your models:

from django.db import models

class Model(models.Model):
    """
    Intermediate model base class.
    """
    class Meta:
        abstract = True

    def delete(self, *args, **kwargs):
        self.clear_nullable_related()
        super(Model, self).delete(*args, **kwargs)

    def clear_nullable_related(self):
        """
        Recursively clears any nullable foreign key fields on related objects.
        Django is hard-wired for cascading deletes, which is very dangerous for
        us. This simulates ON DELETE SET NULL behavior manually.
        """
        for related in self._meta.get_all_related_objects():
            accessor = related.get_accessor_name()
            related_set = getattr(self, accessor)

            if related.field.null:
                related_set.clear()
            else:
                for related_object in related_set.all():
                    related_object.clear_nullable_related()

source

like image 55
Chris Montanaro Avatar answered Oct 31 '22 09:10

Chris Montanaro