Hacker News new | past | comments | ask | show | jobs | submit login
Django 1.2 released (djangoproject.com)
212 points by twampss on May 17, 2010 | hide | past | favorite | 46 comments



Django advent is a very good series of articles about 1.2 http://djangoadvent.com/


My favorite quote on that is:

>"One of Django's core design philosophies is that template languages shouldn't try to be programming languages. To that end, we've kept the template language deliberately simplisitic so that you'd be more or less forced to push advanced logic up into the view."

Very view people seem to understand this at first unfortunately and try to do crazy things like swap out the template language for something else or add on a bunch of hacks. Why create additional custom template logic and the parsing instructions for converting it to python when you can just write the functionality in probably one line of standard python in your view fuction and have it run faster.


I disagree with this philosophy entirely and think it leads to a poor separation of concerns. There is plenty of template specific logic that has no business being in the view, and being forced to put it into your view because your template system is crippled ends up mixing concerns and causing more maintenance headaches than it needs to.

As a very simplistic (and somewhat contrived) example:

  % for label in ('Home','Features','Pricing','Contact'):
    <li>{{ label }}</li>
  % endfor
I'd much rather write that than repeat myself 5x, especially if what I'm doing is more complicated than a simple list tag.

In my mind, the view should be responsible for dealing with application logic and business logic. E.g. stuff like pulling things out of the database, dealing with GET/POST request data, validating forms, verifying user authentication and permissions, and whatever application specific logic is necessary.

The views should pass their data to the template, but not assume anything about how the template is being rendered, and not be doing things for the template. E.g. if you're doing something that renders a HTML snippet to pass into the template, you've done something wrong.

Once you start going down that road you make it much more difficult to render alternate versions of your templates (for mobile users for example).

Another case where the crippled templating system ends up pushing concerns into the wrong layer is rendering hierarchical data: e.g. a nested comments tree. Deciding how to render that data should be entirely within the scope of the template. But because of the lack of simple recursion support, the 'recommended practice' is to unravel the tree in your view code, and pass the unraveled version into the template. Or write your own template tag, but that is even more complicated.

It's also a bit silly that Django calls controllers 'views' and calls views 'templates', but perhaps it explains why they think it's okay to do view specific rendering at the controller level.


  <li>{{home}}</li>
  <li>{{home.features}}</li>
  <li>{{home.pricing}}</li>
  <li>{{home.contact}}</li>
You saved one line of code, but had to pass related data members that should be containerized in a home object to the template seperately, which means you actually used more total code if you include your view function. If you really want to do it that way, why not have a .list() interface method on your Home model that returns all of its string data members in a list?

  {%for label in home.list%}
    <li>{{label}}</li>
  {%endfor%}
But I think the first way reads more like HTML and allows you to style them seperately which your going to have to often do 90% of the time

Edit: also, you can recurse all day long in django with clever use of the {%include%} tag. The {%include%} tag is seriously worth looking into in any complicated situation. Writing your HTML in seperate chunks also make rolling out an AJAX version of the page really easy, because you can just render the included subcomponent in an ajax request instead of the page that includes it, using the same view function.


Like I said, it was a simplistic and contrived example. Obviously if the list was longer or the HTML contained more than a simple <li> tag, then the boilerplate repetition becomes more annoying.

But who said anything about a Home model? What if I was just adding a list of links to the footer of my page? E.g. things that have nothing to do with the application or data but are necessary for presentation on a webpage.


You're absolutely correct in saying that you shouldn't have to create boilerplate to have a footer with nav links on the bottom of every page.

I believe that the preferred way to do this in Django is by either creating a custom template tag, or by using template inheritance.

Template inheritance: create a base.html template with a {% block footer %} that can inherit and/or over ride it from any other template that needs.

Template Tags:

Create a simple tag that renders the comments thread, what's related links, etc... in a separate tag. This is the "preferred" way if you need to query the database for something that's related to multiple different views. For an example of that, see the django-pagination app.


Template inheritance is the way to go, and it's one of the most important features necesary to create modular sites.


I believe they suggest you write custom logic as a template tag, rather than in the view. However, I do agree that the naming conventions are unfortunate, to say the least.

In my experience not doing this separation encourages people solving controller-level problems on the view level, just because they can. Of course, it's just a "quick fix, I'll fix that properly later" everytime that happens. This philosophy is what drew me to Django in the first place, I really dislike HTML fragments in code, and having done enough rewriting of code when it's time to redesign the web site makes this a big feature for me.

Of course, being Django, it's loosely coupled and you can easily switch out the template language to something else.


Absolutely agree. Writing template tags in Django involves a lot of boilerplate. Compare for example Mako or Jinja2 where you can easily write a macro to handle something like nested comments.


FWIW it's pretty easy to write a {% macro %} tag for Django: http://alexgaynor.net/2008/dec/25/building-a-function-templa...


Sure, but that's a workaround for something that arguably belongs in the template language to start with.


Well, that's a matter of perspective. In any event if this were to be implemented in the Django template language it would be implemented as a tag like this, just as {% for %}, {% if %} and everything else are. Everything is a first class citizen :)


You can already drop in a nested comments system with Pinax super easy. But if you want to write your own, use {% include %} tag to render them recursively using multiple templates. This also allows you to implement AJAX loading\closing of subcomments much easier than if you came up with some macro to display\load every single comment in one template


The included simple_tag and filter decorators should be used for simple tags and filters. More sophisticated tags can specify a separate renderer class, which must be what you mean by "boilerplate."

  from django.core.urlresolvers import reverse
  from django.template import Library
  
  register = Library()
  
  @register.simple_tag
  def menu_item(req, viewname, label):
    url = reverse(viewname)
    cls = ''
    if url == req.path:
      cls += 'active'
    return '<li class="%s"><a href="%s">%s</a></li>' % (cls, url, label)
Using the tag:

  {% menu_item request 'accounts.views.profile' 'Your Account' %}
The only part of that I don't like is passing the request, but I'm willing to bet there's a simpler way to access the request object from the function.

A simple filter:

  @register.filter
  def subtract(x, y):
    """Subtracts the arg from the value"""
    return int(x) - int(y)
And maybe in a for loop for overlapping elements:

  <li style="z-index: {{ 100|subtract:forloop.counter }}">
Yes, I use two spaces in my Python code too.


The above solution is just plain ugly, HTML in Python.

Another PITA, where Django templates just fall down, is forms. Suppose you have a form:

   class MyForm(forms.Form):
        name = forms.CharField()
You then add that in the template:

    {{ form.name }}
All well and good; but what if you want to change the size, maxlength, or add a class ? These things clearly belong in the template, but no, you have to either add them in the form declaration:

    name = forms.CharField(widget=forms.TextInput(attrs={'class' : 'foo'}))
or in the view:

     form.fields['name'].widget.attrs = {'class' : 'foo'}
Both of which clearly break the separation of concerns. yes, you could write a template tag to get around this; but it's not in standard Django.

Contrast the following in Jinja2 (using WTForms, but you get the idea):

     {{ form.name(class_="foo") }}


>All well and good; but what if you want to change the size, maxlength, or add a class ?

Adding a class: Django gives every element of the form id values for easy styling in CSS. Just do {{form.as_p}} and see what it outputs.

size and max length: I'm fine with these in python as they correspond to the max-length that would be validated into a data member. If you mean pixel size on screen, this belongs neither in HTML or your template but in CSS, since browsers render forms completely differently regardless of their HTML attributes, you have to style their width\height in CSS to get anything consistent.


Unfortunately, the defaults stink. 1.2 remedies this for error messages at least.

as_p and co. should include some class describing the field type in the outer <p> tag so that a developer can style the label and error messages in a way specific to the field type.


I agree that this is pretty frustrating - it's one of the things my django-html package addresses: http://github.com/simonw/django-html

    {% field form.name class="myclass" %}


I had a similar workaround in a project, it did something like this:

    {% form.name|attrs:"class='foo', maxlength=20" %}
If Django templates allowed function calls however (as Jinja2 does) that would eliminate the need for a lot of these tags.


I'm not really a big fan of how writing custom template tags throws you back into the land of string substitution: the entire problem that templating languages were meant to solve in the first place!

Jinja2's macros are a much more elegant solution, IMO.


Anybody creating a template engine (or having to pick an engine) should read the paper justifying StringTemplate: http://www.cs.usfca.edu/~parrt/papers/mvc.templates.pdf

Generic summary: templates should only be able to do substitution, iteration, and existence checks on variables.


Far to simplistic.

There is a reason Django is introducing range checking and simple logic into their template statements. How often do you specify something like:

"If the amount owed is more than $100, make it red in the table"

That's not a question of separation of view/logic in my mind. It's a question of formatting. Forcing the view to resolve it down to a simple boolean statement results in a lot of cruft in the view layer that really doesn't belong there. It is just as evil to move presentation logic into a view as it is the other way around.


"If the amount owed is more than $100, make it red in the table"

Well, my usual advice on this goes back to the first time I encountered someone pushing a similar situation. In that case he was showing government safety ratings for cars, and if the rating was above a certain level wanted to show a special graphic because that got it some special certification.

Rather than try to force that logic into a template, I suggested giving the relevant model a "meets_certification_standard()" method, since that's the sort of thing you'd probably want to reuse for more than just presentation. And in your case I'd bet a similar approach would be the best solution.


Makes sense but a lot of decisions are much less "important" than that as some are purely about the rendering and don't have many meaning beyond it.


I agree with you but i've seen cases where we needed extra functionality to push some logic to the template, since that's what the design/UI guys use. It could have been done without adding separate template tags, but it certainly seems cleaner/logically consistent to keep things together and have the views/presentation as loosely bound as possible.

And for some reason, i don't personally enjoy polluting my views with statements that do nothing but populate context variables.


> polluting my views with statements that do nothing but populate context variables.

That's pretty much all I like to put in views. The rest goes in models/managers, or forms, or elsewhere.


Great to see further integrated support for geoDjango: http://docs.djangoproject.com/en/dev/releases/1.2/#geodjango



I strongly encourage people to read the release notes before upgrading, there are backwards incompatible changes from 1.1


Yay! No more {% ifnotequal %}{% endifnotequal %}


How bout adding composite primary key support....ARRRGHHH!!!


What major benefit (aside from legacy support) would this achieve that would be worth the effort?


... Situations where use of a composite key is the correct design decision, maybe? Like the very common case of join tables, for example. Surrogate keys in these situations are wasteful and unnecessary.

I find it seriously irritating when silly limitations like this in a framework corner you into bad data design.


So... next time a feature-proposal window rolls around, go sign yourself up to work on composite-key support. That's pretty much how things get done :)


I find it seriously irritating when silly limitations like this in a framework corner you into bad data design.

Frameworks by their very definition are not meant to cover 100% of use cases. They cover the 80% of issues that can be solved without composite keys, or those where the overhead in not having the correct design is negligible.

Perhaps in these cases you shouldn't be forcing the framework into a position it can't fit.


SUCH an annoyance! I've had to put a custom hacks in place to allow interfacing with legacy databases! Nasty nasty stuff :(


Thank you and congratulations to the team!


  "Object-level permissions"

  get_all_permissions(obj=None)

  New in Django 1.2

  If obj is passed in, only returns the permissions for this specific object.
I wander if this has, or rather can have, very positive impact on the admin site app? (Neatly applying row-level permissions that is.)


It just puts the plumbing in place to allow row level perms to built later on



Yes to both!


Great work guys. I do love django and everything it's doing. We can't let these ruby guys nab all the credit


whoa, easy there


When will settings.py be replaced by a YAML file?

just kidding

/me ducks


I worked somewhere a while ago that requested YAML configuration files, since that was how the sysadmin team administered other existing pieces of software. Since settings.py is executable Python code, adding support for reading settings from /conf/django-app.yaml took just a few lines of Python in the settings file itself.


Anyone running 1.2 on Google App Engine? Smooth sail?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: