Manage tow Signals in two different apps in Django - python

i have two Django applications, blogApp and accounts, when i created a signal file for blogapp that can slugify title after saving the model into database, this works perfectly.
But when i added the second signal file to accounts that can create profile to the user when he finished his registration, it shows me this error:
, and when i check the admin section, i can see the profile has been successfully created.
PostModel in blogApp application:
Signals in blogApp application:
ProfileModel in accoounts application:
Signals in accounts application:
So, how can i create the user profile without indexing to Post signals.
Because what i'm thinking is the two signals of two apps is activating after the user press register.

I think, your problem is with the sender you have set.
You want to make a specific action about a Post instance,but you set User as sender ?
So in your receive function, you try to get a Post instance with as id the id of the user provided as isntance.
#receiver(post_save, sender=Post)
def slugify_title_model_field(sender, instance, created, **kwargs):
if created:
post_to_slugify = Post.objects.get(id=instance.id)
post_to_slugify.title = slugify(post_to_slugify.title)
post_to_slugify.slug = slugify(post_to_slugify.title)
post_to_slugify.save()
Of course, you have to remove the post_save.connect... write after this code.
But for this case, I advise you to overload the save function of your model, it is there for that, and it would be much more logical to put this function in a model because it directly concerns the instance being saved. I use signals to deal with cases external to the model itself in general.
class Post(models.Model):
...
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
super().save(*args, **kwargs)

Related

Django - Handle update form submition trigerred from admin section

I have articles that I manage via the admin section of Django.
My problem here is that I need to modify a field right after the administrator submited the form before it goes into database.
My specific need is to replace a part of a string with something else, but I don't know how to handle admin form submittions.
def save(self, *args, **kwargs):
self.title = 'someStuff' #Example
super().save(*args, **kwargs)
Here is the function to place under the model class. As simple as that

How to add a function after a record inserted in database using django admin?

I want to execute a function after a record inserted to database using django-admin panel .
I have a product table , i want to send notification to users when a record inserted in database by django admin panel . i know how to send notification to users , but i dont know where to put my code .
any suggestion will be helpfull .
How can i execute a function to notify user after my record inserted ?
here is my code to execute after record inserted :
from fcm_django.models import FCMDevice
device = FCMDevice.objects.all()
device.send_message(title="Title", body="Message", icon=..., data={"test": "test"})
i searched alot but not found anything usefull .
thanks to this great communtiy .
You can modify save method on your product model
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
device = FCMDevice.objects.all()
device.send_message(title="Title", body="Message", icon=..., data={"test": "test"})
Well, it will send the notification every time the instance is saved (not only when it was added in django admin panel).
You need to use the Django model post_save signals to achieve this. This signal receiver can be placed in the same place where the model is
class FCMDevice(models.Model):
...
#receiver(post_save, sender=FCMDevice)
def notify_users(sender, instance, **kwargs):
# your logic goes here
# instance is referred to currently inserted row
pass
You might wanna check post_save signal. From the docs:
Like pre_save, but sent at the end of the save() method.
url: https://docs.djangoproject.com/en/2.1/ref/signals/#post-save
django-version: 1.7+

How to save related model instances before the model instance in django?

How to save the related model instances before the instance model.
This is necessary because I want to preprocess the related model's instance field under model instance save method.
I am working on Django project, and I am in a situation, that I need to run some function, after all the related models of instance get saved in the database.
Let say I have a model
models.py
from . import signals
class Video(models.Model):
"""Video model"""
title = models.CharField(
max_length=255,
)
keywords = models.ManyToManyField(
KeyWord,
verbose_name=_("Keywords")
)
When the new instance of video model is created.
I need to
1. All the related models get saved first.
a. If the related models are empty return empty or None
2. and then Save this video instance.
I tried to do it using post_save signals, but couldn't succeed as there is no guarantee that related models get saved first that the model.
from django.db.models.signals import post_save, pre_delete, m2m_changed
from django.dispatch import receiver
from .models import Video
#receiver(m2m_changed, sender=Video)
#receiver(post_save, sender=Video)
def index_or_update_video(sender, instance, **kwargs):
"""Update or create an instance to search server."""
# TODO: use logging system
# Grab the id
print("Id is", instance.id)
# Keywords is empty as keyword instance is saved later than this instace.
keywords = [keyword.keyword for keyword in instance.keywords.all()]
print(keywords) # [] empty no keywords
instance.index()
#receiver(pre_delete, sender=Video)
def delete_video(sender, instance, **kwargs):
print("Delete index object")
instance.delete()
Update:
Can be implemented by grabbing the post_save signals and wait unitls
its related models get saved in db, when the related_models get saved
start serialization process and create flat json file along with the models fields and its related instance so, the flat json file can index
into elastic search server.
And the question aries, how much time should we wait in signal handler method? and how to know all instance related fields got saved in db.
class Video(models.Model):
def save(self, *args, **kwargs):
# 1. Make sure all of its related items are saved in db
# 2. Now save this instance in db.
# 3. If the model has been saved. Serialize its value,
# 4. Serailize its related models fields
# 5. Save all the serialized data into index server
# The advantage of using this is the data are indexed in real
# time to index server.
# I tired to to implement this logic using signals, in case of
# signals, when the instance get saved, its related models are
# not instantly available in the databse.
# Other solution could be, grab the `post_save` signals, wait(delay
# the serialization process) and start the serialization of
# instance model and it's related to convert the data to flat json
# file so, that it could index in the searching server(ES) in real
# time.
# until the instance related models get saved and start to
# serialize the data when its
By the way I am using django-admin and I am not defining the logics in
a view, adding the related model instance is handled by django admin
In this case, you can flip the order with which ModelAdmin calls save_model() and save_related() so from Model.save() you will be able to reach the updated values of the related fields, as stated in this post.
class Video(models.Model):
def save(self, *args, **kwargs):
if not self.id:
super().save(*args, **kwargs)
all_updated_keywards = self.keywards.all()
...
super().save(*args, **kwargs)
class VideoAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
if not obj.pk:
super().save_model(request, obj, form, change)
else:
pass
def save_related(self, request, form, formsets, change):
form.save_m2m()
for formset in formsets:
self.save_formset(request, form, formset, change=change)
super().save_model(request, form.instance, form, change)
You can override model's save() method and save related models (objects) before saving instance.

Custom user_logged_in signal BEFORE django updates last_login

I'd like to show a notification to user with some stats (e.g how many items have been sold since last time he logged in)
#receiver(user_logged_in)
def notify_user_on_login(sender, request, user, **kwargs):
items = Item.objects.filter(status=Item.HISTORY_STATUS, seller=user, when_trading__gte=user.last_login)
However, in this signal last_login has already been updated.
According to the source at django.contib.auth django also connects signal with function that updates last_login:
user_logged_in.connect(update_last_login)
Is it possible to call my function BEFORE updating? Or get same result without adding custom field or doing some strange magic?
The last_login is also updated with a handler to that signal, which is surely registered and executed before yours. You might be able to solve your issue by moving your app over django.contrib.auth in INSTALLED_APPS.
Signal handlers depending on order doesn't seem like a good idea though. So I would probably replace Django's handler with your own:
from django.contrib.auth.models import update_last_login
def notify_user_on_login(user):
items = Item.objects.filter(status=Item.HISTORY_STATUS, seller=user, when_trading__gte=user.last_login)
#receiver(user_logged_in)
def after_user_logged_in(sender, user, **kwargs):
notify_user_on_login(user)
update_last_login(sender, user, **kwargs)
user_logged_in.disconnect(update_last_login)

Send Custom Parameters to Django Signals

I am working on Django Signals to handle data in Redis whenever any change happens in the Postgres database. But, I am unable to send custom parameters to Signal Receiver. I have gone through a lot of questions, but I am not able to understand how to send extra custom parameters to Signal Receiver.
Usually I do,
#receiver(post_save, sender=post_data)
def addToRedis(sender, instance, **kwargs):
But I want to do,
#receiver(post_save, sender=post_data)
def addToRedis(sender, instance, extra_param=extra_param_data **kwargs):
# Get `extra_param`
Here, I want to read extra_param to store the data in Redis.
I am using Django Rest Framework. And post_save is directly called after serializer.save()
It'll be great if someone can help me out in this.
You can send any additional parameters in a signal as keyword arguments:
#receiver(post_save, sender=post_data)
def addToRedis(sender, instance, **kwargs):
# kwargs['extra_param']
How to send:
my_signal.send(sender=self.__class__, extra_param='...')
If you have no access to the signal send function (eg REST framework internals), you can always use a custom signal.
This Answer the with Respect to Django Rest:
in your views.py
my_obj = Mymodel()
my_obj.your_extra_param = "Param Value" # your_extra_param field (not Defined in Model)
my_obj.save()
post_save.connect(rcver_func,sender=Mymodel,weak=False)
and define a signal.py with following
from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import Mymodel
#receiver(post_save,sender=Mymodel)
def rcver_func(sender, instance, created,**kwargs):
if created:
received_param_value = instance.your_extra_param # same field as declared in views.py

Categories

Resources