Hacker News new | comments | show | ask | jobs | submit login
Choosing an API framework for Django (pydanny.com)
82 points by pydanny 1845 days ago | hide | past | web | 32 comments | favorite

> I don't want to say anything negative, but let's face it: django-piston is dead.

Typical "I don't want to be rude or anything..." bullshit. Django Piston is not a dead project. It is stable and not buggy, which may explain why there is not a flurry of activity ... but even then, the project has a dozen commits in the past six weeks.

Django ROA depends on Piston. Bitbucket is using Piston. Piston is not going anywhere.


Edit: A commenter on the blog voiced a similar opinion.

> Jon Morton:

> How is django-piston dead? it seems big websites like bitbucket are actively using it and it has had several recent commits: https://bitbucket.org/jespern/...

>> pydanny:

>> Show me docs and test coverage improvements and I'll reconsider.

So, it seems we assess a project's liveliness by code coverage and thorough documentation. Sounds like the author is wrong and is grasping for other reasons to not like Piston. Of course, the fool's too lazy to find the docs (right there on the project page) at https://bitbucket.org/jespern/django-piston/wiki/Documentati... , or to see the many tests for the code at https://bitbucket.org/jespern/django-piston/src/7c90898072ce...

In short, don't listen to the author. People like him are the reason we'll have three more web service libraries targeting Django within a year.

I like piston. I use piston. I want to go on using piston.

The current PyPI release of Piston (0.2.3) is six months old. It's incompatible with the current release version of Django (1.4). That Django release has been available for a month and a half, and available in beta for three months. This does not indicate a project that's in active development. A project in active development would get a release out the door so that if I run

pip install django django-piston

I get two pieces of software that work together.

Also, from lots of personal experience, the django-piston wiki doesn't cover a lot of critical material. As it's a wiki, you can't submit pull requests for it. Which means documentation is functionally scattered across blog articles like mine and Stack Overflow. In the Django community that's considered somewhat lame.

For me, the lack of documentation was a blessing!

When I first started investigating Piston I read almost every line of code that I was going to be using.

I'm glad I did!

Understanding Piston at the source level allowed me to create wrappers, mixins, and extensions that turned Piston into something that I was more comfortable with. I moved away from Piston (Piston lacks a few features that come baked-in by default w\ TP) to Tastypie, but, the experience was almost exactly the same.

I spent most of last week reading the Tastypie code and creating a tastypie_ext library that helps me do things my way and patch up a few of what I see as major issues (did you know that Tastypie will 500 by default if you pass it malformed json/yaml/xml? That is, client input can raise an unhandled exception on demand.)

As far as documentation goes, Tastypie isn't much better than Piston, and Django itself still has a few gaping holes in its documentation (I'm still waiting for better class-based view documentation before I adopt them completely.)

I tend to view frameworks and libraries as loaded guns... At the end of the day every person using a framework should understand how it works from top to bottom at the source level.

P.S. Thanks for django-uni-form (now django-crispy-forms)! I learned to use it by reading the source :D.

MCU - This is an incredible response. You win. :-)

>For me, the lack of documentation was a blessing! When I first started investigating Piston I read almost every line of code that I was going to be using. I'm glad I did!

Nice story, but you forgot the obligatory YMMV warning.

Reading the code is not a substitute for good documentation.

For me, it comes down to this issue: https://bitbucket.org/jespern/django-piston/issue/100/handle...

tl;dr: either documentation or cross-resource links will be broken - pick one. It's been broken for years. There is a kludge-around but it's a rake in the grass waiting for every user.

I also had a related issue which similarly means that a common Django feature breaks the documentation feature: https://bitbucket.org/jespern/django-piston/issue/142/handle...

I won't say piston is dead but I will say that my experience with tastypie is that something like this would be fixed in a day or two.

django-piston doesn't return serialized responses to invalid POST requests.

See my article at http://pydanny.blogspot.com/2010/07/getting-piston-forms-to-... which STILL gets a lot of hits.

That django-piston is 'stable' means work outside of maintenance has ceased. Which means a lot of people are going to this post to figure out what django-piston should do out of the box.

So now you've gone from "I don't want to be negative..." to full-on anti-Piston zealot? Looks like you just edited that post,

> Critical Update 2012/05/10!!!

> Critical Update 2012/05/10!!!

> Critical Update 2012/05/10!!!

(I guess you wanted one line per exclamation point there)

> Except for a critical security patch, django-piston has been unsupported for about 3 years. That is an eternity, and the number of forks to address multiple issues is cause for alarm. Also, the original author has left the project. Because of that, in it's place at this time I recommend django-tastypie. It is up-to-date, has very good documentation, supports OAUTH, and scored second place in the Django Packages thunderdome (it got nearly 3x as many points!). Another tool to consider is Django Rest Framework, which is as good as django-tastypie but lacks the OAUTH support.

Good god, man.

I edited that post before I blogged.

And I had a different Critical Update on that blog post for over 10 months with a harsher warning. I changed it today because I still had seen no progress but felt I should tone it down.

If the django-piston community updates and documents, I'll post something nicer. In the meantime, the critical update remains.

I'm curious where you saw that Bitbucket is using Piston. I'd be really interested to hear where and how extensively.

It's in the BitBucket footer:

  We run Django 1.3.1 / Piston 0.3dev / Git 1.7.6 / Hg 1.9.1 / Python 2.7.3
Presumably they use it for their APIs http://confluence.atlassian.com/display/BITBUCKET/Using+the+...

Given that Piston was developed in-house at Bitbucket, it's hardly surprising.

Thanks for dropping that knowledge. I didn't realize :)

No worries, sorry if I came across as a bit dickish

What's wrong with having three more web service libraries? Competition is good.

I used django-tastypie to create our restful API at work. It turned into a "round peg square hole" situation. In over half of my end points I had to over ride the default behaviour. This goes right down to how URL are generated. I spent a lot of time reading code.

So while it is very powerful, I probably won't be using it again for a large project.

This is exactly my experience. When we were writing the first version of the API for MobileWorks I chose django-tastypie. Within a few months we had overridden most of the default behavior and a lot of my time was spent studying the code-base of tasypie (which is fantastic BTW).

When it was time to write a new version, I decided to start from a clean slate and write it ourselves from grounds-up. We don't have some of the functionality that tasty-pie provided us out of the box but the maintenance and new features are extremely fast to write.

We are about to do the exact same thing. Tastypie was a good decision to begin with, but as our project evolves it becomes unrealistic.

I'm also not very happy with the XML serialization.

(I know, I know, it's XML. But people still use it.)

Also perhaps, is to choose Tastypie if you want API Key Authentication, and Django-Rest-Framework if you want oAuth.

That's the reason I chose Tastypie over everything else, but I really like the user-facing interface to Django-Rest better than I do Tastypie. Not enough to forego our preferred authentication-schema mind you, but I wouldn't hate having Class-based APIs either, but I haven't found that to be limiting in Tastypie either.

Also, there's a Tastypie implementation for Mongo floating around out there somewhere as well.

This is a github issue to integrate TastyPie into Swagger https://github.com/toastdriven/django-tastypie/issues/422

Swagger creates beautiful interactive sandboxes for REST APIs http://swagger.wordnik.com/

django-rest-framework doesn't come with OAuth out of the box, django-tastypie does. ;-)

Gah, you're right -- I was thinking of something altogether different.

Thanks for the correction.

I decided to use rest-framework after using tastypie for some time. Primarily because it seemed like less code and resources could be nested pretty easily, which is strongly adviced agains in tastypie.

Well, i must say that tastypie is just more mature, reliable, documented and support-friendly.

One of the comments on the original post complains about extra boilerplate with CBVs using django-rest-framework. I'll admit that I was concerned about this as well, but after working with it for a while, I have to say that mixins are a very natural pattern for API writing. You can string together a bunch of them to get auth, pagination, etc., in a very clean way.

I like the django-rest-framework CBV design, finding them much more elegant (and documented) than Django's own CBVs.

Honest question - Why do you need API framework for Django? I've created APIs for couple of Django products and never felt a need to use any framework. I felt Django's MVC framework is robust for creating any APIs. May be using some API framework will save some lines of code. But the joy of creating your own stuff can beat that anytime.

Using tastypie for two projects currently, it really is a great framework .. for REST. But if you need a more RPCish style API (say, like what Twitter has), it really is forcing a square peg into round hole and can get really ugly.

I just started working with Tastypie, and am really enjoying it. I'm in the process of writing an adapter to DynamoDB, and it's coming along very smoothly.

django-tastypie is nice and new, but it does not yet handle file uploads natively [1] which is why I went with django-piston for my project.

There is plans to support file uploads, but this was a deal breaker for my API.

[1] https://github.com/toastdriven/django-tastypie/issues/42

There is a mention of `json.dumps` being too naive to be used in an API, and there's good reason for that. If you want a more advanced JSON serializer for Django, here's what I use on NewsBlur.

From https://github.com/samuelclay/NewsBlur/blob/master/utils/jso...:

    def json_encode(data, *args, **kwargs):
        The main issues with django's default json serializer is that properties that
        had been added to an object dynamically are being ignored (and it also has 
        problems with some models).

        def _any(data):
            ret = None
            # Opps, we used to check if it is of type list, but that fails 
            # i.e. in the case of django.newforms.utils.ErrorList, which extends
            # the type "list". Oh man, that was a dumb mistake!
            if hasattr(data, 'to_json'):
                ret = data.to_json()
            elif isinstance(data, list):
                ret = _list(data)
            # Same as for lists above.
            elif isinstance(data, dict):
                ret = _dict(data)
            elif isinstance(data, Decimal):
                # json.dumps() cant handle Decimal
                ret = str(data)
            elif isinstance(data, models.query.QuerySet):
                # Actually its the same as a list ...
                ret = _list(data)
            elif isinstance(data, models.Model):
                ret = _model(data)
            # here we need to encode the string as unicode (otherwise we get utf-16 in the json-response)
            elif isinstance(data, basestring):
                ret = unicode(data)
            # see http://code.djangoproject.com/ticket/5868
            elif isinstance(data, Promise):
                ret = force_unicode(data)
            elif isinstance(data, datetime.datetime) or isinstance(data, datetime.date):
                ret = str(data)
                ret = data
            return ret
        def _model(data):
            ret = {}
            # If we only have a model, we only want to encode the fields.
            for f in data._meta.fields:
                ret[f.attname] = _any(getattr(data, f.attname))
            # And additionally encode arbitrary properties that had been added.
            fields = dir(data.__class__) + ret.keys()
            add_ons = [k for k in dir(data) if k not in fields]
            for k in add_ons:
                ret[k] = _any(getattr(data, k))
            return ret
        def _list(data):
            ret = []
            for v in data:
            return ret
        def _dict(data):
            ret = {}
            for k,v in data.items():
                ret[str(k)] = _any(v)
            return ret
        ret = _any(data)
        return json.dumps(ret)
You can get the imports from the link above, but the point is that you want to normalize any data structures into something that `json.dumps` can handle easily. Things like datetimes, models, and querysets.

A trick that I use is to give each of my models a `Model.to_json()` method, which looks something like this:

    def to_json(self):
        return {
            'date': self.date,
            'category': self.category,
            'title': self.title,
            'content': self.content,
            'with_user_id': self.with_user_id,
            'feed_id': self.feed_id,
            'content_id': self.content_id,

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | DMCA | Apply to YC | Contact