mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-01-24 08:14:16 +03:00
Merge remote branch 'tomchristie/master'
This commit is contained in:
commit
add5f32e8a
2
AUTHORS
2
AUTHORS
|
@ -28,6 +28,8 @@ Sebastian Żurek <sebzur>
|
|||
Benoit C <dzen>
|
||||
Chris Pickett <bunchesofdonald>
|
||||
Ben Timby <btimby>
|
||||
Michele Lazzeri <michelelazzeri-nextage>
|
||||
Camille Harang <mammique>
|
||||
|
||||
THANKS TO:
|
||||
|
||||
|
|
|
@ -1,9 +1,44 @@
|
|||
Release Notes
|
||||
=============
|
||||
|
||||
development
|
||||
-----------
|
||||
|
||||
* Saner template variable autoescaping.
|
||||
* Use `staticfiles` for css files.
|
||||
- Easier to override. Won't conflict with customised admin styles (eg grappelli)
|
||||
* Drop implied 'pk' filter if last arg in urlconf is unnamed.
|
||||
- Too magical. Explict is better than implicit.
|
||||
* Tider setup.py
|
||||
* Bugfixes:
|
||||
- Bug with PerUserThrottling when user contains unicode chars.
|
||||
|
||||
0.3.2
|
||||
-----
|
||||
|
||||
* Bugfixes:
|
||||
* Fix 403 for POST and PUT from the UI with UserLoggedInAuthentication (#115)
|
||||
* serialize_model method in serializer.py may cause wrong value (#73)
|
||||
* Fix Error when clicking OPTIONS button (#146)
|
||||
* And many other fixes
|
||||
* Remove short status codes
|
||||
- Zen of Python: "There should be one-- and preferably only one --obvious way to do it."
|
||||
* get_name, get_description become methods on the view - makes them overridable.
|
||||
* Improved model mixin API - Hooks for build_query, get_instance_data, get_model, get_queryset, get_ordering
|
||||
|
||||
0.3.1
|
||||
-----
|
||||
|
||||
* [not documented]
|
||||
|
||||
0.3.0
|
||||
-----
|
||||
|
||||
* JSONP Support
|
||||
* Bugfixes, including support for latest markdown release
|
||||
|
||||
0.2.4
|
||||
-----
|
||||
|
||||
* Fix broken IsAdminUser permission.
|
||||
* OPTIONS support.
|
||||
|
@ -11,20 +46,24 @@
|
|||
* Drop mentions of Blog, BitBucket.
|
||||
|
||||
0.2.3
|
||||
-----
|
||||
|
||||
* Fix some throttling bugs.
|
||||
* ``X-Throttle`` header on throttling.
|
||||
* Support for nesting resources on related models.
|
||||
|
||||
0.2.2
|
||||
-----
|
||||
|
||||
* Throttling support complete.
|
||||
|
||||
0.2.1
|
||||
-----
|
||||
|
||||
* Couple of simple bugfixes over 0.2.0
|
||||
|
||||
0.2.0
|
||||
-----
|
||||
|
||||
* Big refactoring changes since 0.1.0, ask on the discussion group if anything isn't clear.
|
||||
The public API has been massively cleaned up. Expect it to be fairly stable from here on in.
|
||||
|
@ -49,9 +88,11 @@
|
|||
You can reuse these mixin classes individually without using the ``View`` class.
|
||||
|
||||
0.1.1
|
||||
-----
|
||||
|
||||
* Final build before pulling in all the refactoring changes for 0.2, in case anyone needs to hang on to 0.1.
|
||||
|
||||
0.1.0
|
||||
-----
|
||||
|
||||
* Initial release.
|
|
@ -1,5 +1,5 @@
|
|||
recursive-include djangorestframework/static *.ico *.txt
|
||||
recursive-include djangorestframework/static *.ico *.txt *.css
|
||||
recursive-include djangorestframework/templates *.txt *.html
|
||||
recursive-include examples .keep *.py *.txt
|
||||
recursive-include docs *.py *.rst *.html *.txt
|
||||
include AUTHORS LICENSE requirements.txt tox.ini
|
||||
include AUTHORS LICENSE CHANGELOG.rst requirements.txt tox.ini
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
Django REST framework
|
||||
=====================
|
||||
|
||||
Django REST framework makes it easy to build well-connected, self-describing RESTful Web APIs.
|
||||
**Django REST framework makes it easy to build well-connected, self-describing RESTful Web APIs.**
|
||||
|
||||
**Author:** Tom Christie. `Follow me on Twitter <https://twitter.com/_tomchristie>`_.
|
||||
|
||||
Overview
|
||||
========
|
||||
|
||||
Features:
|
||||
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
__version__ = '0.3.2-dev'
|
||||
__version__ = '0.3.3-dev'
|
||||
|
||||
VERSION = __version__ # synonym
|
||||
|
|
|
@ -6,7 +6,6 @@ classes that can be added to a `View`.
|
|||
from django.contrib.auth.models import AnonymousUser
|
||||
from django.core.paginator import Paginator
|
||||
from django.db.models.fields.related import ForeignKey
|
||||
from django.db.models.query import Q
|
||||
from django.http import HttpResponse
|
||||
from urlobject import URLObject
|
||||
|
||||
|
@ -486,44 +485,25 @@ class ModelMixin(object):
|
|||
|
||||
queryset = None
|
||||
|
||||
def build_query(self, *args, **kwargs):
|
||||
""" Returns django.db.models.Q object to be used for the objects retrival.
|
||||
|
||||
Arguments:
|
||||
- args: unnamed URL arguments
|
||||
- kwargs: named URL arguments
|
||||
|
||||
If a URL passes any arguments to the view being the QueryMixin subclass
|
||||
build_query manages the arguments and provides the Q object that will be
|
||||
used for the objects retrival with filter/get queryset methods.
|
||||
|
||||
Technically, neither args nor kwargs have to be provided, however the default
|
||||
behaviour is to map all kwargs as the query constructors so that if this
|
||||
method is not overriden only kwargs keys being model fields are valid.
|
||||
|
||||
If positional args are provided, the last one argument is understood
|
||||
as the primary key. However this usage should be considered
|
||||
deperecated, and will be removed in a future version.
|
||||
def get_query_kwargs(self, *args, **kwargs):
|
||||
"""
|
||||
Return a dict of kwargs that will be used to build the
|
||||
model instance retrieval or to filter querysets.
|
||||
"""
|
||||
|
||||
tmp = dict(kwargs)
|
||||
kwargs = dict(kwargs)
|
||||
|
||||
# If the URLconf includes a .(?P<format>\w+) pattern to match against
|
||||
# a .json, .xml suffix, then drop the 'format' kwarg before
|
||||
# constructing the query.
|
||||
if BaseRenderer._FORMAT_QUERY_PARAM in tmp:
|
||||
del tmp[BaseRenderer._FORMAT_QUERY_PARAM]
|
||||
if BaseRenderer._FORMAT_QUERY_PARAM in kwargs:
|
||||
del kwargs[BaseRenderer._FORMAT_QUERY_PARAM]
|
||||
|
||||
if args:
|
||||
# If we have any no kwargs then assume the last arg represents the
|
||||
# primrary key. Otherwise assume the kwargs uniquely identify the
|
||||
# model.
|
||||
tmp.update({'pk': args[-1]})
|
||||
return Q(**tmp)
|
||||
return kwargs
|
||||
|
||||
def get_instance_data(self, model, content, **kwargs):
|
||||
"""
|
||||
Returns the dict with the data for model instance creation/update query.
|
||||
Returns the dict with the data for model instance creation/update.
|
||||
|
||||
Arguments:
|
||||
- model: model class (django.db.models.Model subclass) to work with
|
||||
|
@ -548,12 +528,11 @@ class ModelMixin(object):
|
|||
|
||||
return all_kw_args
|
||||
|
||||
def get_object(self, *args, **kwargs):
|
||||
def get_instance(self, **kwargs):
|
||||
"""
|
||||
Get the instance object for read/update/delete requests.
|
||||
Get a model instance for read/update/delete requests.
|
||||
"""
|
||||
model = self.resource.model
|
||||
return model.objects.get(self.build_query(*args, **kwargs))
|
||||
return self.get_queryset().get(**kwargs)
|
||||
|
||||
def get_queryset(self):
|
||||
"""
|
||||
|
@ -575,21 +554,15 @@ class ReadModelMixin(ModelMixin):
|
|||
"""
|
||||
def get(self, request, *args, **kwargs):
|
||||
model = self.resource.model
|
||||
query_kwargs = self.get_query_kwargs(request, *args, **kwargs)
|
||||
|
||||
try:
|
||||
self.model_instance = self.get_object(*args, **kwargs)
|
||||
self.model_instance = self.get_instance(**query_kwargs)
|
||||
except model.DoesNotExist:
|
||||
raise ErrorResponse(status.HTTP_404_NOT_FOUND)
|
||||
|
||||
return self.model_instance
|
||||
|
||||
def build_query(self, *args, **kwargs):
|
||||
# Build query is overriden to filter the kwargs priori
|
||||
# to use them as build_query argument
|
||||
filtered_keywords = kwargs.copy()
|
||||
|
||||
return super(ReadModelMixin, self).build_query(*args, **filtered_keywords)
|
||||
|
||||
|
||||
class CreateModelMixin(ModelMixin):
|
||||
"""
|
||||
|
@ -637,11 +610,12 @@ class UpdateModelMixin(ModelMixin):
|
|||
"""
|
||||
def put(self, request, *args, **kwargs):
|
||||
model = self.resource.model
|
||||
query_kwargs = self.get_query_kwargs(request, *args, **kwargs)
|
||||
|
||||
# TODO: update on the url of a non-existing resource url doesn't work
|
||||
# correctly at the moment - will end up with a new url
|
||||
try:
|
||||
self.model_instance = self.get_object(*args, **kwargs)
|
||||
self.model_instance = self.get_instance(**query_kwargs)
|
||||
|
||||
for (key, val) in self.CONTENT.items():
|
||||
setattr(self.model_instance, key, val)
|
||||
|
@ -657,9 +631,10 @@ class DeleteModelMixin(ModelMixin):
|
|||
"""
|
||||
def delete(self, request, *args, **kwargs):
|
||||
model = self.resource.model
|
||||
query_kwargs = self.get_query_kwargs(request, *args, **kwargs)
|
||||
|
||||
try:
|
||||
instance = self.get_object(*args, **kwargs)
|
||||
instance = self.get_instance(**query_kwargs)
|
||||
except model.DoesNotExist:
|
||||
raise ErrorResponse(status.HTTP_404_NOT_FOUND, None, {})
|
||||
|
||||
|
@ -675,8 +650,9 @@ class ListModelMixin(ModelMixin):
|
|||
def get(self, request, *args, **kwargs):
|
||||
queryset = self.get_queryset()
|
||||
ordering = self.get_ordering()
|
||||
query_kwargs = self.get_query_kwargs(request, *args, **kwargs)
|
||||
|
||||
queryset = queryset.filter(self.build_query(**kwargs))
|
||||
queryset = queryset.filter(**query_kwargs)
|
||||
if ordering:
|
||||
queryset = queryset.order_by(*ordering)
|
||||
|
||||
|
@ -710,7 +686,7 @@ class PaginatorMixin(object):
|
|||
Constructs a url used for getting the next/previous urls
|
||||
"""
|
||||
url = URLObject.parse(self.request.get_full_path())
|
||||
url = url.add_query_param('page', page_number)
|
||||
url = url.set_query_param('page', page_number)
|
||||
|
||||
limit = self.get_limit()
|
||||
if limit != self.limit:
|
||||
|
|
|
@ -188,7 +188,7 @@ class PerUserThrottling(BaseThrottle):
|
|||
|
||||
def get_cache_key(self):
|
||||
if self.auth.is_authenticated():
|
||||
ident = str(self.auth)
|
||||
ident = self.auth.id
|
||||
else:
|
||||
ident = self.view.request.META.get('REMOTE_ADDR', None)
|
||||
return 'throttle_user_%s' % ident
|
||||
|
|
|
@ -34,7 +34,7 @@ class Response(object):
|
|||
return STATUS_CODE_TEXT.get(self.status, '')
|
||||
|
||||
|
||||
class ErrorResponse(BaseException):
|
||||
class ErrorResponse(Exception):
|
||||
"""
|
||||
An exception representing an Response that should be returned immediately.
|
||||
Any content should be serialized as-is, without being filtered.
|
||||
|
|
|
@ -97,6 +97,14 @@ INSTALLED_APPS = (
|
|||
'djangorestframework',
|
||||
)
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
import django
|
||||
|
||||
if django.VERSION < (1, 3):
|
||||
INSTALLED_APPS += ('staticfiles',)
|
||||
|
||||
|
||||
# OAuth support is optional, so we only test oauth if it's installed.
|
||||
try:
|
||||
import oauth_provider
|
||||
|
|
1209
djangorestframework/static/css/djangorestframework.css
Normal file
1209
djangorestframework/static/css/djangorestframework.css
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -1,54 +1,44 @@
|
|||
{% load static %}
|
||||
<html>
|
||||
<head>
|
||||
{% if ADMIN_MEDIA_PREFIX %}
|
||||
<link rel="stylesheet" type="text/css" href='{{ADMIN_MEDIA_PREFIX}}css/base.css'/>
|
||||
<link rel="stylesheet" type="text/css" href='{{ADMIN_MEDIA_PREFIX}}css/forms.css'/>
|
||||
<link rel="stylesheet" type="text/css" href='{{ADMIN_MEDIA_PREFIX}}css/login.css' />
|
||||
{% else %}
|
||||
<link rel="stylesheet" type="text/css" href='{{STATIC_URL}}admin/css/base.css'/>
|
||||
<link rel="stylesheet" type="text/css" href='{{STATIC_URL}}admin/css/forms.css'/>
|
||||
<link rel="stylesheet" type="text/css" href='{{STATIC_URL}}admin/css/login.css' />
|
||||
{% endif %}
|
||||
<style>
|
||||
.form-row {border-bottom: 0.25em !important}</style>
|
||||
</head>
|
||||
<body class="login">
|
||||
<div id="container">
|
||||
<div id="header">
|
||||
<div id="branding">
|
||||
<h1 id="site-name">Django REST framework</h1>
|
||||
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href='{% get_static_prefix %}css/djangorestframework.css'/>
|
||||
</head>
|
||||
|
||||
<body class="login">
|
||||
|
||||
<div id="container">
|
||||
|
||||
<div id="header">
|
||||
<div id="branding">
|
||||
<h1 id="site-name">Django REST framework</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="content" class="colM">
|
||||
<div id="content-main">
|
||||
<form method="post" action="{% url djangorestframework.utils.staticviews.api_login %}" id="login-form">
|
||||
{% csrf_token %}
|
||||
<div class="form-row">
|
||||
<label for="id_username">Username:</label> {{ form.username }}
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="id_password">Password:</label> {{ form.password }}
|
||||
<input type="hidden" name="next" value="{{ next }}" />
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label> </label><input type="submit" value="Log in">
|
||||
</div>
|
||||
</form>
|
||||
<script type="text/javascript">
|
||||
document.getElementById('id_username').focus()
|
||||
</script>
|
||||
</div>
|
||||
<br class="clear">
|
||||
</div>
|
||||
|
||||
<div id="footer"></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="content" class="colM">
|
||||
|
||||
<div id="content-main">
|
||||
<form method="post" action="{% url djangorestframework.utils.staticviews.api_login %}" id="login-form">
|
||||
{% csrf_token %}
|
||||
<div class="form-row">
|
||||
<label for="id_username">Username:</label> {{ form.username }}
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label for="id_password">Password:</label> {{ form.password }}
|
||||
<input type="hidden" name="next" value="{{ next }}" />
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<label> </label><input type="submit" value="Log in">
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<script type="text/javascript">
|
||||
document.getElementById('id_username').focus()
|
||||
</script>
|
||||
</div>
|
||||
|
||||
|
||||
<br class="clear">
|
||||
</div>
|
||||
|
||||
<div id="footer"></div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,25 +1,14 @@
|
|||
{% load urlize_quoted_links %}{% load add_query_param %}<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
{% load urlize_quoted_links %}
|
||||
{% load add_query_param %}
|
||||
{% load static %}
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<style>
|
||||
/* Override some of the Django admin styling */
|
||||
#site-name a {color: #F4F379 !important;}
|
||||
.errorlist {display: inline !important}
|
||||
.errorlist li {display: inline !important; background: white !important; color: black !important; border: 0 !important;}
|
||||
/* Custom styles */
|
||||
.version{font-size:8px;}
|
||||
</style>
|
||||
{% if ADMIN_MEDIA_PREFIX %}
|
||||
<link rel="stylesheet" type="text/css" href='{{ADMIN_MEDIA_PREFIX}}css/base.css'/>
|
||||
<link rel="stylesheet" type="text/css" href='{{ADMIN_MEDIA_PREFIX}}css/forms.css'/>
|
||||
{% else %}
|
||||
<link rel="stylesheet" type="text/css" href='{{STATIC_URL}}admin/css/base.css'/>
|
||||
<link rel="stylesheet" type="text/css" href='{{STATIC_URL}}admin/css/forms.css'/>
|
||||
{% endif %}
|
||||
<title>Django REST framework - {{ name }}</title>
|
||||
</head>
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href='{% get_static_prefix %}css/djangorestframework.css'/>
|
||||
<title>Django REST framework - {{ name }}</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container">
|
||||
|
||||
|
@ -34,7 +23,7 @@
|
|||
|
||||
<div class="breadcrumbs">
|
||||
{% for breadcrumb_name, breadcrumb_url in breadcrumblist %}
|
||||
<a href="{{breadcrumb_url}}">{{breadcrumb_name}}</a> {% if not forloop.last %}›{% endif %}
|
||||
<a href="{{ breadcrumb_url }}">{{ breadcrumb_name }}</a> {% if not forloop.last %}›{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
|
@ -50,7 +39,7 @@
|
|||
|
||||
<div class='content-main'>
|
||||
<h1>{{ name }}</h1>
|
||||
<p>{% autoescape off %}{{ description }}{% endautoescape %}</p>
|
||||
<p>{{ description }}</p>
|
||||
<div class='module'>
|
||||
<pre><b>{{ response.status }} {{ response.status_text }}</b>{% autoescape off %}
|
||||
{% for key, val in response.headers.items %}<b>{{ key }}:</b> {{ val|urlize_quoted_links }}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{{ name }}
|
||||
{% autoescape off %}{{ name }}
|
||||
|
||||
{{ description }}
|
||||
|
||||
{% autoescape off %}HTTP/1.0 {{ response.status }} {{ response.status_text }}
|
||||
HTTP/1.0 {{ response.status }} {{ response.status_text }}
|
||||
{% for key, val in response.headers.items %}{{ key }}: {{ val }}
|
||||
{% endfor %}
|
||||
{{ content }}{% endautoescape %}
|
||||
|
|
|
@ -30,7 +30,7 @@ class TestModelRead(TestModelsTestCase):
|
|||
mixin = ReadModelMixin()
|
||||
mixin.resource = GroupResource
|
||||
|
||||
response = mixin.get(request, group.id)
|
||||
response = mixin.get(request, id=group.id)
|
||||
self.assertEquals(group.name, response.name)
|
||||
|
||||
def test_read_404(self):
|
||||
|
@ -41,7 +41,7 @@ class TestModelRead(TestModelsTestCase):
|
|||
mixin = ReadModelMixin()
|
||||
mixin.resource = GroupResource
|
||||
|
||||
self.assertRaises(ErrorResponse, mixin.get, request, 12345)
|
||||
self.assertRaises(ErrorResponse, mixin.get, request, id=12345)
|
||||
|
||||
|
||||
class TestModelCreation(TestModelsTestCase):
|
||||
|
@ -280,3 +280,12 @@ class TestPagination(TestCase):
|
|||
self.assertTrue('foo=bar' in content['next'])
|
||||
self.assertTrue('another=something' in content['next'])
|
||||
self.assertTrue('page=2' in content['next'])
|
||||
|
||||
def test_duplicate_parameters_are_not_created(self):
|
||||
""" Regression: ensure duplicate "page" parameters are not added to
|
||||
paginated URLs. So page 1 should contain ?page=2, not ?page=1&page=2 """
|
||||
request = self.req.get('/paginator/?page=1')
|
||||
response = MockPaginatorView.as_view()(request)
|
||||
content = json.loads(response.content)
|
||||
self.assertTrue('page=2' in content['next'])
|
||||
self.assertFalse('page=1' in content['next'])
|
||||
|
|
|
@ -36,6 +36,7 @@ def _remove_trailing_string(content, trailing):
|
|||
return content[:-len(trailing)]
|
||||
return content
|
||||
|
||||
|
||||
def _remove_leading_indent(content):
|
||||
"""
|
||||
Remove leading indent from a block of text.
|
||||
|
@ -50,6 +51,7 @@ def _remove_leading_indent(content):
|
|||
return re.sub(re.compile(whitespace_pattern, re.MULTILINE), '', content)
|
||||
return content
|
||||
|
||||
|
||||
def _camelcase_to_spaces(content):
|
||||
"""
|
||||
Translate 'CamelCaseNames' to 'Camel Case Names'.
|
||||
|
@ -161,9 +163,10 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView):
|
|||
|
||||
def markup_description(self, description):
|
||||
if apply_markdown:
|
||||
return apply_markdown(description)
|
||||
description = apply_markdown(description)
|
||||
else:
|
||||
return mark_safe(escape(description).replace('\n', '<br />'))
|
||||
description = escape(description).replace('\n', '<br />')
|
||||
return mark_safe(description)
|
||||
|
||||
def http_method_not_allowed(self, request, *args, **kwargs):
|
||||
"""
|
||||
|
|
|
@ -105,6 +105,8 @@ The following example exposes your `MyModel` model through an api. It will provi
|
|||
|
||||
contents
|
||||
|
||||
.. include:: ../CHANGELOG.rst
|
||||
|
||||
Indices and tables
|
||||
------------------
|
||||
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
Pygments==1.4
|
||||
Markdown==2.0.3
|
||||
djangorestframework
|
||||
git+git://github.com/tomchristie/django-rest-framework.git
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# Settings for djangorestframework examples project
|
||||
import django
|
||||
import os
|
||||
|
||||
DEBUG = True
|
||||
|
@ -53,16 +54,10 @@ MEDIA_ROOT = os.path.join(os.getenv('EPIO_DATA_DIRECTORY', '.'), 'media')
|
|||
# trailing slash if there is a path component (optional in other cases).
|
||||
# Examples: "http://media.lawrence.com", "http://example.com/media/"
|
||||
# NOTE: None of the djangorestframework examples serve media content via MEDIA_URL.
|
||||
MEDIA_URL = ''
|
||||
MEDIA_URL = '/uploads/'
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
|
||||
# trailing slash.
|
||||
# Examples: "http://foo.com/media/", "/media/".
|
||||
# NOTE: djangorestframework does not require the admin app to be installed,
|
||||
# but it does require the admin media be served. Django's test server will do
|
||||
# this for you automatically, but in production you'll want to make sure you
|
||||
# serve the admin media from somewhere.
|
||||
ADMIN_MEDIA_PREFIX = '/static/admin'
|
||||
|
||||
# Make this unique, and don't share it with anybody.
|
||||
SECRET_KEY = 't&9mru2_k$t8e2-9uq-wu2a1)9v*us&j3i#lsqkt(lbx*vh1cu'
|
||||
|
@ -90,18 +85,17 @@ TEMPLATE_DIRS = (
|
|||
# Don't forget to use absolute paths, not relative paths.
|
||||
)
|
||||
|
||||
# for loading initial data
|
||||
##SERIALIZATION_MODULES = {
|
||||
# 'yml': "django.core.serializers.pyyaml"
|
||||
|
||||
#}
|
||||
|
||||
if django.VERSION < (1, 3):
|
||||
staticfiles = 'staticfiles'
|
||||
else:
|
||||
staticfiles = 'django.contrib.staticfiles'
|
||||
|
||||
INSTALLED_APPS = (
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.sites',
|
||||
staticfiles,
|
||||
'django.contrib.messages',
|
||||
|
||||
'djangorestframework',
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
from django.conf.urls.defaults import patterns, include, url
|
||||
from django.conf import settings
|
||||
from django.conf.urls.defaults import patterns, include
|
||||
from sandbox.views import Sandbox
|
||||
try:
|
||||
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
|
||||
except ImportError: # Django <= 1.2
|
||||
from staticfiles.urls import staticfiles_urlpatterns
|
||||
|
||||
|
||||
urlpatterns = patterns('',
|
||||
(r'^$', Sandbox.as_view()),
|
||||
|
@ -15,3 +19,4 @@ urlpatterns = patterns('',
|
|||
(r'^', include('djangorestframework.urls')),
|
||||
)
|
||||
|
||||
urlpatterns += staticfiles_urlpatterns()
|
||||
|
|
81
setup.py
Normal file → Executable file
81
setup.py
Normal file → Executable file
|
@ -1,33 +1,70 @@
|
|||
#!/usr/bin/env/python
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from setuptools import setup
|
||||
import re
|
||||
import os
|
||||
import sys
|
||||
|
||||
import os, re
|
||||
|
||||
path = os.path.join(os.path.dirname(__file__), 'djangorestframework', '__init__.py')
|
||||
init_py = open(path).read()
|
||||
VERSION = re.match("__version__ = '([^']+)'", init_py).group(1)
|
||||
def get_version(package):
|
||||
"""
|
||||
Return package version as listed in `__version__` in `init.py`.
|
||||
"""
|
||||
init_py = open(os.path.join(package, '__init__.py')).read()
|
||||
return re.match("__version__ = ['\"]([^'\"]+)['\"]", init_py).group(1)
|
||||
|
||||
|
||||
def get_packages(package):
|
||||
"""
|
||||
Return root package and all sub-packages.
|
||||
"""
|
||||
return [dirpath
|
||||
for dirpath, dirnames, filenames in os.walk(package)
|
||||
if os.path.exists(os.path.join(dirpath, '__init__.py'))]
|
||||
|
||||
|
||||
def get_package_data(package):
|
||||
"""
|
||||
Return all files under the root package, that are not in a
|
||||
package themselves.
|
||||
"""
|
||||
walk = [(dirpath.replace(package + os.sep, '', 1), filenames)
|
||||
for dirpath, dirnames, filenames in os.walk(package)
|
||||
if not os.path.exists(os.path.join(dirpath, '__init__.py'))]
|
||||
|
||||
filepaths = []
|
||||
for base, filenames in walk:
|
||||
filepaths.extend([os.path.join(base, filename)
|
||||
for filename in filenames])
|
||||
return {package: filepaths}
|
||||
|
||||
|
||||
version = get_version('djangorestframework')
|
||||
|
||||
|
||||
if sys.argv[-1] == 'publish':
|
||||
os.system("python setup.py sdist upload")
|
||||
print "You probably want to also tag the version now:"
|
||||
print " git tag -a %s -m 'version %s'" % (version, version)
|
||||
print " git push --tags"
|
||||
sys.exit()
|
||||
|
||||
|
||||
setup(
|
||||
name = 'djangorestframework',
|
||||
version = VERSION,
|
||||
url = 'http://django-rest-framework.org',
|
||||
download_url = 'http://pypi.python.org/pypi/djangorestframework/',
|
||||
license = 'BSD',
|
||||
description = 'A lightweight REST framework for Django.',
|
||||
author = 'Tom Christie',
|
||||
author_email = 'tom@tomchristie.com',
|
||||
packages = ['djangorestframework',
|
||||
'djangorestframework.templatetags',
|
||||
'djangorestframework.tests',
|
||||
'djangorestframework.runtests',
|
||||
'djangorestframework.utils'],
|
||||
package_dir={'djangorestframework': 'djangorestframework'},
|
||||
package_data = {'djangorestframework': ['templates/*', 'static/*']},
|
||||
test_suite = 'djangorestframework.runtests.runcoverage.main',
|
||||
name='djangorestframework',
|
||||
version=version,
|
||||
url='http://django-rest-framework.org',
|
||||
download_url='http://pypi.python.org/pypi/djangorestframework/',
|
||||
license='BSD',
|
||||
description='A lightweight REST framework for Django.',
|
||||
author='Tom Christie',
|
||||
author_email='tom@tomchristie.com',
|
||||
packages=get_packages('djangorestframework'),
|
||||
package_data=get_package_data('djangorestframework'),
|
||||
test_suite='djangorestframework.runtests.runcoverage.main',
|
||||
install_requires=['URLObject>=0.6.0'],
|
||||
classifiers = [
|
||||
classifiers=[
|
||||
'Development Status :: 4 - Beta',
|
||||
'Environment :: Web Environment',
|
||||
'Framework :: Django',
|
||||
|
|
6
tox.ini
6
tox.ini
|
@ -32,6 +32,7 @@ commands=
|
|||
basepython=python2.5
|
||||
deps=
|
||||
django==1.2.4
|
||||
django-staticfiles>=1.1.2
|
||||
coverage==3.4
|
||||
URLObject>=0.6.0
|
||||
unittest-xml-reporting==1.2
|
||||
|
@ -43,6 +44,7 @@ deps=
|
|||
basepython=python2.6
|
||||
deps=
|
||||
django==1.2.4
|
||||
django-staticfiles>=1.1.2
|
||||
coverage==3.4
|
||||
URLObject>=0.6.0
|
||||
unittest-xml-reporting==1.2
|
||||
|
@ -54,6 +56,7 @@ deps=
|
|||
basepython=python2.7
|
||||
deps=
|
||||
django==1.2.4
|
||||
django-staticfiles>=1.1.2
|
||||
coverage==3.4
|
||||
URLObject>=0.6.0
|
||||
unittest-xml-reporting==1.2
|
||||
|
@ -135,6 +138,7 @@ commands=
|
|||
python examples/runtests.py
|
||||
deps=
|
||||
django==1.2.4
|
||||
django-staticfiles>=1.1.2
|
||||
coverage==3.4
|
||||
URLObject>=0.6.0
|
||||
wsgiref==0.1.2
|
||||
|
@ -150,6 +154,7 @@ commands=
|
|||
python examples/runtests.py
|
||||
deps=
|
||||
django==1.2.4
|
||||
django-staticfiles>=1.1.2
|
||||
coverage==3.4
|
||||
URLObject>=0.6.0
|
||||
wsgiref==0.1.2
|
||||
|
@ -165,6 +170,7 @@ commands=
|
|||
python examples/runtests.py
|
||||
deps=
|
||||
django==1.2.4
|
||||
django-staticfiles>=1.1.2
|
||||
coverage==3.4
|
||||
URLObject>=0.6.0
|
||||
wsgiref==0.1.2
|
||||
|
|
Loading…
Reference in New Issue
Block a user