Django command line interface
Yesterday I started experimenting with a cli interface for a django application.
When you write a CLI you may need to pass complex data (dictionaries, python objects) to the application. So It's not a good idea to break their contents and send them via POST method to the server, it's better if you serialize them first.
On the application side, you have to find that data in the request.POST dictionary, deserialize it, do the things you want to do with it and finally return a json response to the client.
Bits
I wrote a BaseClient class that basically provides a send_request method. You just have to specify the remote action and the arguments to pass, and send_request takes care of the low level bits, POSTs the data and returns a deserialized response from the webserver.
At the server, a middleware detects if a request requires json response and if it's passing some serialized data. This data is binded to request.JSON.
Finally, the view uses a JSONResponse object which is a wrapper around the famous json_encoder by Wolfram Kriesing.
I have packaged all that code in a python module named json_utils so it can be reused.
Writing the application
Now using json_utils implementing a simple cli is pretty straight-forward:
Adding a middleware:
MIDDLEWARE_CLASSES = (
...
'json_utils.middleware.JSONMiddleware',
...
The NotesClient:
#notes-client.py
#!/bin/env python
from json_utils.client import BaseClient
class NotesClient(BaseClient):
"A command line client to interact with notes django-app"
def take_note(self, name, note, tags):
reqs = dict(title=name,body=note,tags=tags)
return self._send_request('take_note', reqs)
def list_notes(self,tags):
reqs = dict(tags=tags)
return self._send_request('list_notes',reqs)
if __name__ == "__main__":
notes_cl = NotesClient('http://localhost:8080/notes/',debug=True)
params = dict(name='A Demo note', note="Foo", tags=['test', 'demo'])
notes_cl.take_note(**params)
res = notes_cl.list_notes(tags=['demo'])
for n in res['objects']:
print n['title']
And the views.py serving the client:
#urls.py
urlpatterns = patterns('',
url(r'^take_note/$', view = 'notes.views.take_note',
name = 'take_note'
),
url(r'^list_notes/$', view = 'notes.views.list',
name = 'list'
),
)
#views.py
def take_note(request):
if request.format != 'json':
raise Http404
data = request.JSON
n = Note()
n.title = data['title']
n.body = data['body']
n.tags = ' '.join(data['tags'])
errors = n.validate()
if errors:
return JSONResponse({ 'errors' :errors })
n.save()
return JSONResponse({ 'object' : n })
def list(request):
if request.format != 'json':
raise Http404
data = request.JSON
tags = data['tags']
notes = Note.tagged.with_all(tags=tags)
return JSONResponse({'objects' : notes })
Well, that's it! It's the first time I'm messing with json and remote webapps, so I started by visiting djangosnippets.com and got a tone of good ideas about handling json in django. The thing I enjoyed the most is that in a cli-based app you don't have to write any css at all :)
If you want to check out the code, you can find json utils at github. Any feedback is more than welcome :)
Comments
Alexander Artemenko
0 minutes since post.
Interesting idea! Let's build a django shell!
I imaging it how interactive console just right in the browser, which allows all what
./manage shelldo.