Don't repeat your self, use monkeypatching - a better default '__unicode__'
This latest top-secret project for sure is keeping me busy and time wise leaves little to keep blogging, however it being Friday and all and because you're worth it here is a Django expert tip.
Django's default '__unicode__' representation leaves a bit to be desired to say the least. In a nut shell it returns the class name + 'object' for all instances and so requires that all your models have a '__unicode__' defined to have a useful string represenation. Well with a bit of friendly monkeys we can patch it right up as per the code below:
from django.db.models.base import Model import logging import hashlib import re from django.conf import settings logger = logging.getLogger(__name__) #---------------------------------------------------------------------------------------------------------------------- logger.info("Patching 'django.db.models.base.Model': adding get_pk_display() method that return pk like string "\ " that is based on class name and pk of the model, ex. #NG000-341-000 or #NGNone, or #NGXYA") # confirm signature of code we are patching and warn if it has changed #raise Exception(hashlib.md5(str(Model)).hexdigest()) if not '300fd49fc5099da23c0929fb1b7b48cd' == \ hashlib.md5(str(Model)).hexdigest(): logger.warn("Hexdigest md5 signature of 'django.db.models.base.Model' does not match expected value." " There might be a chance patch is broken so please review code and update as needed.") def get_pk_display(self): try: return u'#{0}{1:09}'.format(''.join(re.findall('[A-Z]', self.__class__.__name__)), self.pk) except: # most likely non integer based pk or not yet saved i.e. pk == None return u'#{0}{1}'.format(''.join(re.findall('[A-Z]', self.__class__.__name__)), self.pk) # do the actual patch Model.get_pk_display = get_pk_display del get_pk_display # clean up namespace after patching #---------------------------------------------------------------------------------------------------------------------- #---------------------------------------------------------------------------------------------------------------------- logger.info("Patching 'django.db.models.base.Model': adding default __unicode__() method that return self.name" \ " prepended with self.get_pk_display if settings.DEBUG = True. If self.name does not exist then only" \ " self.get_pk_display is returned") # confirm signature of code we are patching and warn if it has changed #raise Exception(hashlib.md5(str(Model)).hexdigest()) if not '300fd49fc5099da23c0929fb1b7b48cd' == \ hashlib.md5(str(Model)).hexdigest(): logger.warn("Hexdigest md5 signature of 'django.db.models.base.Model' does not match expected value." " There might be a chance patch is broken so please review code and update as needed.") def __unicode__(self): try: return u'{0}{1}'.format(self.get_pk_display() + ': ' if settings.DEBUG else '', self.name) except: return self.get_pk_display() Model.__unicode__ = __unicode__
I store the above file in the project root with an app labled '_monkeypatches' in a file named 'patch_django_db_models_base_model.py' - nomenclature and organization is an art in itself but I prefer verbose for my own sake and the team - and below is what it does in plain English:
- Every model in your django project gets a new method 'get_pk_display' – it takes the capital letters of the class name and the instances default pk and renders a front end friendly id of object. For example UserProfile with pk 7 would be rendered as '#UP000000007'. This is a handy method in itself as for example I use it heavily on the current project that requires information is hidden until certian conditions are met.
- Every model get's a new shiny __unicode__ that returns the objects 'self.name' (from 4+ years of Django it's uncommon for my objects not to need a 'name' field) and prepends it with the output 'get_pk_display' IF settings.DEBUG is True – if object does not have 'self.name' defined then 'get_pk_display' is just returned, ex '#C000000312 Danols Web Engineering'.
I tell you – the above is rather handy and now I am in the process of wiping out uneeded __unicode__ and cleaning up templates.
Thoughts, comments and feel free to share your nuggets of Django wisdom.
Be great – @danielsokolow
Comments
Post a Comment