19 May 2017 code

If you are using rate limiting with Django Rest Framework you probably already know that it provides some pretty simple methods for setting global rate limits using DEFAULT_THROTTLE_RATES. You can also set rate limits for specific views using the throttle_classes property on class-based views or the @throttle_classes decorator for function based views.

What if you are using ViewSets but want different throttling rules to apply to different actions? Unfortunately DRF provides no official method of doing this. Luckily we can accomplish this functionality without too much fuss.

The solution comes from combining the ScopedRateThrottle throttle class with the get_throttles() method of APIView.

In our ViewSet let's override the get_throttles() method:

    class FooViewSet(viewsets.ModelViewSet):
        queryset = Foo.objects.all()
        serializer_class = FooSerializer

        def get_throttles(self):
            if self.action in ['delete', 'validate']:
                self.throttle_scope = 'foo.' + self.action
            return super().get_throttles()

        def validate(self, request):
            return Response('Validation!')

What we are doing here is pretty simple: checking to see if the action being performed is one we want to throttle , and if so, setting the throttle_scope property on the ViewSet.

This alone won't do anything (in fact it will error) so let's add the necessary config to settings.py to make it work:

            'user': '5000/day',
            'foo.delete': '100/day',
            'foo.validate': '10000/day'

The magic is contained within the ScopedRateThrottle. This class will look for the throttle_scope property on the view, and if found, look up a corresponding key in the DEFAULT_THROTTLE_RATES dictionary.

Notice that the keys are namespaced with .foo. This isn't necessary, but if you're using more than one ViewSet and you don't want the rules to apply to all of them, you should namespace them.

There you have it, throttling for ViewSets.

27 Feb 2017 code


I host quite a few sideprojects on my VPS. They range from static Jekyll sites (like this one) to large web applications. There's even some wordpress hiding in a corner, disgraced and neglected.

Despite the fact that none of these sites are actually useful for anything, they still need some poor bastard to keep then running. Over the years I've collected quite the assortment of nginx, uwsgi, php, apache, supervisor, and other configs. All of them written at various levels of understanding, none of them tracked anywhere, all of them confusing and terrible.

Docker to the rescue

One of the most under-spoken benefits of using docker is that a Dockerfile is literally a document describing how to get your garbage apps up and running. Ever forget a system dependency for some niche third part library? Have junky code that only runs with old versions of programming languages? It is nearly impossible to remember the myriad of caveats that come with deploying software.

If you're like me, and you don't write a ton of documentation, these are the kinds of things that can really bite you in the ass in the future when you have to modify or redeploy something.

Dockerizing your stuff is an excellent way of documenting what it actually takes to get something running. Plus you get all the other benefits of containerizing your apps, but there is nothing I can say here that hasn't been said before about that.

I've gone all in. I'm even using a jekyll docker image to generate this site now. As the only ruby application I ever actually use, I always forget the gems and other dependencies I need in order to run it - no longer.

It's all just a container away.

18 Nov 2016 code

This one got me for a bit. If you are using django-bootstrap3 and also want to use it's handy bootstrap_pagination template tag for generating pagination links, you may be in for an unplesant surprise if your view uses any GET parameters. While the django-bootstrap-pagination project handles this by default, django-bootstrap3 will not persist GET paramters between pages.

The key to using the bootstrap_pagination tag is the extra argument, which takes a string and appends it to each page. If you have the request_context context processor installed, you can pass in this string using the QueryDict urlencode() method. For example:

{% bootstrap_pagination page_obj extra=request.GET.urlencode %}

Voila. Pagination in django with bootstrap working as it should.

11 May 2016 astronomy, cycling

LCOGT has participated in this year's Cyclemaynia event in the best way we know how: by geeking out over both cycling and astronomy at the same time.

I thought it would be neat to do a scale model of the solar system that people could ride in order to experience in order to gain a deeper appreciation of how vast the solar system really is.


I was inspired by a model at Anza Borrego State Park which had 3-dimensional models of the planets along a dirt path in the desert. To do it our way we settled on using chalk to draw the planets along the Obern Trail. This is a popular carless path that helps link Santa Barbara to Goleta and sees pretty heavy traffic during rush hour.

We decided to place the Sun at the start of the path at Modoc rd and Neptune about 8 miles away at LCOGT's headquarters in Goleta, CA. Using this as the scale, we ended up with a ratio of about 0.245mi/AU


We decided to use a different scale for the size of the planets (otherwise they would be very, very tiny) and gave Jupiter a radius of 3 feet, or about 13x10-9 it's actual size. At this scale Mercury's radius was only 1.2 inches.

Trader Joes generously volunteered 2 chalk artists and on Monday the planets were drawn.

Thanks to everyone's support, this project was a success. See you on the trail!


09 May 2016 other

The first thing I noticed when I moved to Santa Barbara and started going outdoors was that everything just seemed a little more hostile than what I was used to. There are the ever present threats of overwhelming heat, lack of water, exposure and poison oak. By now, I've come to know some of the more subtle actors as well.

One of them I met today: Pitchfork Weed aka Bidens frondosa or, the Devil's Beggarticks, Devil's Pitchfork, Tickseed Sunflower... Would you believe it is closely related to the lovely sunflower? Neither would I, the family resemblance is illusive. Trust me, you don't want to run through a field of these, and their seeds are not pleasant.

Pitchfork Weed

I was walking down from the top of Tangerine Falls feeling pretty good about the stupid scramble I had just survived (despite a sprained wrist) when I felt a peculiar sensation on my legs. When I looked down and saw that they were covered, absolutely trashed, by tons of tiny pitchfork looking things. And they did not want to let go.

Pitchfork Pants

That's what pants are for I guess, so no harm no foul. I was still in a better situation than the dudes trying to scale the right side of the falls. I could hear their nervous laughter from a mile away. And then they stopped laughing, started yelling. Eventually they did make it out of sight - hope they made it!


13 Nov 2015 code

So I really like code linters. My coworkers know this. Actually, I got called a syntax Nazi today by a fellow developer. I'm OK with that. I believe in readability and consistency.

In my projects I make it impossible to make a git commit before the source code passes a flake8 check. How to perform this minor miracle you ask? With a simple git pre-commit hook:


flake8 .

When I commit, the hook executes. Since git knows a return of anything besides 0 means abort, it stops the commit from happening. Awesome.

Here is a terminal recording of it in action:

Don't forget to make your pre-commit hook file executable!

09 Oct 2015 code

Recently I started a new Django project, and this time I decided to go all in on Docker. No virtualenvs, no local databases - containers all the way.

There are about a million and ten articles about how to dockerize webapps by now. However, none of them seem to address one simple fact: we don't simply want to dockerize our applications, we want to develop them too!

sane-django-docker contains a sample django project webapp as well as the necessary config files to run both a development and production server.

Continue Reading...
10 Aug 2015 linux

I've been pretty good about not becoming a open source pundit. But today I feel like writing something useless.

My laptop's ssd crapped out yesterday so I spent the day restoring backups and installing operating systems. I've been using Ubuntu for a few years now, so I thought it would be great to revisit Gnome and see how the 3.x development is coming along, maybe even switch back.


Continue Reading...
22 May 2015 other

I was waiting in line at the supermarket this morning when I came across this cover of the June 2015 Vanity Fair:

Vanity Fair

Immediately something struck me as very, very wrong.

I know we all hope the new Star Wars will be good and make up for the complete travesty of episodes I, II and III. But I'm going to make a quick and uninformed judgment based solely on this magazine cover and say: no, no it won't.

Continue Reading...
29 Apr 2015 code

I just upgraded this VPS from Debian Wheezy to Jessie. The upgrade went pretty flawless, excpet some minor issues with postgres and the new bad systemd smell.

However, if you are running NGINX + PHP5-fpm, you may want to read the news that gets displayed during the upgrade:

nginx shipped a modified `fastcgi_params`, which declared `SCRIPT_FILENAME`
fastcgi_param. This line has now been removed. From now on we are also
shipping fastcgi.conf from the upstream repository, which includes a sane
`SCRIPT_FILENAME` parameter value.

So, if you are using fastcgi_params, you can try switching to fastcgi.conf
or manually set the relevant params.

After the upgrade, I was getting blank responses from nginx for all php scripts. No errors in nginx or fpm logs. After re-reading the news above, the following fix worked for me:

In /etc/nginx/sites-available/* change

include fastcgi_params


include fastcgi.conf

Hope this helps anyone in need.