We love designing and developing websites, but what really drives us is solving problems and cultivating strong relationships with our clients
Five Things I Hate About Django.
By : shabda
The five things I hate about * meme seems have died down, and memes, should not be allowed to die.
Of course I love Django, and have bet very heavily on it. But we do not know a topic, until we know it warts, so here you go. The listing is in no particular order, so sorry no numbering.
Ajax with Django is hard:
Most of the Django Community has decided that bundling Javascript helpers with a python framework is bad idea. Though I can understand the reasoning, (argued here and rebuttal), that Javascript is so basic that you can not be expected to not know it, I can not agree with it. SQL is as basic as Javascript, and yet we have ORM for abstracting away the common and the tedious.
Of Course, with simplejson, and a good Javascript library, you can build Ajax apps fast and with only a minimal amout of fuss. And yet switching between Python and Javascript, twice every hour is a huge time drain. Eg. I put commas after the last element in Python arrays, with JS this would work in FF, but fail with weird errors in IE.
Lack of identity map:
If you get the same row from the DB twice using Model.objects.get, you will get two different objects. Apart from the performance problems of two DB queries, when only one should have done, when you update one of them, the other does not get updated, and you will have interesting things happening in your application. And if you update both of them, you might write two inconsistent changes to the DB.
Look at this code for example.
See this code
In [2]: from django.contrib.auth.models import User
In [3]: usr1 = User.objects.create_user('ram', 'demo@demo.com', 'demo')
In [4]: usr2 = User.objects.get(username='ram')
In [5]: usr3 = User.objects.get(username='ram')
In [6]: user2 == user3
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
...
In [7]: usr2 == usr3
Out[7]: True
In [8]: usr3.username = 'not_ram'
In [9]: usr3.save()
In [10]: usr2.username
Out[10]: u'ram'
In [11]: us3.username
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
...
In [12]: usr3.username
Out[12]: 'not_ram'
In [13]: usr2 == usr3
Out[13]: True
Whether Sessions are browser length/persistent are set sitewide:
You can set whether you want sessions to be browser length/persistent using SESSION_EXPIRE_AT_BROWSER_CLOSE in settings.py. But you can not set them per user, without mucking with django internal. This might seem a minor annoyance, yet this is something which you need to do for every app, as the remember me, function will not work without this.
Newforms is very limited:
Let us say you want the Form to contain a varible number of fields. How can you define the NewForms class to do your biddings.
from django import newforms as forms
class MyForm(forms.Form):
foo = froms.CharField()
bar = froms.CharField()
This can only create a form with a fixed number of fields. While there are ways to generate forms with variable number of fields, (generate the Form class programatically), they are not easy or well documented. (Remind me to write such tutorial sometime.)
Bonus question: How can you generate a form with same form elements multiple (and variable number) times, ala what happens with edit_inline?
Settings mixes application configuration which should be public and passwords, which should be private:
If I am distributing an app MIDDLEWARE_CLASSES is something which I would assume users would not (generally) modify. Similarly, in most of the cases, INSTALLED_APPS, would also be something which users would not change, (unless you are distributing standalone_apps). This means, I want to source control settings.py. But settings.py also contain my DB setiings, and SECRET_KEY, which means, I cannot source control settings.py.
And while we are at it, can we refactor settings.py, so it works without
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
Bonus:
Two things which used to bug me but no more. 1. You cannot extend Models - Well now you can if you use queryset-refactor, or soon can if you are on trunc. 2. Url configuration using regexes. - Now they have two problems. joke notwithstanding, mapping URLs to views is one problem where regexes fit the problem beautifully. With less that 50 lines of code, you can manage a large number of views, and Url patterns.
Comments
you would be smart not to do 'remember me' through long running sessions - instead use a authentication hash that can be used to re-login after a long time.
@Lorenzo
"AJAX is hard with Django is complete FUD"
I am sorry you thnk of it this way. I absolutely LOVE Django, so I guess I meant "AJAX is hard with Django, compared to how easy Django makes other things"
What i really mean is that by getting completely out of your way (and just giving you some convenience functions to serialize Models to json) it actually makes things easier.
And DOM scripting doesn't get any easier than jQuery! ;)
L.
You've completely missed:
1) Lack of migrations in the ORM
2) Poor REST support
@EvanC
Lack of migrations in the ORM: I am pretty good with SQL, so firing a few ALTER TABLE .. SET DEFAULT .. is not a big deal for me, so its not what I hate.
Poor REST support: Try http://code.google.com/p/django-rest-interface/
@troy:
He he, :)
Lack of GROUP BY in the ORM!!! This is driving me nuts... why isn't that included???
As for newforms with variable number of fields.. yes you can generate the class programatically... but compared to how easy Django makes other things.. that is just crappy.
@Julian:
in my (fairly limited) experience with various ORMs, I have yet to see one that supports GROUP BY. I think the rationale behind this is that ORMs return model objects from the database; however if you are using GROUP BY, you typically are performing a SUM(), COUNT(), or other arithmetic operation, in which case the result doesn't fit the concept of a strict model-- since a sum or count of matching items is not a property of the object, but a property of that object's relations to other objects.
Not to say it wouldn't be useful, but I guess the use cases are limited enough and don't fit the ORM concept enough to make it a priority to implement. IMHO, such queries are best executed "raw" (or through a database abstraction layer).
@EvanC + Shabda:
Database Migration is kinda similar-- Sometimes having a tool to do things for you is more trouble that just doing it manually. I'm a fan of versioning SQL structure dumps, then running a simple diff to remind myself of what needs to be changed when migrating. If the changes require some data manipulation, it should be done in a migration script anyway-- plugging along with incomplete or partially-converted data on a live site, while you finish the modifications on the shell or something like phpPgAdmin, is never a good idea!
I just don't see how a tool could (reliably) automatically know how to do all that for you.
Hi! I was surfing and found your blog post... nice! I love your blog. :) Cheers! Sandra. R.
Sign: umsun Hello!!! rcuwwymhyw and 7668ssgfhphzye and 2321I love your blog. :) I just came across your blog.
About Lack of identity map.
The problem is only in how you understand the system.
If yesterday you had 1000 000 $ and someone stol it from you today. I does not meen that you are different person now? Am I right? Just one of you attribute changed. The same with name. The primary key is id not name. In our word system you can make yourself new pasport that meen that you changed id. So system can treat you like different person. But not people who know you. They know all you attribues, and comparing by all of them. The same is you. It's just because you know that they are suppose to be the same. Think like system. Not like human!!!
- Test Driven Development in Python
- Deploying Django apps on Heroku
- Developing android applications from command line
- Deploy Django App in 5 Easy Steps
- Project Management Tools for Start-Ups
- Generating a pdf from an image using PIL and django
- Dynamically attaching SITE_ID to Django Caching
- Screencast: How to deploy Django on Heroku
- Deploying Django apps on Heroku
- How to use pep8.py to write better Django code
- rails
- django
- linkroundup
- django opinion
- opinion
- business
- API
- appengine
- python
- satire
- startup
- Uncategorized
- marketing
- personal
- rambling
- search
- interviews
- seo-interviews
- 5startupideas
- ideas
- seo
- tips
- forms
- paypal
- utilities
- datetime
- web2.0
- Amazon
- algorithms
- presentations
- products
- pinax
- satchmo
- ecommerce
- microsoft
- yahoo
- book
- tutorial
- models
- aggreagtion
- meta
- India
- apps
- about
- CSS
- Design
- wordpress
- test slug
- vim
- urls
- reviews
- javascript
- xmpp
- emacs
- Typography
- Grid Theory
- Color Theory
- iphone
- android
- titanium
- mobile applications
- CSS3
- Browser Compatibility
- mobile
- jobs
- lamson
- django setup
- files
- upload
- jsTree
- hierarchical view
- web page
- Treeview
- coffeescript
- request
- response
- South
- django south
- django migration
- --fake
- screencasts
- django caching
- SITE_ID prefix
- review
- code hosting
- comparison
- unfuddle
- fogbugz
- assembla
- github
- project management
- ticketing system
- gunicorn
- deploy
- nginx
- ubuntu
- vps
- android terminal
- terminal
- programming
- TDD
- Test Driven
- Development
- May 2012
- April 2012
- March 2012
- February 2012
- January 2012
- December 2011
- October 2011
- September 2011
- July 2011
- June 2011
- April 2011
- February 2011
- January 2011
- December 2010
- November 2010
- October 2010
- September 2010
- June 2010
- April 2010
- March 2010
- January 2010
- December 2009
- November 2009
- October 2009
- September 2009
- August 2009
- July 2009
- June 2009
- April 2009
- March 2009
- February 2009
- November 2008
- October 2008
- June 2008
- May 2008
- April 2008
Regarding your settings.py problem, you can have a file in your project called localsettings.py which contains only your db user/password. Then in settings.py, remove your db info and add code to import localsettings.py. That way you can source control settings.py without source controlling local_settings.py.