I’d like to use a string as the sender for a custom Django signal but have run into some issues related to how Django’s unicode encoding of a model’s strings. Here’s a hopefully working short example illustrating the problem:
from django.dispatch import Signal
from django.db import models
example_signal = Signal(providing_args=["data"])
class Example(models.Model):
example_field = models.CharField(max_length=32)
def send_signal(self):
example_signal.send(sender=self.example_field, data=self) # (arbitrarily using self as the signal payload)
def example_handler(sender, data=None):
print "received data %s" % data
example_signal.connect(example_handler, sender=u'boogat')
... (after entering the django shell and importing the models)
>>> t = Example.objects.create(example_field='boogat')
>>> t.send_signal()
>>>
I’ve skimmed through Django’s dispatcher.py code – in this case, the signals dispatcher appears to use the Python builtin id function to generate a unique id for whatever object is used as the sender. However, I can’t seem to figure out what I need to do to programmatically generate a string that, when sent to id(), is equivalent to Django’s unicode model string. I’ve tried str, repr, encode('UTF-8'), django.util.encodings, all to no avail.
At this point I’ve already implemented a workaround but I’d still like to understand what is going on… any input would be much appreciated!
I ran into a similar problem with signals and found what I think is a better solution.
I definitely prefer using the
senderargument ofconnectto checks inside the handler if possible.The problem as you say is object
id(): two strings (not even just unicode strings!) with the same content may have different object ids. The solution is theintern()built-in which enters the given string into python’s internal identifier table (this is very similar to ruby’sSymbol).If you use
sender=intern(sender_string)on bothsend()andconnect()things should work as expected.Two important caveats:
intern()only works onstr, notunicode– you will have to deal with encoding back tostr, and you have to perform the same encoding for bothsend()andconnect().A good way to deal with both problems is that you are probably only interested in signals from a few pre-defined strings, so just stick those in a configuration constant, already interned.
For example:
BIG_ADMIN_USERwill print out to gibberish if not decoded back to aunicodestring, but I suspect most such identifiers will be ascii.