Skip to content

Instantly share code, notes, and snippets.

@santiagobasulto
Created August 3, 2012 20:49
Show Gist options
  • Select an option

  • Save santiagobasulto/3251381 to your computer and use it in GitHub Desktop.

Select an option

Save santiagobasulto/3251381 to your computer and use it in GitHub Desktop.
Django DRY context managers
"""
You find yourself doing this all the time?
>>> car = Car.objects.get(id=1)
>>> if c.user != request.user:
>>> return HttpResponse("This car doesn't belong to you")
>>> c.brand = request.POST.get('brand_name')
>>> c.save()
Better to turn it into:
>>> try:
>>> with ensure_instance_owner(car, user) as c:
>>> c.brand = request.POST.get('brand_name')
>>> except NotInstanceOwner:
>>> return HttpResponse("This car doesn't belong to you")
"""
class NotInstanceOwner(Exception):
pass
class EnsureModelInstanceOwner(object):
def __init__(self, instance, user, owner_field='user'):
self.instance = instance
self.owner_field = owner_field
self.user = user
def __enter__(self):
owner = getattr(self.instance, self.owner_field)
if owner != self.user:
raise NotInstanceOwner()
return self.instance
def __exit__(self, exc_type, exc_value, traceback):
if exc_type is None:
self.instance.save()
ensure_instance_owner = EnsureModelInstanceOwner
"""
Now, I don't like that Car.objects.get, let's make it better:
>>> try:
>>> with get_and_ensure_owner(Car, 1, user) as c:
>>> c.brand = request.POST.get('brand_name')
>>> except Car.DoesNotExist:
>>> return HttpResponseNotFound()
>>> except NotInstanceOwner:
>>> return HttpResponse("This car doesn't belong to you")
"""
class GetAndEnsureOwner(object):
def __init__(self, model_class, pk, user, owner_field='user'):
self.model_class = model_class
self.pk = pk
self.owner_field = owner_field
self.user = user
def __enter__(self):
self.instance = self.model_class.objects.get(pk=self.pk)
owner = getattr(self.instance, self.owner_field)
if owner != self.user:
raise NotInstanceOwnerException()
return self.instance
def __exit__(self, exc_type, exc_value, traceback):
if exc_type is None:
self.instance.save()
get_and_ensure_owner = GetAndEnsureOwner
# License: DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
@nqnwebs
Copy link

nqnwebs commented Aug 3, 2012

de verdad te parece que es util esto? no es poco DRY tener que darle el el nombre del field que queremos chequear (si no es 'user') ? y si es DRY no te parece poco KISS ? no es sobreingenieria?

@santiagobasulto
Copy link
Author

Might be over-engineered. Don't know, for me it's useful. See the update (the second context manager). I'm just trying to share and have fun!

@fgallina
Copy link

fgallina commented Aug 3, 2012

Armar context managers para python es una divertido y groso, pero ¿Qué te evita usar los clásicos shortcuts? Esto para mí es más straightforward y djanguero:

from django.shortcuts import get_object_or_404
car = get_object_or_404(Car, pk=1, user=request.user)

@santiagobasulto
Copy link
Author

+1 a los shortcuts, obvio. El ejemplo completo sería:

from django.shortcuts import get_object_or_404
car = get_object_or_404(Car, pk=1, user=request.user)
if car.user != request.user:
     return HttpResponse("This car doesn't belong to you")
car.brand = request.POST.get('brand_name')
car.save()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment