Call a method for each model instance

Viewed 54

I have a Category model. I want to make a directory for the category everytime I create a new category. I have a method in my model called create_directory.

class Category(models.Model):
    category_title = models.CharField(max_length=200)
    category_image = models.ImageField(upload_to="category")
    category_description = models.TextField()
    slug = models.SlugField(max_length=200, unique=True, default=1)

    def create_directory(self):
        gallery_path = os.path.abspath(
            os.path.join(settings.MEDIA_ROOT, Category.slug))
        if not os.path.isdir(gallery_path):
            os.mkdir(gallery_path)

    class Meta:
        verbose_name_plural = "Categories"
        unique_together = ("category_title", "slug")

    def __str__(self):
        return self.category_title

I want to call create_directory each time I create a category in the Admin panel.

2 Answers

First, I think you meant self.slug and not Category.slug. self.slug is the value of the slug field for that particular instance, while Category.slug is just an instance of the SlugField class.

You should override your model's save method to call create_directory:

class Category(models.Model):
    ...

    def create_directory(self):
        gallery_path = os.path.abspath(
            os.path.join(settings.MEDIA_ROOT, self.slug))
        if not os.path.isdir(gallery_path):
            os.mkdir(gallery_path)

    def save(self, *args, **kwargs):
        if not self.pk:
            self.create_directory()
        super().save(*args, **kwargs)

Alternatively, you can create a signal for this:

models.py:

from django.db.models.signals import post_save
from django.dispatch import receiver

@receiver(post_save, sender=Category)
def category_post_save(sender, instance, *args, **kwargs):
    gallery_path = os.path.abspath(
        os.path.join(settings.MEDIA_ROOT, instance.slug))
    if not os.path.isdir(gallery_path):
        os.mkdir(gallery_path)

Update

If you want to remove the directory as well, you can override the delete method:

class Category(models.Model):
    ...

    def delete(self, *args, **kwargs):
        os.rmdir(os.path.join(settings.MEDIA_ROOT, self.slug))
        super().delete(*args, **kwargs)

There is also a pre_delete signal that you can use.

I want to call create_directory each time I create a category in the Admin panel.

As you want to call the create_directory method when a category is created from the admin panel, you should use save_model and not save.

You might want to read Difference between save() and save_model().

Simply you can do:

def save_model(self, request, obj, form, change):
    self.create_directory()
    super().save_model(request, obj, form, change)
Related