Skip to content

Commit

Permalink
Remove InstanceMixin auto-url magicks.
Browse files Browse the repository at this point in the history
  • Loading branch information
tomchristie committed Feb 23, 2012
1 parent 2b59df0 commit e15494a
Show file tree
Hide file tree
Showing 10 changed files with 35 additions and 88 deletions.
31 changes: 3 additions & 28 deletions djangorestframework/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,13 @@
'ResponseMixin',
'AuthMixin',
'ResourceMixin',
# Reverse URL lookup behavior
'InstanceMixin',
# Model behavior mixins
'ReadModelMixin',
'CreateModelMixin',
'UpdateModelMixin',
'DeleteModelMixin',
'ListModelMixin'
'ListModelMixin',
'PaginatorMixin'
)


Expand Down Expand Up @@ -444,30 +443,6 @@ def get_bound_form(self, content=None, method=None):
else:
return None

##########


class InstanceMixin(object):
"""
`Mixin` class that is used to identify a `View` class as being the canonical identifier
for the resources it is mapped to.
"""

@classmethod
def as_view(cls, **initkwargs):
"""
Store the callable object on the resource class that has been associated with this view.
"""
view = super(InstanceMixin, cls).as_view(**initkwargs)
resource = getattr(cls(**initkwargs), 'resource', None)
if resource:
# We do a little dance when we store the view callable...
# we need to store it wrapped in a 1-tuple, so that inspect will treat it
# as a function when we later look it up (rather than turning it into a method).
# This makes sure our URL reversing works ok.
resource.view_callable = (view,)
return view


########## Model Mixins ##########

Expand Down Expand Up @@ -599,7 +574,7 @@ def post(self, request, *args, **kwargs):
manager.through(**data).save()

headers = {}
if hasattr(instance, 'get_absolute_url'):
if hasattr(self.resource, 'url'):
headers['Location'] = self.resource(self).url(instance)
return Response(status.HTTP_201_CREATED, instance, headers)

Expand Down
55 changes: 3 additions & 52 deletions djangorestframework/resources.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
from django import forms
from django.core.urlresolvers import get_urlconf, get_resolver, NoReverseMatch
from django.db import models

from djangorestframework.response import ErrorResponse
from djangorestframework.reverse import reverse
from djangorestframework.serializer import Serializer, _SkipField
from djangorestframework.serializer import Serializer
from djangorestframework.utils import as_tuple


Expand All @@ -20,7 +17,7 @@ class BaseResource(Serializer):
def __init__(self, view=None, depth=None, stack=[], **kwargs):
super(BaseResource, self).__init__(depth, stack, **kwargs)
self.view = view
self.request = view.request
self.request = getattr(view, 'request', None)

def validate_request(self, data, files=None):
"""
Expand Down Expand Up @@ -224,9 +221,6 @@ class ModelResource(FormResource):
Also provides a :meth:`get_bound_form` method which may be used by some renderers.
"""

# Auto-register new ModelResource classes into _model_to_resource
#__metaclass__ = _RegisterModelResource

form = None
"""
The form class that should be used for request validation.
Expand Down Expand Up @@ -260,7 +254,7 @@ class ModelResource(FormResource):
The list of fields to exclude. This is only used if :attr:`fields` is not set.
"""

include = ('url',)
include = ()
"""
The list of extra fields to include. This is only used if :attr:`fields` is not set.
"""
Expand Down Expand Up @@ -323,49 +317,6 @@ class Meta:

return form()

def url(self, instance):
"""
Attempts to reverse resolve the url of the given model *instance* for this resource.
Requires a ``View`` with :class:`mixins.InstanceMixin` to have been created for this resource.
This method can be overridden if you need to set the resource url reversing explicitly.
"""

if not hasattr(self, 'view_callable'):
raise _SkipField

# dis does teh magicks...
urlconf = get_urlconf()
resolver = get_resolver(urlconf)

possibilities = resolver.reverse_dict.getlist(self.view_callable[0])
for tuple_item in possibilities:
possibility = tuple_item[0]
# pattern = tuple_item[1]
# Note: defaults = tuple_item[2] for django >= 1.3
for result, params in possibility:

#instance_attrs = dict([ (param, getattr(instance, param)) for param in params if hasattr(instance, param) ])

instance_attrs = {}
for param in params:
if not hasattr(instance, param):
continue
attr = getattr(instance, param)
if isinstance(attr, models.Model):
instance_attrs[param] = attr.pk
else:
instance_attrs[param] = attr

try:
return reverse(self.view_callable[0],
kwargs=instance_attrs,
request=self.view.request)
except NoReverseMatch:
pass
raise _SkipField

@property
def _model_fields_set(self):
"""
Expand Down
2 changes: 1 addition & 1 deletion djangorestframework/reverse.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from django.utils.functional import lazy


def reverse(viewname, request, *args, **kwargs):
def reverse(viewname, *args, **kwargs):
"""
Same as `django.core.urlresolvers.reverse`, but optionally takes a request
and returns a fully qualified URL, using the request to get the base URL.
Expand Down
5 changes: 4 additions & 1 deletion djangorestframework/tests/modelviews.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
from django.conf.urls.defaults import patterns, url
from django.test import TestCase
from django.forms import ModelForm
from django.contrib.auth.models import Group, User
from djangorestframework.resources import ModelResource
from djangorestframework.views import ListOrCreateModelView, InstanceModelView
from djangorestframework.tests.models import CustomUser
from djangorestframework.tests.testcases import TestModelsTestCase


class GroupResource(ModelResource):
model = Group


class UserForm(ModelForm):
class Meta:
model = User
exclude = ('last_login', 'date_joined')


class UserResource(ModelResource):
model = User
form = UserForm


class CustomUserResource(ModelResource):
model = CustomUser

Expand Down
3 changes: 1 addition & 2 deletions djangorestframework/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
"""

import re
from django.core.urlresolvers import set_script_prefix, get_script_prefix
from django.http import HttpResponse
from django.utils.html import escape
from django.utils.safestring import mark_safe
Expand Down Expand Up @@ -269,7 +268,7 @@ class ModelView(View):
resource = resources.ModelResource


class InstanceModelView(InstanceMixin, ReadModelMixin, UpdateModelMixin, DeleteModelMixin, ModelView):
class InstanceModelView(ReadModelMixin, UpdateModelMixin, DeleteModelMixin, ModelView):
"""
A view which provides default operations for read/update/delete against a model instance.
"""
Expand Down
3 changes: 2 additions & 1 deletion examples/blogpost/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from django.template.defaultfilters import slugify
import uuid


def uuid_str():
return str(uuid.uuid1())

Expand All @@ -14,6 +15,7 @@ def uuid_str():

MAX_POSTS = 10


class BlogPost(models.Model):
key = models.CharField(primary_key=True, max_length=64, default=uuid_str, editable=False)
title = models.CharField(max_length=128)
Expand All @@ -37,4 +39,3 @@ class Comment(models.Model):
comment = models.TextField()
rating = models.IntegerField(blank=True, null=True, choices=RATING_CHOICES, help_text='How did you rate this post?')
created = models.DateTimeField(auto_now_add=True)

5 changes: 5 additions & 0 deletions examples/blogpost/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ class BlogPostResource(ModelResource):
fields = ('created', 'title', 'slug', 'content', 'url', 'comments')
ordering = ('-created',)

def url(self, instance):
return reverse('blog-post',
kwargs={'key': instance.key},
request=self.request)

def comments(self, instance):
return reverse('comments',
kwargs={'blogpost': instance.key},
Expand Down
6 changes: 6 additions & 0 deletions examples/modelresourceexample/resources.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
from djangorestframework.resources import ModelResource
from djangorestframework.reverse import reverse
from modelresourceexample.models import MyModel


class MyModelResource(ModelResource):
model = MyModel
fields = ('foo', 'bar', 'baz', 'url')
ordering = ('created',)

def url(self, instance):
return reverse('model-resource-instance',
kwargs={'id': instance.id},
request=self.request)
7 changes: 5 additions & 2 deletions examples/modelresourceexample/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
from djangorestframework.views import ListOrCreateModelView, InstanceModelView
from modelresourceexample.resources import MyModelResource

my_model_list = ListOrCreateModelView.as_view(resource=MyModelResource)
my_model_instance = InstanceModelView.as_view(resource=MyModelResource)

urlpatterns = patterns('',
url(r'^$', ListOrCreateModelView.as_view(resource=MyModelResource), name='model-resource-root'),
url(r'^(?P<id>[0-9]+)/$', InstanceModelView.as_view(resource=MyModelResource), name='model-resource-instance'),
url(r'^$', my_model_list, name='model-resource-root'),
url(r'^(?P<id>[0-9]+)/$', my_model_instance, name='model-resource-instance'),
)
6 changes: 5 additions & 1 deletion examples/resourceexample/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ def get(self, request):
"""
Handle GET requests, returning a list of URLs pointing to 3 other views.
"""
return {"Some other resources": [reverse('another-example', kwargs={'num':num}, request=request) for num in range(3)]}
resource_urls = [reverse('another-example',
kwargs={'num': num},
request=request)
for num in range(3)]
return {"Some other resources": resource_urls}


class AnotherExampleView(View):
Expand Down

0 comments on commit e15494a

Please sign in to comment.