Using signal to delete old profile picture when sending update request.
What is Signal in Django.
Signals help decoupled applications get notified when actions occur elsewhere in the framework. Signals are signals or notifications that are fired at different times
- pre_save -> that is fired before a model is saved
- post_save -> witch is fired after a model is saved
- pre_delete -> that is fired before a model is saved
- post_delete -> witch is fired after a model is saved
We can listen to the signals and by the signal can do what we need.
After creating a Django project:
Crating profile app
python manage.py startapp profiles
After that, we have to add it to
INSTALLED_APPS = [ ..... 'profiles' ]
Siting up the media path in
MEDIA_URL = 'media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
Also, we will use the Django rest framework. Have to be installed first.
pip install django-rest-framework
We have to add it to
INSTALLED_APPS = [ ..... 'rest-framwork', 'profiles' ]
To use Images we have to install
pip install pillow
urls.py in the app and include it in the core project URLs
Also, we have to set up media to
urls so that we can access it in the browser.
from django.conf import settings from django.conf.urls.static import static from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), # including the profiles urls path('api/', include('profiles.urls')) ] # setting up media in urls if settings.DEBUG: urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Now let's create a model.
In profiles app:
class ProfileModel(models.Model): full_name = models.CharField(max_length=255) bio = models.TextField() profile_picture = models.ImageField(upload_to='profile_pictures', null=True, blank=True)
Let's run migrations
python manage.py makemigrations python manage.py migrate
Let's serializer the model.
First, create the file
serializers.py in the profiles app.
from rest_framework import serializers from profiles.models import ProfileModel class ProfileSerializer(serializers.ModelSerializer): class Meta: model = ProfileModel fields = ['id', 'full_name', 'bio', 'profile_picture']
In the profiles app open
views.py Will create generics API view for listing, creating, retrieving, and updating.
from rest_framework.generics import ListAPIView, CreateAPIView, RetrieveAPIView, UpdateAPIView from profiles.models import ProfileModel from profiles.serializers import ProfileSerializer # Listing all profiles and creating new profile class ProfileApiViewList(ListAPIView, CreateAPIView): queryset = ProfileModel.objects.all() serializer_class = ProfileSerializer # Retriving specific profile and updating it. class ProfileApiViewRetrieve(RetrieveAPIView, UpdateAPIView): queryset = ProfileModel.objects.all() serializer_class = ProfileSerializer
And now we have to create endpoints. In profiles app: urls.py
from django.urls import path from blogTest.views import ProfileApiViewList, ProfileApiViewRetrieve urlpatterns = [ path('profiles/', ProfileApiViewList.as_view()), path('profiles/<int:pk>', ProfileApiViewRetrieve.as_view()), ]
Now let's run the server and go to the
python manage.py runserver
After will open browser and navigate to
http://127.0.0.1:8000/api/profiles/ (maybe your port is different)
Create a Profile:
Now we can go to that specific profile by using the
Here we can send the update to the profile.
Every time when we update the profile picture, the new image will be saved in
media/profile_pictures but let's say we don't need the old ones to be saved in the server. We will delete the old one by using the signals
Finally let's create a signal
In the profiles app, create a new file
We will use
pre_delete -> that is fired before a model is saved
sender – Specifies a particular sender to receive signals from. See Connecting to signals sent by specific senders for more information.
from django.db.models.signals import pre_save from django.dispatch import receiver from blogTest.models import ProfileModel # receiver - function which will be connected to this signal def deleting_old_profile_pic_on_update(sender, instance, **kwargs): if instance.pk: old_profile_picture = ProfileModel.objects.get(pk=instance.pk).profile_picture new_profile_picture = instance.profile_picture if old_profile_picture and old_profile_picture.url != new_profile_picture.url: old_profile_picture.delete(save=False)
apps.py StoreConfig class, we have to overwrite the
from django.apps import AppConfig class ProfilesConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'profiles' def ready(self): import profiles.signals
And now when we update the profile picture the old one will be deleted.