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.
Related
I have a OneToOneField between my UserTrust model and django.contrib.auth.models.User that I would like to create whenever a new User registers. I thought on creating the UserTrust instance using the user_signed_up signal.
I have the following code in my AppConfig
def ready(self):
# importing model classes
from .models import UserTrust
#receiver(user_signed_up)
def create_usertrust(sender, **kwargs):
u = kwargs['user']
UserTrust.objects.create(user=u)
... and this is in my pytest test
#pytest.fixture
def test_password():
return 'strong-test-pass'
#pytest.fixture
def create_user(db, django_user_model, test_password):
def make_user(**kwargs):
kwargs['password'] = test_password
if 'username' not in kwargs:
kwargs['username'] = str(uuid.uuid4())
return django_user_model.objects.create_user(**kwargs)
return make_user
#pytest.mark.django_db
def test_my_user(create_user):
user = create_user()
assert user.usertrust.available == 1000
Still, the test fails with
django.contrib.auth.models.User.usertrust.RelatedObjectDoesNotExist: User has no usertrust.
What did I miss?
The problem with you creating the user via the django_user_model is that it doesn't actually pass through the allauth code that actually sends that signal. You've got two options:
Use a client (since I'm assuming you're using pytest-django) and fill out a registration via the allauth provided link for registering new users. That way, a signal is sent, and you can assert attributes and model instances like that.
You can simply ignore the signal and unittest the function itself. That's it. You put your trust in that single registration view not changing at all and put your trust in the package that the API will not change. I can still recommend this option, but you've been warned.
You can send the signal yourself. Not recommended in case allauth's API changes, but you could just import the signal from allauth and send it like this: user_signed_up.send(sender=self.__class__, toppings=toppings, size=size) where user_signed_up is the signal. Ref the docs: https://docs.djangoproject.com/en/dev/topics/signals/#sending-signals
Again, definitely recommend the first one in case of API changes. I can also recommend the second option just because allauth is pretty reputable and you know what going to happen without too huge of an package change, but you never know.
Im using Django and django-paypal to try and setup a payment system.
Using the developer IPN simulator I can send posts to my server to test with.
[13/Sep/2015 18:54:08] "POST /paypal/ HTTP/1.1" 200 4
There is the post coming through from the simulator, no problems.
Now I want to get the signal fireing. I put the following in one of my aps models.py as in the documentation:
from paypal.standard.models import ST_PP_COMPLETED
from paypal.standard.ipn.signals import valid_ipn_received
def show_me_the_money(sender, **kwargs):
print "Hello"
ipn_obj = sender
if ipn_obj.payment_status == ST_PP_COMPLETED:
# Undertake some action depending upon `ipn_obj`.
if ipn_obj.custom == "Upgrade all users!":
Users.objects.update(paid=True)
else:
#...
valid_ipn_received.connect(show_me_the_money)
But I never get any repsonse from the signal.
I have no idea why? And I don't know how else to test this
I'm not familiar with this library, but are you defining your receiver and sender?
For example, on a post_save signal, I would structure it like this:
post_save.connect(receiver=my_function, sender=myModel)
It looks like show_me_the_money the money is the receiver of the signal, but it's not clear here what is firing the signal. Perhaps it should be:
post_save.connect(receiver=my_function, sender=ST_PP_COMPLETED)
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 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.
I am making use of Django's contrib.comments and want to know the following.
Are there any utils or app out there that can be plugged into an app that sends you a notification when a comment is posted on an item?
I haven't really worked with signals that much, so please be a little bit descriptive.
This is what I came up with.
from django.contrib.comments.signals import comment_was_posted
from django.core.mail import send_mail
if "notification" in settings.INSTALLED_APPS:
from notification import models as notification
def comment_notification(request):
user = request.user
message = "123"
notification.send([user], "new comment", {'message': message,})
comment_was_posted.connect(comment_notification)
Connect django.contrib.comments.signals.comment_was_posted to notification.models.send() as appropriate.
You have to register your comment_notification function with comment_was_posted signal.
from django.contrib.comments.signals import comment_was_posted
if "notification" in settings.INSTALLED_APPS:
from notification import models as notification
def comment_notification(sender, comment, request):
user = request.user
message = "123"
notification.send([user], "new comment", {'message': message,})
comment_was_posted.connect(comment_notification)
I don't know of an app (pretty sure there'll be something out there) but it is fairly straightforward to roll your own. You can tap the Comment model's comment_was_posted signal to call a function that will send you an email.