Remove InstanceMixin auto-url magicks.

This commit is contained in:
Tom Christie 2012-02-23 09:21:01 +00:00
parent 2b59df004a
commit e15494a172
10 changed files with 35 additions and 88 deletions

View File

@ -25,14 +25,13 @@ __all__ = (
'ResponseMixin',
'AuthMixin',
'ResourceMixin',
# Reverse URL lookup behavior
'InstanceMixin',
# Model behavior mixins
'ReadModelMixin',
'CreateModelMixin',
'UpdateModelMixin',
'DeleteModelMixin',
'ListModelMixin'
'ListModelMixin',
'PaginatorMixin'
)
@ -444,30 +443,6 @@ class ResourceMixin(object):
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 ##########
@ -599,7 +574,7 @@ class CreateModelMixin(ModelMixin):
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)

View File

@ -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
@ -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):
"""
@ -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.
@ -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.
"""
@ -323,49 +317,6 @@ class ModelResource(FormResource):
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):
"""

View File

@ -5,7 +5,7 @@ from django.core.urlresolvers import reverse as django_reverse
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.

View File

@ -1,5 +1,4 @@
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
@ -7,18 +6,22 @@ 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

View File

@ -6,7 +6,6 @@ By setting or modifying class attributes on your view, you change it's predefine
"""
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
@ -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.
"""

View File

@ -2,6 +2,7 @@ from django.db import models
from django.template.defaultfilters import slugify
import uuid
def uuid_str():
return str(uuid.uuid1())
@ -14,6 +15,7 @@ RATING_CHOICES = ((0, 'Awful'),
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)
@ -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)

View File

@ -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},

View File

@ -1,4 +1,5 @@
from djangorestframework.resources import ModelResource
from djangorestframework.reverse import reverse
from modelresourceexample.models import MyModel
@ -6,3 +7,8 @@ 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)

View File

@ -2,7 +2,10 @@ from django.conf.urls.defaults import patterns, url
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'),
)

View File

@ -15,7 +15,11 @@ class ExampleView(View):
"""
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):