RESTful API Design

I just stumbled on Geert Jansen’s book ‘Thoughts on RESTful API Design.’ Here he has documented things he learned while designing the Red Hat Enterprise Virtualization API.

The nice thing is that the source to the book is on github and you can read it on ReadTheDocs.org.

It outlines some good design decisions when creating an API and is well worth taking a look. It’s not too long of a read.

Posted in programming | Tagged , | Leave a comment

Repeating Sections in a Django Template

I have a need to have multiple sections of name/value pairs with a header on some pages. Something like:

<div class="row">
    <div class="span6">
        <div class="row"><div class="span3"><h2>History:</h2></div></div>
        <div class="row"><div class="span2">Date added to fleet:</div><div class="span2">{{plane.dateAddedToFleet}}</div></div>
        <div class="row"><div class="span2">Total Flight Time:</div><div class="span2">{{plane.totalFlightTime|asTime}}</div></div>
        <div class="row"><div class="span2">Total Number of Flights:</div><div class="span2">{{plane.totalNumberOfFlights}}</div></div>
    </div>
</div>

So that’s wrong. I first tried creating a custom tag to render the entire section that would be used like this within the django template:


{% specgroup "History" "Date added to fleet" plane.dateAddedToFleet "Total Flight Time:" plane.totalFlightTime|asTime "Total Number of Flights" plane.totalNumberOfFlights %}

The custom tag code for the above is:


# tags for groups of fields (such as on plane detail page)
@register.simple_tag
def specgroup(*args):
    """group header label1 value1 label2 value2 ...."""
    header= args[0]
    logging.getLogger().error(header)
    html = """
<div class="row">
    <div class="span6">
        <div class="row"><div class="span3"><h2>%s:</h2></div></div>
"""%header
    # parse remainder of args as  label1 value1 label2 value2 etc....
    data = args[1:]
    diter = iter(data)
    for d in diter:
        data = {}
        data["label"] = d
        data["value"] = diter.next()
        html += """  <div class="row"><div class="span2">%(label)s:</div><div class="span2">%(value)s</div></div>"""%data
    html += """
    </div>
</div>"""
    return html 

You cannot split the arguments across multiple lines to clean up the mess that is the call to the custom tag. So back to the drawing board.

I compromised with this:


{% specheader "History" %}
{% specdata "Date added to fleet" plane.dateAddedToFleet %}
{% specdata "Total Flight Time" plane.totalFlightTime|asTime %}
{% specdata "Total Number of Flights" plane.totalNumberOfFlights %}
{% specend %} 

It’s my favorite compromise between brevity and maintainability.

The custom tags to implement this are:


@register.simple_tag
def specheader(header):
    return """
<div class="row">
    <div class="span6">
        <div class="row"><div class="span3"><h2>%s:</h2></div></div>"""%header

@register.simple_tag
def specdata(label,value):
    return '<div class="row"><div class="span2">%s:</div><div class="span2">%s</div></div>'%(label, value)

@register.simple_tag
def specend():
    return "</div></div>"

Which is also cleaner than the all-in-one tag.

It’s not for me, but Skylar Savland on github created a Django Template macros with args and kwargs gist that is another solution to this problem.

I’d love to hear ideas that solve this problem in a better way.

Posted in Django, Python | 8 Comments

Rate limiting with django-ratelimit

I was playing around with James Socol’s django-ratelimit tonight. It provides a decorator to rate-limit view functions. Very nice! I wanted to use it for login blocking, and some minor changes helped this out. My forked version of django-ratelimit is a available on GitHub It adds a message when a call is blocked and the ability to clear the count for given user.

Adding it to django-userena sign-in was as simple as:

in userena/views.py:


from ratelimit.decorators import ratelimit, clear
@ratelimit(field='identification',rate="5/m", method="POST", block=True, error_message="You have too many invalid login attempts.  Please try again later")
@secure_required
def signin(request, auth_form=AuthenticationForm,.....
.
.
.
     #after successful login
     clear(request, field='identification') ### clear rate limiting 

Posted in Django, Python | Leave a comment

Custom Tag to Render Avatar in Django Userena

Here is a simple custom tag to render a users avatar (‘mugshot’) when using Django Userena. It optionally takes width and or height in pixels.

Place the following code in /templatetags/my_app_tags.py:

your_app/
    models.py
    templatetags/
        __init__.py
        my_app_tags.py


from django import template
register = template.Library()

from django import template
register = template.Library()

@register.simple_tag(takes_context=True)
def avatar(context, height=None, width=None):
    """ returns html for avatar, optional height/width supplied """
    user = context['user']
    widthAttr = 'width="%s"'%width if width is not None else ""
    heightAttr = 'height="%s"'%height if height is not None else ""
    return """<img %s %s class="avatar" src="%s"" alt="avatar image"  />"""%(heightAttr, widthAttr, user.get_profile().get_mugshot_url())

The following template shows how this could be used


{% load myapp_tags %}

{% avatar %}
{% avatar height=5 %}
{% avatar width=150 %}
{% avatar width=100 height=100 %} 
 

Posted in Django, Python | Leave a comment

Mothballed Software

We all probably have mothballed software – projects that didn’t go very far. This was one of mine, a rowing game!

Posted in rowing | Leave a comment

Django Image Field Overwrite with ImageKit

I’m using django-imagekit on a new site. I was having a problem that when a user uploaded a new image for the object, the system would not overwrite the existing image file, but instead would create a new file with a sequence number on the end. This was not the behavior I was looking for. Lockjaw’s answer on StackExchange handled the not-overwriting the existing file problem. ImageKit was still caching the previous image for any specfields. The solution is to call ‘.clear()’ after saving the new image to purge the ImageKit cache for that specfield/image.

So, the total solution is:


#Lockjaw's code on StackExchange
class OverwriteStorage(FileSystemStorage):   
    def get_available_name(self, name):
        if self.exists(name):
            os.remove(os.path.join(settings.MEDIA_ROOT, name))
        return name

def issue_plane_image_path(plane, filename):
    "return the canonical file name for an image on this plane instance"
    extension = os.path.splitext(filename)[1]
    return os.path.join('photos/planes', plane.slug+extension) 

class Plane(models.Model):
    image = models.ImageField(upload_to=issue_plane_image_path, storage=OverwriteFileStorage(), null=True, blank=True)
    gallery = ImageSpecField(...)
    thumbnail = ImageSpecField(...) 

    def clearImageCache(self):
       "invalidate all ImageKit spec caches"
       self.gallery.clear()
       self.thumbnail.clear()

and in the edit view:


.
.
if form.is_valid():
   form.save()
   plane.clearImageCache()

And now each instance has very few images (usually only one, but if a person uploads different filetypes such as a PNG then a JPG, they will both exist. I am OK with that.)

Posted in Django, Python | Leave a comment

TiddlyWiki with Firefox 15

TiddlyWiki saves (and exports) stopped working with the Firefox upgrade to 15. After trying a few changes to prefs.js, I found the post Will Firefox 16 support TiddlyWiki on the Mozilla site. It had a link to a Firefox extension called Tiddly Wiki 5, which fixed the problems I had with saving and the export plugin.

https://github.com/Jermolene/TiddlyWiki5

Posted in Uncategorized | Tagged , | Leave a comment

Custom Sort in Google Apps Spreadsheet

I use a Google Docs spreadsheet to track my personal projects. Only, I’m not aware of a way to save sort options in a Google Docs spreadsheet. The solution is to create a script. The following script will add a menu option that remembers sort parameters and makes use of a header row on the data. Detailed instructions on adding the script are here: http://productforums.google.com/forum/#!topic/docs/Kl9WEj6Kha0 and I just added skipping of the header row.

/**
* sort spreadsheet assuming first row is a header row
*/
function customSort() {
var sheet = SpreadsheetApp.getActiveSheet();
var allData = sheet.getDataRange();
var range = sheet.getRange(2,1, allData.getNumRows()-1, allData.getNumColumns());
range.sort( [1,2,4]); // see https://developers.google.com/apps-script/class_range#sort
};

/**
* Adds a custom menu to the active spreadsheet, containing a single menu item
* for invoking the readRows() function specified above.
* The onOpen() function, when defined, is automatically invoked whenever the
* spreadsheet is opened.
* For more information on using the Spreadsheet API, see
* https://developers.google.com/apps-script/service_spreadsheet
*/
function onOpen() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var entries = [{
name : "Custom Sort",
functionName : "customSort"
}];
sheet.addMenu(“Custom Scripts”, entries);
};

Posted in Uncategorized | Leave a comment

SimpleJson Error with django under google app engine

Since moving over to 64 bit windows 7, I’ve had this error when starting up:

"... py_zipimport.py:108] zipimporter('C:\\python25\\lib\\site-
packages\\simplejson-2.0.9-py2.5-win.egg', 'simplejson\\') ...
dev_appserver_main.py ... SetGlobals() ...
...
File "C:\Program 
Files\Google\google_appengine\google\appengine\dist\py_zipimport.py", line 
268, in _getitem__
info = _zipfile_cache[self._archive].getinfo(filename)
File "C:\Python25\lib\zipfile.py", line 462, in getinfo
return self.NameToInfo[name]
KeyError: 'simplejson\\_speedups.pyd'

The solution is from peplafi on the google app engine defect list:

It looks that it gives the error when you have installed simplejson in your python
dist and dev_appserver is mixing its own simplejson (which is located in
django\utils) and the python’s sipmlejson. The solution is to go to

The solution is to go to 

"c:\Program Files\Google\google_appengine\google\appengine\ext\key_range\__init__.py" 
, line 26

and change:

   import simplejson

 to:

   from django.utils import simplejson

Posted in Python | Leave a comment

Rynsc on Windows 7 Under Cygwin

I *finally* have rysnc working under Windows 7 without issuing permission-denied messages. Here’s the story:

The goal is to run a bash script that backs up a set of directories to a an external hard-drive. This script will run as me from a bash shell.

The destination hard drive is mounted as E: in this example. The bash script contains a series of rysnc commands similar to:

rsync -rltgovR --delete-after /cygdrive/h/music /cygdrive/e

This will mirror h:\music on E:\h\music with recursion.

The catch was getting permissions correct on the external drive. This took two commands run from a cmd.exe shell (bash shell should work if you escape the parameters correctly, but don’t bother for two commands).

E: is rsync destination for mirrors, ‘Kevin’ is the windows user name the script will be running under.


E:
cd \
takeown /f * /r /d y
icacls * /grant Kevin:(F) /T

This did it for me. Hope this helps.

Some other posts mention adding
none /cygdrive cygdrive binary,posix=0,user,noacl 0 0
to /etc/fstab. I tried this both ways and it did not seem to matter. For now it is commented out.

Posted in programming | Leave a comment