Compare values while saving upon a model in django? - django

this is my model
class Profile(models.Model):
activate = models.BooleanField(default=False)
Now i want to do is , whenever some one from admin panel makes it true , an email will be sent to this particular user whose account is activated.
But i want to sent mail only when the value becomes true from false. if the value is already true i dont want to send any mail .
tried this thing with post save , but it sends email after every save action on Profile Model

Here the code, that will do it (used pre_save signal):
from django.db.models.signals import pre_save
from django.dispatch import receiver
#receiver(pre_save, sender=Profile)
def profile_changed(sender, instance, *args, **kwargs):
if instance.activate:
if not instance.pk:
print "Send email to user here"
else:
activate_was = sender._default_manager.filter(pk=instance.pk)\
.values("activate").get()["activate"]
if activate_was != instance.activate:
print "Send email to user here"

Related

How to integrate notification feature to Custom User in Django

I have gone through many blogs and apps, mostly all the apps are integrating notifications feature using Django auth user, So if there is any way or blog for it that would be helpful.
Problem That i am facing is i have defined my user model as:
class user_signup(models.Model):
full_name = models.CharField('Full Name',max_length=200)
user_email = models.EmailField('User Email', max_length=255)
user_password = models.CharField('Password', max_length=30)
date_time=models.DateTimeField(auto_now=True)
def __unicode__(self):
return smart_unicode(self.user_email)
And i want to add notification center to the existing model, so what could be the best way for it.
Donot know why anybody didn't answered
You can use one that i recently used , its django-notification module and below is the snippet
Handler:-
from django.db.models.signals import post_save
from notifications.signals import notify
from myapp.models import MyModel
def my_handler(sender, instance, created, **kwargs):
notify.send(instance, verb='was saved')
post_save.connect(my_handler, sender=MyModel)
generate an notification
from notifications.signals import notify
notify.send(user, recipient=user, verb='you reached level 10')
// "recipient" can also be a Group, the notification will be sent to all the Users in the Group
notify.send(comment.user, recipient=group, verb=u'replied', action_object=comment,
description=comment.comment, target=comment.content_object)
notify.send(follow_instance.user, recipient=follow_instance.follow_object, verb=u'has followed you',
action_object=instance, description=u'', target=follow_instance.follow_object, level='success')
Read refs:-
Ref1 and Ref2

Send confirmation email when changing the email in Django

I'm currently using django-registration, and it is working well (with some tricks). When the user registers, he has to check his/her mail and click on the activation link. That's fine, but...
What if the user changes the email? I would like to send him/her an email in order to confirm that he is the owner of the email address...
Is there an application, snippet, or something that would save me the time of writing it by myself?
I've faced the same issue recently. And I didn't like the idea of having another app/plugin for just that.
You can achieve that by, listening to User model's singles(pre_save, post_save) and using RegistrationProfile:
signals.py:
from django.contrib.sites.models import Site, RequestSite
from django.contrib.auth.models import User
from django.db.models.signals import post_save, pre_save
from django.dispatch import receiver
from registration.models import RegistrationProfile
# Check if email change
#receiver(pre_save,sender=User)
def pre_check_email(sender, instance, **kw):
if instance.id:
_old_email = instance._old_email = sender.objects.get(id=instance.id).email
if _old_email != instance.email:
instance.is_active = False
#receiver(post_save,sender=User)
def post_check_email(sender, instance, created, **kw):
if not created:
_old_email = getattr(instance, '_old_email', None)
if instance.email != _old_email:
# remove registration profile
try:
old_profile = RegistrationProfile.objects.get(user=instance)
old_profile.delete()
except:
pass
# create registration profile
new_profile = RegistrationProfile.objects.create_profile(instance)
# send activation email
if Site._meta.installed:
site = Site.objects.get_current()
else:
site = RequestSite(request)
new_profile.send_activation_email(site)
So whenever a User's email is changed, the user will be deactivated and an activation email will be send to the user.

Getting remote ip and model field name in signals

How to get remote ip and fields name in signals ?
I have tried using def ModelChangeLogger(sender, request, **Kwargs): but it throws error message takes only one argument. The code:
signals.py
def ModelChangeLogger(sender, **Kwargs):
if str(sender._meta) == str(models.DBLogEntry._meta):
return
log_time = datetime.datetime.now()
log_table_name = sender._meta.object_name
log_instance = Kwargs['instance']
log_ip = '0.0.0.0' **####### Remote ip #########**
log_change_type = ''
if 'created' in Kwargs:
log_change_type = Kwargs['created'] and 'Creation' or 'Updating'
else:
log_change_type = 'Deleting'
models.DBLogEntry.objects.create(
log_time=log_time,
log_table_name=log_table_name,
log_instance=log_instance,
log_change_type=log_change_type
)
__init__.py
from django.db.models.signals import post_save
from django.db.models.signals import pre_save
from django.db.models.signals import post_delete
from myapp.tracker.signals import ModelChangeLogger
pre_save.connect(ModelChangeLogger)
post_save.connect(ModelChangeLogger)
post_delete.connect(ModelChangeLogger)
How to get remote_add and field names from there?
It is not recommendable to have a signal handler expecting a request object due to the fact that a model save might be triggered without having a request coming from a web browser (eg. if you simply do it through the shell) or call model.save() somewhere else in your code!
You could either make your own custom signal that gets send from the views that modifiy your model or call the logging method yourself in your views.

django-registration auto create UserProfile

I'm using django-registration and I'm trying to connect to its signals to automatically create a UserProfile.
Signal definition:
from django.dispatch import Signal
# A new user has registered.
user_registered = Signal(providing_args=["user", "request"])
Signal send by django-registration:
def register(self, request, **kwargs):
"""
Create and immediately log in a new user.
"""
username, email, password = kwargs['username'], kwargs['email'], kwargs['password1']
User.objects.create_user(username, email, password)
# authenticate() always has to be called before login(), and
# will return the user we just created.
new_user = authenticate(username=username, password=password)
login(request, new_user)
signals.user_registered.send(sender=self.__class__,
user=new_user,
request=request)
return new_user
My signal connect:
from registration.signals import *
from core.models import UserProfile
from django.contrib.auth.models import User
def createUserProfile(sender, instance, **kwargs):
UserProfile.objects.get_or_create(user=instance)
user_registered.connect(createUserProfile, sender=User)
Needless to say no UserProfile is being created. What am I missing here?
Thanks a lot!
EDIT: I moved my connect() and its corresponding method to a model.py and still no luck.
New code:
from django.db import models
from django.contrib import auth
from django.contrib.auth import login
from core.forms import AuthForm
from registration.signals import *
from django.contrib.auth.models import User
# Create your models here.
class UserProfile(models.Model) :
user = models.ForeignKey(User, unique=True)
def __unicode__(self):
return self.user.username
def createUserProfile(sender, instance, **kwargs):
print "creating profile"
UserProfile.objects.get_or_create(user=instance)
user_registered.connect(createUserProfile, sender=User)
I'm using Pycharm to debug, and in the very beginning my breakpoint on user_registered.connect() is hit. So I assume that connect() is being registered correctly. However, I still don't see createUserProfile being run. Anything else I'm missing?
Thanks!
ANSWER: Doh. My connect and receiver code was wrong. Correct code:
def createUserProfile(sender, user, request, **kwargs):
UserProfile.objects.get_or_create(user=user)
user_registered.connect(createUserProfile)
Realized it after I read signals.py in django-registration
You need to register (connect) your signal in a module which is imported on server startup. Your file where user_registered.connect(createUserProfile, sender=User)lives is mot likely not imported on startup. From the django docs:
You can put signal handling and
registration code anywhere you like.
However, you'll need to make sure that
the module it's in gets imported early
on so that the signal handling gets
registered before any signals need to
be sent. This makes your app's
models.py a good place to put
registration of signal handlers.
http://docs.djangoproject.com/en/dev/topics/signals/#connecting-receiver-functions
So models.py of your custom app would be a good place (or any other module which is definitely imported on server startup).
Torsten is right: the alternative way is to use decorators as stated in documentation:
from registration.signals import user_registered
# ...
#receiver(user_registered)
def your_function_name_here(sender, user, request, **kwargs):
# your code here
pass
I like this way because it's compact and readable.

Django - send email on model change

I want to send an email when a specific field is changed in a model. Is it possible? Here is what I am looking for. I have a profile model that includes a BooleanField that when the administrator selects to be true I want to send user an email. I know I could put it in a "def save(self):" but, that fires off an email anytime the model is changed and the field is true. Is there a way to have it only email if the field was changed from False to True?
save method is a perfectly good place for what you want to do:
def save(self):
if self.id:
old_foo = Foo.objects.get(pk=self.id)
if old_foo.YourBooleanField == False and self.YourBooleanField == True:
send_email()
super(Foo, self).save()
You can use django-model-changes to do this without an additional database lookup:
from django.db import models
from django.dispatch import receiver
from django_model_changes import ChangesMixin
class MyModel(ChangesMixin, models.Model):
flag = models.BooleanField()
#receiver(pre_save, sender=MyModel)
def send_email_if_flag_enabled(sender, instance, **kwargs):
if instance.previous_instance().flag == False and instance.flag == True:
# send email
Something like this could help and only sends an email when change from false to true
#models.py
from django.contrib.auth.models import User
from django.db.models import signals
from django.db import models
from django.dispatch import receiver
from django.db.models.signals import pre_save
from django.conf import settings
from django.core.mail import send_mail
#signal used for is_active=False to is_active=True
#receiver(pre_save, sender=User, dispatch_uid='active')
def active(sender, instance, **kwargs):
if instance.is_active and User.objects.filter(pk=instance.pk, is_active=False).exists():
subject = 'Active account'
mesagge = '%s your account is now active' %(instance.username)
from_email = settings.EMAIL_HOST_USER
send_mail(subject, mesagge, from_email, [instance.email], fail_silently=False)
Use hook a function with your models post_save using django signals (http://docs.djangoproject.com/en/dev/ref/signals/#django.db.models.signals.post_save)
In that function use standard django mailing: http://docs.djangoproject.com/en/dev/topics/email/