I took up the Python programming language because of its design philosophies, its great community and most importantly for me its beautiful syntax. However, recently I’ve been a left a little disheartend. In my attempts to customise Django I’ve come across code that I think syntactically could be cleaner. I’m by no means a seasoned Python programmer, in-fact I’ve only been using it properly for the past few months. I’d appreciate your insights and your views.
Here are some examples of code I have come across:
Why is there a need for the slash?
from django.contrib.admin.util import get_model_from_relation, \
reverse_field_path, get_limit_choices_to_from_path
Could this be written more elegantly?
rel_name = other_model._meta.pk.name
self.lookup_kwarg = '%s__%s__exact' % (self.field_path, rel_name)
self.lookup_kwarg_isnull = '%s__isnull' % (self.field_path)
self.lookup_val = request.GET.get(self.lookup_kwarg, None)
self.lookup_val_isnull = request.GET.get(
self.lookup_kwarg_isnull, None)
self.lookup_choices = f.get_choices(include_blank=False)
One thing I don’t understand is why the code after the if statement for each and statement is on seperate lines?
def has_output(self):
if isinstance(self.field, models.related.RelatedObject) \
and self.field.field.null or hasattr(self.field, 'rel') \
and self.field.null:
extra = 1
else:
extra = 0
return len(self.lookup_choices) + extra > 1
This just looks messy!
def choices(self, cl):
from django.contrib.admin.views.main import EMPTY_CHANGELIST_VALUE
yield {'selected': self.lookup_val is None
and not self.lookup_val_isnull,
'query_string': cl.get_query_string(
{},
[self.lookup_kwarg, self.lookup_kwarg_isnull]),
'display': _('All')}
for pk_val, val in self.lookup_choices:
yield {'selected': self.lookup_val == smart_unicode(pk_val),
'query_string': cl.get_query_string(
{self.lookup_kwarg: pk_val},
[self.lookup_kwarg_isnull]),
'display': val}
if isinstance(self.field, models.related.RelatedObject) \
and self.field.field.null or hasattr(self.field, 'rel') \
and self.field.null:
yield {'selected': bool(self.lookup_val_isnull),
'query_string': cl.get_query_string(
{self.lookup_kwarg_isnull: 'True'},
[self.lookup_kwarg]),
'display': EMPTY_CHANGELIST_VALUE}
Please don’t get me wrong, I’m not doing a disservice to the many contributors of Django, on the contrary I really admire them and I’m grateful. I appreciate that maybe it’s my lack of experience with Python itself or that bits of code that make the syntax look unclean are in-fact core features of the Python programming language.
Just to make it clear this question is genuine and sincere, I ask this question in the spirit of learning and discussion. If you don’t have anything conducive to contribute please don’t respond.
Thank You
1) You need slash, because usually, but not always, Django adheres to pep8, where lines should have at most 80 characters. The better way to write this though, is:
\should generally be avoided.2) There is nothing inelegant with this code. Simply attributes required for making lookup are created. Why do you feel it’s not elegant? How would you prefer this to be written?
3) Again to satisfy the need of having line shorter than 80 characters. This could be rewritten using
()and made shorter:However since Django uses Python 2.4 (I think they are bumping version soon or already did it), they can’t use inline
if-else.On the other hand it could be also written in shorter way:
But I feel the original way is slightly clearer by having the
extravariable. Here you would need a comment, why it’s either 0 or 1. With extra you don’t need a comment and it’s perfectly clear. I dislike comments, so I prefer the first way 🙂4) This indeed looks messy. I believe it would be better to split it into three smaller methods, each potentially yielding someting. But then I am not sure that it’s allowed in python2.4 (or python2.5) to yield from subroutine (I have some vague memory, that this was introduced later or even in py3). Anyway I would put creation of those dictionaries into a separate methods, because it seems very untrivial. What I would prefer is this:
Of course I would use some more meaningful names for submethods, but I don’t see the full context and I don’t really know what those choices are.
Finally:
What you see here is Python2 pushed to its limits. Django is a big framework. There are some features that are simply result of Django being large project, that has been now developed for several years and people learning new stuff. Fortunately Django developers are slowly removing stuff they believe is wrong, e.g. changing default project structure in Django 1.4, deprecating stuff and bumping python version. You can actually learn a lot from reading django code and asking questions. You probably can learn even more by trying to refactor some code and then learning, why it’s not that easy and why it must be left the way it is 😉 Try it, it will be fun 🙂