I have the requirement that whenever there is a model get's added/changed/deleted, it should send a mail notification. The content will be more like the django_admin_log entries. I just need to extend this functionality in my model to send the mail. Any suggestions?
Django_log_admin will only track changes made in the admin interface. If the model is changed anywhere else, it will not update the log. However, if you are OK with just admin changes, then you can use a combination of django_log_admin and the post_save signal to do the trick. Put this in your management.py:
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.contrib.admin.models import LogEntry
from django.core.mail import mail_admins
from django.template.loader import render_to_string
#will be triggered every time a LogEntry is saved i.e. every time an action is made.
#receiver(post_save, sender=LogEntry)
def send_notification_email(change, **kwargs):
mail_admins(subject="model %(model) has been changed by %(user)" %
{'model':change.content_type, 'user': change.user},
message = render_to_string('change_email.html', { 'change': change }) )
note to self: wow, django really includes all the batteries :D
You should look at Django's signals. In your case, you'll connect your handlers to the post_save and post_delete signals, for starters. Look through the built-in signal documentation for others you may want to tap. No need to hack into admin.
Related
I have djoser integrated on my django project, and I need to create a stripe customer_id on account activation, how can I do this?
I've been searching on djoser doc, but there is nothing about customizing activation, or passing a callback method.
Djoser provides user_activated signal. It is usable just like ordinary django signal.
It's undocumented but working.
Example usage
from django.dispatch import receiver
from djoser.signals import user_activated
#receiver(user_activated)
def my_handler(user, request):
# do what you need here
I realize there are many other questions related to custom django signals that don't work, and believe me, I have read all of them several times with no luck for getting my personal situation to work.
Here's the deal: I'm using django-rq to manage a lengthy background process that is set off by a particular http request. When that background process is done, I want it to fire off a custom Django signal so that the django-rq can be checked for any job failure/exceptions.
Two applications, both on the INSTALLED_APPS list, are at the same level. Inside of app1 there is a file:
signals.py
import django.dispatch
file_added = django.dispatch.Signal(providing_args=["issueKey", "file"])
fm_job_done = django.dispatch.Signal(providing_args=["jobId"])
and also a file jobs.py
from app1 import signals
from django.conf import settings
jobId = 23
issueKey = "fake"
fileObj = "alsoFake"
try:
pass
finally:
signals.file_added.send(sender=settings.SIGNAL_SENDER,issueKey=issueKey,fileName=fileObj)
signals.fm_job_done.send(sender=settings.SIGNAL_SENDER,jobId=jobId)
then inside of app2, in views.py
from app1.signals import file_added, fm_job_done
from django.conf import settings
#Setup signal handlers
def fm_job_done_callback(sender, **kwargs):
print "hellooooooooooooooooooooooooooooooooooo"
logging.info("file manager job done signal fired")
def file_added_callback(sender, **kwargs):
print "hellooooooooooooooooooooooooooooooooooo"
logging.info("file added signal fired")
file_added.connect(file_added_callback,sender=settings.SIGNAL_SENDER,weak=False)
fm_job_done.connect(fm_job_done_callback,sender=settings.SIGNAL_SENDER,weak=False)
I don't get any feedback whatsoever though and am at a total loss. I know for fact that jobs.py is executing, and therefore also that the block of code that should be firing the signals is executing as well since it is in a finally block (no the try is not actually empty - I just put pass there for simplicity) Please feel free to ask for more information - I'll respond asap.
here is the solution for django > 2.0
settings.py:
change name of your INSTALLED_APPS from 'app2' to
'app2.apps.App2Config'
app2 -> apps.py:
from app1.signals import file_added, fm_job_done
Class App2Config(AppConfig):
name = 'app2'
def ready(self):
from .views import fm_job_done_callback, file_added_callback
file_added.connect(file_added_callback)
fm_job_done.connect(fm_job_done_callback)
use django receiver decorator
from django.dispatch import receiver
from app1.signals import file_added, fm_job_done
#receiver(fm_job_done)
def fm_job_done_callback(sender, **kwargs):
print "helloooooooooooooo"
#receiver(file_added)
def file_added_callback(sender, **kwargs):
print "helloooooooooooooo"
Also, I prefer to handle signals in models.py
I have my models in individual files:
models
\
|__init__.py
|event.py
|a_thing.py
|...
In __init__.py I import each model and after that I set the signal handling.
For the Event model I need some post_save handling.
This is the truncated version of __init__.py:
from django.db.models.signals import post_save
from django.dispatch import receiver
from core.models.event import Event
# Event
#receiver(post_save, sender = Event)
def event_post_save(sender, dispatch_uid = 'nope', **kwargs):
print kwargs.get('created')
print '------'
Whenever I save an Event via the console the message in the post_save is printed once but whenever I use the admin interface it gets printed twice. This may be because I import the models inside admin.py as well.
Is there a workaround for this so that I can save Event objects from the admin interface without the post_save firing twice?
It's probably from Django/Python import silliness. You need dispatch_uid like you have, but I think it needs to be an argument to the decorator, not the handler itself.
I managed to fix it my moving the signal handling to the views' __init__.py instead of models' __init__.py
OK, using the new-ish 'user_logged_in' signal in Django 1.3, and it works great. But, the corresponding 'user_logged_out' signal appears to be getting ignored. Let's assume I'm just trying to log the logins & logouts using a module called transaction. Again, the login bit works great, but the logout looks like it's being ignored... No error messages anywhere, and nothing in my resulting logs. OK, here's the code:
from django.contrib.auth.signals import user_logged_in, user_logged_out
from django.dispatch import receiver
from myapp.utils import transaction
#receiver(user_logged_out)
def log_logout(sender, **kwargs):
u = kwargs['user'].username
data={ 'Successful Logout': u }
transaction.add(data)
#receiver(user_logged_in)
def log_login(sender, **kwargs):
u = kwargs['user'].username
data={ 'Successful Login': u }
transaction.add(data)
...I've tested this a couple different ways, and I can't seem to get the user_logged_out signal to fire (or, be heard). Any ideas? Thanks in advance.
I've been struggling with this problem for 5 hours and I have a feeling it's a simple solution that I'm just overlooking.
I'm trying to tie in a third party module (Django Activity Stream) that uses a series of senders and receivers to post data about user activity to a database table. Everything is set up and installed correctly, but I get a 'Signal' Object has No Attribute 'Save' error when I try to run it.
I suspect the problem is in my syntax somewhere. I'm just getting started with Signals, so am probably overlooking something a veteran will spot immediately.
In views.py I have:
from django.db.models.signals import pre_save
from actstream import action ##This is the third-party app
from models import Bird
def my_handler(sender, **kwargs):
action.save(sender, verb='was saved')
#return HttpResponse("Working Great")
pre_save.connect(my_handler, sender=Bird)
def animal(request):
animal = Bird()
animal.name = "Douglas"
animal.save()
The Django Activity Stream app has this signals.py file:
from django.dispatch import Signal
action = Signal(providing_args=['actor','verb','target','description','timestamp'])
And then this models.py file:
from datetime import datetime
from operator import or_
from django.db import models
from django.db.models.query import QuerySet
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _
from django.utils.timesince import timesince as timesince_
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.models import User
from actstream import action
...
def action_handler(verb, target=None, **kwargs):
actor = kwargs.pop('sender')
kwargs.pop('signal', None)
action = Action(actor_content_type=ContentType.objects.get_for_model(actor),
actor_object_id=actor.pk,
verb=unicode(verb),
public=bool(kwargs.pop('public', True)),
description=kwargs.pop('description', None),
timestamp=kwargs.pop('timestamp', datetime.now()))
if target:
action.target_object_id=target.pk
action.target_content_type=ContentType.objects.get_for_model(target)
action.save()
action.connect(action_handler, dispatch_uid="actstream.models")
Your main problem is in the discipline in maintaining coding style, or rather in this case, lack of. You will find that it is easier to identify problems in your code if you do not use the same name to refer to multiple things within the same module; give each object a unique, meaningful name, and refer to it using only that name.
The bottom line here is that the docs for that project contain bad code. This line:
action.save(sender, verb='was saved')
isn't ever going to work. The from actstream import action ultimately imports a signal from actstream.signals, and signals do not and never have had a save method. Especially not with such an odd signature of sender, verb.
At first I thought maybe the author had done something odd with subclassing Signal, but after looking at the rest of the codebase, that's just not the case. I'm not entirely sure what the intention of those docs was supposed to be, but the right thing to do in your handler will either be to save a new Action (imported from actstream.models) instance, or to do something with your model.
Sadly, the project's repository has a pretty sorry set of tests/examples, so without downloading and trying the app myself, I can't tell you what needs to happen there. You might try contacting the author or simply try finding a better-documented/better-maintained Activity Streams app.