Commit e15494a1 by Tom Christie

Remove InstanceMixin auto-url magicks.

parent 2b59df00
...@@ -25,14 +25,13 @@ __all__ = ( ...@@ -25,14 +25,13 @@ __all__ = (
'ResponseMixin', 'ResponseMixin',
'AuthMixin', 'AuthMixin',
'ResourceMixin', 'ResourceMixin',
# Reverse URL lookup behavior
'InstanceMixin',
# Model behavior mixins # Model behavior mixins
'ReadModelMixin', 'ReadModelMixin',
'CreateModelMixin', 'CreateModelMixin',
'UpdateModelMixin', 'UpdateModelMixin',
'DeleteModelMixin', 'DeleteModelMixin',
'ListModelMixin' 'ListModelMixin',
'PaginatorMixin'
) )
...@@ -444,30 +443,6 @@ class ResourceMixin(object): ...@@ -444,30 +443,6 @@ class ResourceMixin(object):
else: else:
return None 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 ########## ########## Model Mixins ##########
...@@ -599,7 +574,7 @@ class CreateModelMixin(ModelMixin): ...@@ -599,7 +574,7 @@ class CreateModelMixin(ModelMixin):
manager.through(**data).save() manager.through(**data).save()
headers = {} headers = {}
if hasattr(instance, 'get_absolute_url'): if hasattr(self.resource, 'url'):
headers['Location'] = self.resource(self).url(instance) headers['Location'] = self.resource(self).url(instance)
return Response(status.HTTP_201_CREATED, instance, headers) return Response(status.HTTP_201_CREATED, instance, headers)
......
from django import forms 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.response import ErrorResponse
from djangorestframework.reverse import reverse from djangorestframework.serializer import Serializer
from djangorestframework.serializer import Serializer, _SkipField
from djangorestframework.utils import as_tuple from djangorestframework.utils import as_tuple
...@@ -20,7 +17,7 @@ class BaseResource(Serializer): ...@@ -20,7 +17,7 @@ class BaseResource(Serializer):
def __init__(self, view=None, depth=None, stack=[], **kwargs): def __init__(self, view=None, depth=None, stack=[], **kwargs):
super(BaseResource, self).__init__(depth, stack, **kwargs) super(BaseResource, self).__init__(depth, stack, **kwargs)
self.view = view self.view = view
self.request = view.request self.request = getattr(view, 'request', None)
def validate_request(self, data, files=None): def validate_request(self, data, files=None):
""" """
...@@ -224,9 +221,6 @@ class ModelResource(FormResource): ...@@ -224,9 +221,6 @@ class ModelResource(FormResource):
Also provides a :meth:`get_bound_form` method which may be used by some renderers. 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 form = None
""" """
The form class that should be used for request validation. The form class that should be used for request validation.
...@@ -260,7 +254,7 @@ class ModelResource(FormResource): ...@@ -260,7 +254,7 @@ class ModelResource(FormResource):
The list of fields to exclude. This is only used if :attr:`fields` is not set. 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. The list of extra fields to include. This is only used if :attr:`fields` is not set.
""" """
...@@ -323,49 +317,6 @@ class ModelResource(FormResource): ...@@ -323,49 +317,6 @@ class ModelResource(FormResource):
return form() 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 @property
def _model_fields_set(self): def _model_fields_set(self):
""" """
......
...@@ -5,7 +5,7 @@ from django.core.urlresolvers import reverse as django_reverse ...@@ -5,7 +5,7 @@ from django.core.urlresolvers import reverse as django_reverse
from django.utils.functional import lazy 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 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. and returns a fully qualified URL, using the request to get the base URL.
......
from django.conf.urls.defaults import patterns, url from django.conf.urls.defaults import patterns, url
from django.test import TestCase
from django.forms import ModelForm from django.forms import ModelForm
from django.contrib.auth.models import Group, User from django.contrib.auth.models import Group, User
from djangorestframework.resources import ModelResource from djangorestframework.resources import ModelResource
...@@ -7,18 +6,22 @@ from djangorestframework.views import ListOrCreateModelView, InstanceModelView ...@@ -7,18 +6,22 @@ from djangorestframework.views import ListOrCreateModelView, InstanceModelView
from djangorestframework.tests.models import CustomUser from djangorestframework.tests.models import CustomUser
from djangorestframework.tests.testcases import TestModelsTestCase from djangorestframework.tests.testcases import TestModelsTestCase
class GroupResource(ModelResource): class GroupResource(ModelResource):
model = Group model = Group
class UserForm(ModelForm): class UserForm(ModelForm):
class Meta: class Meta:
model = User model = User
exclude = ('last_login', 'date_joined') exclude = ('last_login', 'date_joined')
class UserResource(ModelResource): class UserResource(ModelResource):
model = User model = User
form = UserForm form = UserForm
class CustomUserResource(ModelResource): class CustomUserResource(ModelResource):
model = CustomUser model = CustomUser
......
...@@ -6,7 +6,6 @@ By setting or modifying class attributes on your view, you change it's predefine ...@@ -6,7 +6,6 @@ By setting or modifying class attributes on your view, you change it's predefine
""" """
import re import re
from django.core.urlresolvers import set_script_prefix, get_script_prefix
from django.http import HttpResponse from django.http import HttpResponse
from django.utils.html import escape from django.utils.html import escape
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
...@@ -269,7 +268,7 @@ class ModelView(View): ...@@ -269,7 +268,7 @@ class ModelView(View):
resource = resources.ModelResource 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. A view which provides default operations for read/update/delete against a model instance.
""" """
......
...@@ -2,6 +2,7 @@ from django.db import models ...@@ -2,6 +2,7 @@ from django.db import models
from django.template.defaultfilters import slugify from django.template.defaultfilters import slugify
import uuid import uuid
def uuid_str(): def uuid_str():
return str(uuid.uuid1()) return str(uuid.uuid1())
...@@ -14,6 +15,7 @@ RATING_CHOICES = ((0, 'Awful'), ...@@ -14,6 +15,7 @@ RATING_CHOICES = ((0, 'Awful'),
MAX_POSTS = 10 MAX_POSTS = 10
class BlogPost(models.Model): class BlogPost(models.Model):
key = models.CharField(primary_key=True, max_length=64, default=uuid_str, editable=False) key = models.CharField(primary_key=True, max_length=64, default=uuid_str, editable=False)
title = models.CharField(max_length=128) title = models.CharField(max_length=128)
...@@ -37,4 +39,3 @@ class Comment(models.Model): ...@@ -37,4 +39,3 @@ class Comment(models.Model):
comment = models.TextField() comment = models.TextField()
rating = models.IntegerField(blank=True, null=True, choices=RATING_CHOICES, help_text='How did you rate this post?') 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) created = models.DateTimeField(auto_now_add=True)
...@@ -11,6 +11,11 @@ class BlogPostResource(ModelResource): ...@@ -11,6 +11,11 @@ class BlogPostResource(ModelResource):
fields = ('created', 'title', 'slug', 'content', 'url', 'comments') fields = ('created', 'title', 'slug', 'content', 'url', 'comments')
ordering = ('-created',) ordering = ('-created',)
def url(self, instance):
return reverse('blog-post',
kwargs={'key': instance.key},
request=self.request)
def comments(self, instance): def comments(self, instance):
return reverse('comments', return reverse('comments',
kwargs={'blogpost': instance.key}, kwargs={'blogpost': instance.key},
......
from djangorestframework.resources import ModelResource from djangorestframework.resources import ModelResource
from djangorestframework.reverse import reverse
from modelresourceexample.models import MyModel from modelresourceexample.models import MyModel
...@@ -6,3 +7,8 @@ class MyModelResource(ModelResource): ...@@ -6,3 +7,8 @@ class MyModelResource(ModelResource):
model = MyModel model = MyModel
fields = ('foo', 'bar', 'baz', 'url') fields = ('foo', 'bar', 'baz', 'url')
ordering = ('created',) ordering = ('created',)
def url(self, instance):
return reverse('model-resource-instance',
kwargs={'id': instance.id},
request=self.request)
...@@ -2,7 +2,10 @@ from django.conf.urls.defaults import patterns, url ...@@ -2,7 +2,10 @@ from django.conf.urls.defaults import patterns, url
from djangorestframework.views import ListOrCreateModelView, InstanceModelView from djangorestframework.views import ListOrCreateModelView, InstanceModelView
from modelresourceexample.resources import MyModelResource from modelresourceexample.resources import MyModelResource
my_model_list = ListOrCreateModelView.as_view(resource=MyModelResource)
my_model_instance = InstanceModelView.as_view(resource=MyModelResource)
urlpatterns = patterns('', urlpatterns = patterns('',
url(r'^$', ListOrCreateModelView.as_view(resource=MyModelResource), name='model-resource-root'), url(r'^$', my_model_list, name='model-resource-root'),
url(r'^(?P<id>[0-9]+)/$', InstanceModelView.as_view(resource=MyModelResource), name='model-resource-instance'), url(r'^(?P<id>[0-9]+)/$', my_model_instance, name='model-resource-instance'),
) )
...@@ -15,7 +15,11 @@ class ExampleView(View): ...@@ -15,7 +15,11 @@ class ExampleView(View):
""" """
Handle GET requests, returning a list of URLs pointing to 3 other views. 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): class AnotherExampleView(View):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment