This week marks a break away from the topic of templates and instead will be focussing on signals.
Signals are Django's way of allowing you to listen out for certain events that either occur by default in the Django code or that have been specified by an application developer. The signals provided by default are explained in a fair amount of detail in the Django Built-in Signal Reference (djangoproject.com) so I won't go into too much depth on what they do, but they are as follows (skip to the first example):
- pre_init
- Occurs at the start of the process of initialising a model;
- post_init
- Occurs at the end of the process of initialising a model;
- pre_save
- Occurs at the start of the process of saving a model;
- post_save
- Occurs at the end of the process of saving a model;
- pre_delete
- Occurs at the start of the process of deleting a model;
- post_delete
- Occurs at the end of the process of deleting a model;
- class_prepared
- Internally used, occurring when a model class has been registered with Django;
- post_syncdb
- Occurs after syncdb installs an application;
- request_started
- Occurs just before Django starts to process a request;
- request_finished
- Occurs just after Django processes a request;
- got_request_exception
- Occurs when Django encounters an exception whilst processing a request;
- template_rendered
- Occurs only whilst running tests when Django renders a template;
- comment_will_be_posted
- Occurs if you have Django's comment app installed and a comment is just about to be saved;
- comment_was_posted
- Occurs if you have Django's comment app installed and a comment has just been saved;
- comment_was_flagged
- Occurs if you have Django's comment app installed and a comment has had a flag set (i.e. a moderator just approved it).
For my first example this week I'm going to be looking at the post_save signal and how it can be used to ensure that a User object always has a profile instance associated with it.
# File: test_signal/models.py
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
allow_our_emails = models.BooleanField(default=False)
allow_other_emails = models.BooleanField(default=False)
def ensure_profile_exists(sender, **kwargs):
if kwargs.get('created', False):
UserProfile.objects.create(user=kwargs.get('instance'))
post_save.connect(ensure_profile_exists, sender=User)
# File: (somewhere in) settings.py
AUTH_PROFILE_MODULE = "test_signal"
As you can see this defines a fairly simple profile model (supposedly for storing a user's e-mail preferences), the key part of this comes from the function ensure_profile_exists. With all signals it can only be guaranteed that the sender keyword argument will be present therefore we also need to catch everything else using **kwargs. Inside the function we use the fact that post_save is supposed to provide the arguments created and instance to check if the save was for a new object and if so to assign the created instance to the user property of a freshly created UserProfile object.
Finally we connect our function to the post_save signal with instructions to only receive signals when the sending class is User
If the test_signal app is now added to the list of installed apps in settings.py then all new users created will now have an associated profile created also.
The second example for this week demonstrates how you can create your very own signals for code to listen to.
# File: test_signal/signals.py
from django.dispatch import Signal
form_post_received = Signal(providing_args=["path","arguments",]
Here we tell Django that we want form_post_received to be a signal and that it should provide the arguments path and arguments. Now if we add the following:
# File: test_signal/views.py
from signals import form_post_received
from django.conf import settings
def view1(request):
if request.method == "POST":
form_post_received.send(sender=request, path=request.path, arguments=request.POST)
# Continue to do stuff with the form.
def view2(request):
if request.method == "POST":
form_post_received.send(sender=request, path=request.path, arguments=request.POST)
# Continue to do stuff with the form.
def log_form_received(sender, **kwargs):
print "Form Received at %(path)s with arguments %(arguments)s" % kwargs
if settings.DEBUG:
form_post_received.connect(log_form_received)
When pointing views at view1 and view2 whenever the server is in debug mode extra information should be output to the terminal informing us of whenever a form has been posted to either view.
This is done by calling send on our signal along with an argument for sender, in this case we use the request that triggered the view, along with values for each of the other arguments we specified. Django then passes them on to each function that has connected to our signal, which in this case is our logging function (but only when the server is in debug mode, otherwise connect will never be called).
That concludes this weeks tutorial on signals. Next week we shall be looking at the useful functions Django has built in for performing pagination.
UPDATE:There is now a second part to this tutorial talking about more advanced uses of signals. Check it out at Signals - Part 2: Return to sender
I had a similar usage in my app for a signal to make sure a user profile is created. What i still didn't fully get WRT registration is:
ReplyDelete1. When i define user-specific models (i.e) models that are only accessible for a specific user - do i link them to User or to UserProfile - and why?
2. When do i present the UserProfile form, it is part of the registration form/process or is it presented when the user first logs in (after registering)? What are the pros and cons?
Hi avivgr,
ReplyDeleteThank you for your questions.
1. Personally I would link the model to the User as this way it boosts the chances of the model being reusable by others (if it's part of a potentially stand alone app) as well as allowing you to change the model that is used for the profile without having to update any of your other code.
2. I guess there are a couple of ways that this could be done, firstly you could ask for the information on the sign up page (or potentially the page after) by using a custom form on your view and making sure the data is created there. Alternatively you can use some custom middleware to detect if a logged in user has any 'required' fields missing and redirect them to a form to fill in the information at that point. I would tend to lean towards asking for any required information on the sign up page so that it's got out of the way as early as possible. Anything extra can always be put on a secondary page which the user can safely skip (otherwise without some middleware to catch them there's not much you can do to stop them clicking elsewhere on your site). Finally the middleware option is probably best left until you decide that you require some extra information from your existing users at which point it can catch their requests and ensure that their info is up-to-date before letting them get to their destination, this should be used with caution though as it can get quite annoying to click to go somewhere and end up in a completely different place.
I hope this helps answer your questions or at least nudges you in the right direction.
-- G
nft nasıl alınır
ReplyDeletelisans satın al
özel ambulans
yurtdışı kargo
minecraft premium
en son çıkan perde modelleri
en son çıkan perde modelleri
uc satın al
Good content. You write beautiful things.
ReplyDeletetaksi
sportsbet
hacklink
korsan taksi
sportsbet
mrbahis
hacklink
mrbahis
vbet
Good text Write good content success. Thank you
ReplyDeletebetpark
kralbet
kibris bahis siteleri
slot siteleri
tipobet
mobil ödeme bahis
poker siteleri
betmatik
başakşehir
ReplyDeletebayrampaşa
beşiktaş
beykoz
beylikdüzü
FZ6M
mecidiyeköy
ReplyDeletesakarya
istanbul
kayseri
ordu
UO2QNK
GVFCYTGHY
ReplyDeleteصيانة افران غاز
شركة مكافحة الصراصير بالاحساء LuqR2o1Gqr
ReplyDelete