Created
August 3, 2012 20:49
-
-
Save santiagobasulto/3251381 to your computer and use it in GitHub Desktop.
Django DRY context managers
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| """ | |
| 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 |
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!
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)
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
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?