views:

609

answers:

10

What are the worst mistakes made using Django framework, that you have noticed? Have you seen some real misuses, that maybe should go as warnings to the Django docs?

+7  A: 

I tried to append items to my session without copying them out, appending the items, and then adding the list back to the session.

This mistake is on a NewbieMistakes page, so hopefully I'm in good company.

This is the correct way to do it, in case anyone is curious.

sessionlist = request.session['my_list']
sessionlist.append(new_object)
request.session['my_list'] = sessionlist
Robert Greiner
+1 for the NewbieMistakes page.
Noufal Ibrahim
Yep, make this the selected answer as it points to the source of knowledge for the question. We don't need to duplicate in SO what is already provided by the Django team...
celopes
+4  A: 

Not splitting stuff up into multiple applications. It's not so much about reusability as it is about having a dozen models, and over 100 views in one app, it's damned unreadable. Plus I like to be able to scan my urls.py file easily to see where a URL points, when I have 100 URLs that gets harder.

Alex Gaynor
Where do you put the project specific tieing up the different apps, code?
Lakshman Prasad
+3  A: 

I think the biggest problem is that people try to code as if this were Java/C: They try to create overly generic applications that need never be changed when future requirements change (which is necessary for Java/C because those apps aren't so easy to change/redesign). What results is a hideously complicated application, which is inflexible and impossible to maintain.

It's just not necessary in Django: just write for today's requirements, build reusable apps with defined, specific tasks and make changes when needed. More and more often I find myself trying to write things as simply as possible, avoiding overly complicated designs at all costs.

Will Hardy
A: 

I first and fore most mistake start writing python code without reading PEP. The worst thing i would quote are

NOTE: Things I am quoting here are DONT'S

1

foo       =  bar

foobar    =  bar

foobarbuz =  bar

2

foo = "foo"
bar = "bar"
foobar = foo + bar //string concat

3

foo = [1,2,3,4,5,6]
foo_ = []
for bar in foo:
  foo_.append(bar)

4

writing import statements with project name

from projectname.appname.models import model

5

Trying to use view like normal python functions

Update: or having too much logic in the view rather moving something to the helper(utils), I dint mean here its a bad practice to make a redirect, There are people who write helper functions in the view.

6

Function/method without a docstring and using namespace no way connected to the context.

Prashanth
I call shenanigans on number 5. There are specific instances where calling another view is useful. It just shouldn't be done very often.
Ignacio Vazquez-Abrams
I think it's good to know when to break away from #1 (from PEP8). I do this when defining django models, as vertical alignment is extremely useful for quickly reading the different field types. I would otherwise never do it, but this is a good enough reason for me.
Will Hardy
I agree with Ignacio. A view IS a normal python function (well, a normal python callable). You should definitely try to use them like normal python callables. Just remember that they expect an HttpRequest object and should return an HttpResponse object.
ozan
@Ignacio, ozan I dint mean having redirect is wrong but there are people who write helper functions in the view rather than writing that in the utils.
Prashanth
+8  A: 

Too much logic in views.

I used to write views that would struggle to fit in 40 lines. Now I consider more than 2-3 indentation levels, 10 or so LOC or a handful of inline comments in a view to be code smells.

The temptation is to write minimal models, figure out your url routing, then do everything else in the view. In reality, you should be using model methods, managers, template tags, context processors, class-based views with abstract base views... anything to keep the view code simple and readable. Logic around saving forms should go in Form.save(). Logic repeated at the start or end of multiple views should go in decorators. Reused display logic should go in included templates, template tags, and filters.

Long views are hard to read, understand, and debug. Learn to use the other tools in you toolkit any you'll save yourself and your team a lot of pain.

ozan
+3  A: 
  1. Monkeying around with pre-save and post-save events.

    If you can't simply do it in save, you should probably rethink what you're trying to do. After all, it's just a relational database under the hood. If what you're doing gets too complex, you'll have ORM mapping issues.

  2. Trying to write uber-generic -- one view does it all -- functionality. View functions are functions for a reason. They can use modules, packages, objects, other functions, etc. They can be short and similar without it being a code smell.

    If you need to use 10 lines of code to construct the uber-generic-do-it-all object and it would have been a 12-line view function without the uber-generic-do-it-all object, then the uber-object isn't helping.

  3. Imposing too much super-sophisticated object class design on the ORM model classes. If it requires abstract base classes or metaclasses, it won't do well in the ORM layer.

  4. Failing to make use of tests.py and the test client to create complete unit tests of whatever it's claimed that the application does.

S.Lott
I have to disagree with 3. Abstract base classes do fine in the ORM layer, and are an important tool. This is particularly true in an agency context where there is a great deal of overlap in attributes of models, both within a project and across projects. Keeping a small library of mixins really helps here.
ozan
+3  A: 

Worst facepalm moment...returning an unlimited query, which happened to be several hundred thousand rows long. It was in a rarely used bit of code, so didn't happen often, but when it did it brought down the server.

Always make sure your query results are limited, i.e.:

results = MyModel.query.all()[:100]

not:

results = MyModel.query.all()

or use an iterator:

for result in MyModel.query.iterator():
zeemonkee
Aren't you are supposed to use pagination, anyway?
Lakshman Prasad
Not necessarily - for example, suppose you are using the model in the shell or cronjob. In this case though it should have been, yes.
zeemonkee
+1  A: 

My worst mistake was using absolute imports like <project_name>.<app_name>.models rather than <app_name>.models. This way when I made a branch and wanted to check it out in different directory (like having and -stable of my project), it wouldn't run. I managed to revert in one project and use only relative imports in one project, but in another, larger one, we have to stick with it (we have there both absolute and relative). I won't make this mistake again.

gruszczy
A: 

I've experienced a worst practice : use something else that the default id as primary key of model.

It looked as a good idea but it caused some problems in the administration web site and it was difficult to restore the id as primary key on an existing database.

I think that there is no specific case that are specific enough to cause these problems. I recommend to keep the id of your model as it is by default.

See http://stackoverflow.com/questions/2055784/what-is-the-best-approach-to-change-primary-keys-in-an-existing-django-app for details

luc
+3  A: 

Not using raw_id fields for a key to 10000+ objects, then wondering why visiting the Admin brings a server to its knees

stevejalim