Skip to content

Allow use of native migrations in 1.7 #1653

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 71 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
3fcc012
Remove deprecated code
tomchristie Jun 27, 2013
379ad8a
pending deprecations -> deprecated
tomchristie Jun 27, 2013
9e4e2c6
Merge branch 'master' into 2.4.0
tomchristie Jul 4, 2013
d72603b
Add support for collection routes to SimpleRouter
aburgel Jun 5, 2013
5b11e23
Add docs for collection routes
aburgel Jun 5, 2013
57cf8b5
Rework extra routes doc for better readability
aburgel Jun 6, 2013
8d521c0
Revert route name change and add key to Route object to identify diff…
aburgel Jun 16, 2013
f022743
Rename router collection test case
aburgel Jun 16, 2013
e14cbaf
Changed collection_* decorators to list_*
aburgel Jul 13, 2013
ca7ba07
Introduce DynamicDetailRoute and DynamicListRoute to distinguish betw…
aburgel Jul 13, 2013
eaae8fb
Combined link_* and action_* decorators into detail_route and list_ro…
aburgel Jul 15, 2013
c607414
Merge
tomchristie Aug 19, 2013
4292cc1
Docs tweaking
tomchristie Aug 19, 2013
28e44ef
Merge branch 'master' into 2.4.0
tomchristie Aug 19, 2013
8acee2e
Commenting link/action decorators as pending deprecation
tomchristie Aug 19, 2013
db25aaf
Merge branch 'static-routes' into 0.4.0
tomchristie Aug 21, 2013
815ef50
If page size query param <= 0, just use default page size.
tomchristie Aug 21, 2013
44ceef8
Updating 2.4.0 release notes
tomchristie Aug 21, 2013
16ffded
Merge master
tomchristie Aug 21, 2013
f631f55
Tweak comment
tomchristie Aug 21, 2013
bf07b8e
Better docs for customizing dynamic routes. Refs #908
tomchristie Aug 29, 2013
9a5b2ee
Merge master
tomchristie Aug 30, 2013
21cd638
Merge master
tomchristie Sep 25, 2013
e441f85
Drop 1.3 support
tomchristie Sep 25, 2013
1bd8fe4
Whitespace fix
tomchristie Sep 25, 2013
ab4be47
Fixed code example.
thedrow Oct 3, 2013
3604616
Merge pull request #1148 from thedrow/patch-1
tomchristie Oct 3, 2013
9ab0759
Add tests to pass for get_ident method in BaseThrottle class.
Dec 6, 2013
89f26c5
Add get_ident method to pass new tests.
Dec 6, 2013
100a933
Add documentation to explain what effect these changes have.
Dec 6, 2013
196c595
Fix typo
Dec 6, 2013
887da7f
Add missing tick marks
Dec 6, 2013
23db6c9
PEP8 Compliance
Dec 6, 2013
d6d4621
Merge pull request #1273 from kahnjw/add_get_ident_method_to_base_thr…
tomchristie Dec 12, 2013
83da494
Allow NUM_PROXIES=0 and include more docs
tomchristie Dec 13, 2013
ed931b9
Further docs tweaks
tomchristie Dec 13, 2013
9c41c00
Merge branch 'master' into 2.4.0
tomchristie Dec 13, 2013
83b31e7
Merge branch 'patch-1' of git://github.com/bennbollay/django-rest-fra…
tomchristie Dec 23, 2013
5268642
Merge branch 'bennbollay-patch-1' into 2.4.0
tomchristie Dec 23, 2013
a1d7aa8
Allow viewset to specify lookup value regex for routing
Jan 2, 2014
3cd15fb
Router: Do not automatically adjust lookup_regex when trailing_slash …
Jan 4, 2014
8993815
Fix a typo
Jan 4, 2014
46f5c62
Regression test for #1330 (Coerce None to '')
yprez Jan 5, 2014
e88e3c6
Possible fix for #1330
yprez Jan 5, 2014
6e622d6
CharField - add allow_null argument
yprez Jan 5, 2014
e1bbe9d
Set `allow_none = True` for CharFields with null=True
yprez Jan 6, 2014
0fd0454
Test for setting allow_none=True for nullable CharFields
yprez Jan 6, 2014
cd9a419
Check the modelfield's class instead
yprez Jan 12, 2014
07cff7b
Merge pull request #1348 from yprez/none-to-empty-string_2.4
tomchristie Jan 12, 2014
a90796c
Track changes that need noting in 2.4 announcement
tomchristie Jan 13, 2014
4ab9784
Merge pull request #1333 from bodylabs/2.4.0+lookup_regex
tomchristie Jan 13, 2014
2911cd6
Minor tweaks to 'lookup_value_regex' work
tomchristie Jan 13, 2014
971578c
Support for running the test suite with py.test
pelme Mar 2, 2014
d08536a
Merge remote-tracking branch 'origin/master' into 2.4.0
xordoquy Apr 12, 2014
1797a74
Merge remote-tracking branch 'pelme/pytest' into feature/pytest
xordoquy Apr 17, 2014
f22ed49
Upgraded to pytest-django 2.6.1
xordoquy Apr 17, 2014
c5f68fb
Fixed the issue with django-filters / django 1.7 / pytest
xordoquy Apr 17, 2014
56b4390
Merge remote-tracking branch 'origin/master' into 2.4.0
xordoquy Apr 30, 2014
2aca69a
Merge remote-tracking branch 'reference/master' into feature/pytest
xordoquy Apr 30, 2014
cd93cd1
Use url functions from Django itself.
xordoquy Apr 30, 2014
7475fce
Added missing field for the tests.
xordoquy Apr 30, 2014
38362bb
Fixed new default for many
xordoquy Apr 30, 2014
c9e6f31
Fixed new default for many
xordoquy Apr 30, 2014
7b4463f
Merge remote-tracking branch 'reference/2.4.0' into feature/pytest
xordoquy May 1, 2014
eb89ed0
Added missing staticfiles app
xordoquy May 1, 2014
e5441d8
Use urls functions from django instead of compat.
xordoquy May 1, 2014
15c2c58
Updated the release-notes.
xordoquy May 1, 2014
2489e38
Merge remote-tracking branch 'origin/master' into 2.4.0
xordoquy Jun 23, 2014
f34011f
Allow use of native migrations in 1.7
Jun 23, 2014
3f727ce
Added (first pass) notes to docs & release notes. Backed out `SOUTH_M…
Jun 24, 2014
d98245a
Merge branch '2.4.0' of github.com:tomchristie/django-rest-framework …
Jun 24, 2014
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 2 additions & 8 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ env:
- DJANGO="django==1.6.5"
- DJANGO="django==1.5.8"
- DJANGO="django==1.4.13"
- DJANGO="django==1.3.7"

install:
- pip install $DJANGO
- pip install defusedxml==0.3 Pillow==2.3.0
- pip install pytest-django==2.6.1
- "if [[ ${TRAVIS_PYTHON_VERSION::1} != '3' ]]; then pip install oauth2==1.5.211; fi"
- "if [[ ${TRAVIS_PYTHON_VERSION::1} != '3' ]]; then pip install django-oauth-plus==2.2.4; fi"
- "if [[ ${TRAVIS_PYTHON_VERSION::1} != '3' ]]; then pip install django-oauth2-provider==0.2.4; fi"
Expand All @@ -28,21 +28,15 @@ install:
- export PYTHONPATH=.

script:
- python rest_framework/runtests/runtests.py
- py.test

matrix:
exclude:
- python: "2.6"
env: DJANGO="https://www.djangoproject.com/download/1.7.b4/tarball/"
- python: "3.2"
env: DJANGO="django==1.4.13"
- python: "3.2"
env: DJANGO="django==1.3.7"
- python: "3.3"
env: DJANGO="django==1.4.13"
- python: "3.3"
env: DJANGO="django==1.3.7"
- python: "3.4"
env: DJANGO="django==1.4.13"
- python: "3.4"
env: DJANGO="django==1.3.7"
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ To run the tests, clone the repository, and then:
pip install -r optionals.txt

# Run the tests
rest_framework/runtests/runtests.py
py.test

You can also use the excellent [`tox`][tox] testing tool to run the tests against all supported versions of Python and Django. Install `tox` globally, and then simply run:

Expand Down
88 changes: 88 additions & 0 deletions conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
def pytest_configure():
from django.conf import settings

settings.configure(
DEBUG_PROPAGATE_EXCEPTIONS=True,
DATABASES={'default': {'ENGINE': 'django.db.backends.sqlite3',
'NAME': ':memory:'}},
SECRET_KEY='not very secret in tests',
USE_I18N=True,
USE_L10N=True,
STATIC_URL='/static/',
ROOT_URLCONF='tests.urls',
TEMPLATE_LOADERS=(
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
),
MIDDLEWARE_CLASSES=(
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
),
INSTALLED_APPS=(
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',

'rest_framework',
'rest_framework.authtoken',
'tests',
'tests.accounts',
'tests.records',
'tests.users',
),
PASSWORD_HASHERS=(
'django.contrib.auth.hashers.SHA1PasswordHasher',
'django.contrib.auth.hashers.PBKDF2PasswordHasher',
'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
'django.contrib.auth.hashers.BCryptPasswordHasher',
'django.contrib.auth.hashers.MD5PasswordHasher',
'django.contrib.auth.hashers.CryptPasswordHasher',
),
)

try:
import oauth_provider
import oauth2
except ImportError:
pass
else:
settings.INSTALLED_APPS += (
'oauth_provider',
)

try:
import provider
except ImportError:
pass
else:
settings.INSTALLED_APPS += (
'provider',
'provider.oauth2',
)

# guardian is optional
try:
import guardian
except ImportError:
pass
else:
settings.ANONYMOUS_USER_ID = -1
settings.AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend', # default
'guardian.backends.ObjectPermissionBackend',
)
settings.INSTALLED_APPS += (
'guardian',
)

try:
import django
django.setup()
except AttributeError:
pass
24 changes: 22 additions & 2 deletions docs/api-guide/authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,13 @@ To use the `TokenAuthentication` scheme you'll need to [configure the authentica
'rest_framework.authtoken'
)

Make sure to run `manage.py syncdb` after changing your settings. The `authtoken` database tables are managed by south (see [Schema migrations](#schema-migrations) below).

---

**Note:** Make sure to run `manage.py syncdb` after changing your settings. Both Django native (from v1.7) and South migrations for the `authtoken` database tables are provided. See [Schema migrations](#schema-migrations) below.

---


You'll also need to create tokens for your users.

Expand Down Expand Up @@ -198,7 +204,21 @@ Note that the default `obtain_auth_token` view explicitly uses JSON requests and

#### Schema migrations

The `rest_framework.authtoken` app includes a south migration that will create the authtoken table.
The `rest_framework.authtoken` app includes both a Django native migration (for Django versions >1.7) and a south migration that will create the authtoken table.

----

**Note** By default both Django (>1.7) and South will look for a module named `migrations`. To avoid a collision here, in order to use South you **must** provide the `SOUTH_MIGRATION_MODULES` option in your `settings.py`:


SOUTH_MIGRATION_MODULES = {
'authtoken': 'rest_framework.authtoken.south_migrations',
}

This tells South to look in the `south_migrations` module for the `authtoken` app.

----


If you're using a [custom user model][custom-user-model] you'll need to make sure that any initial migration that creates the user table runs before the authtoken table is created.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without thinking about it, I'm not sure what needs to be said in this section.

Topics are:

  1. Migration dependencies. (Not sure, yet, how Django handles that)
  2. post_save creation of tokens — I'd guess this remains unchanged but need to think it through.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Grumble, grumble... :) Django uses depenencies rather than needed_by but looks okay other than that.

https://docs.djangoproject.com/en/1.7/topics/migrations/#migration-files

I'll edit later on

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this will change anything for those two points. We are just using an alternative location for south's modules.
However I don't know the minimum south version that will support that configuration option.


Expand Down
3 changes: 2 additions & 1 deletion docs/api-guide/fields.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,11 +164,12 @@ Corresponds to `django.db.models.fields.BooleanField`.
## CharField

A text representation, optionally validates the text to be shorter than `max_length` and longer than `min_length`.
If `allow_none` is `False` (default), `None` values will be converted to an empty string.

Corresponds to `django.db.models.fields.CharField`
or `django.db.models.fields.TextField`.

**Signature:** `CharField(max_length=None, min_length=None)`
**Signature:** `CharField(max_length=None, min_length=None, allow_none=False)`

## URLField

Expand Down
115 changes: 93 additions & 22 deletions docs/api-guide/routers.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,36 +51,41 @@ This means you'll need to explicitly set the `base_name` argument when registeri

### Extra link and actions

Any methods on the viewset decorated with `@link` or `@action` will also be routed.
Any methods on the viewset decorated with `@detail_route` or `@list_route` will also be routed.
For example, given a method like this on the `UserViewSet` class:

from myapp.permissions import IsAdminOrIsSelf
from rest_framework.decorators import action

@action(permission_classes=[IsAdminOrIsSelf])
def set_password(self, request, pk=None):
from myapp.permissions import IsAdminOrIsSelf
from rest_framework.decorators import detail_route

class UserViewSet(ModelViewSet):
...

@detail_route(methods=['post'], permission_classes=[IsAdminOrIsSelf])
def set_password(self, request, pk=None):
...

The following URL pattern would additionally be generated:

* URL pattern: `^users/{pk}/set_password/$` Name: `'user-set-password'`

For more information see the viewset documentation on [marking extra actions for routing][route-decorators].

# API Guide

## SimpleRouter

This router includes routes for the standard set of `list`, `create`, `retrieve`, `update`, `partial_update` and `destroy` actions. The viewset can also mark additional methods to be routed, using the `@link` or `@action` decorators.
This router includes routes for the standard set of `list`, `create`, `retrieve`, `update`, `partial_update` and `destroy` actions. The viewset can also mark additional methods to be routed, using the `@detail_route` or `@list_route` decorators.

<table border=1>
<tr><th>URL Style</th><th>HTTP Method</th><th>Action</th><th>URL Name</th></tr>
<tr><td rowspan=2>{prefix}/</td><td>GET</td><td>list</td><td rowspan=2>{basename}-list</td></tr></tr>
<tr><td>POST</td><td>create</td></tr>
<tr><td>{prefix}/{methodname}/</td><td>GET, or as specified by `methods` argument</td><td>`@list_route` decorated method</td><td>{basename}-{methodname}</td></tr>
<tr><td rowspan=4>{prefix}/{lookup}/</td><td>GET</td><td>retrieve</td><td rowspan=4>{basename}-detail</td></tr></tr>
<tr><td>PUT</td><td>update</td></tr>
<tr><td>PATCH</td><td>partial_update</td></tr>
<tr><td>DELETE</td><td>destroy</td></tr>
<tr><td rowspan=2>{prefix}/{lookup}/{methodname}/</td><td>GET</td><td>@link decorated method</td><td rowspan=2>{basename}-{methodname}</td></tr>
<tr><td>POST</td><td>@action decorated method</td></tr>
<tr><td>{prefix}/{lookup}/{methodname}/</td><td>GET, or as specified by `methods` argument</td><td>`@detail_route` decorated method</td><td>{basename}-{methodname}</td></tr>
</table>

By default the URLs created by `SimpleRouter` are appended with a trailing slash.
Expand All @@ -90,6 +95,12 @@ This behavior can be modified by setting the `trailing_slash` argument to `False

Trailing slashes are conventional in Django, but are not used by default in some other frameworks such as Rails. Which style you choose to use is largely a matter of preference, although some javascript frameworks may expect a particular routing style.

The router will match lookup values containing any characters except slashes and period characters. For a more restrictive (or lenient) lookup pattern, set the `lookup_value_regex` attribute on the viewset. For example, you can limit the lookup to valid UUIDs:

class MyModelViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
lookup_field = 'my_model_id'
lookup_value_regex = '[0-9a-f]{32}'

## DefaultRouter

This router is similar to `SimpleRouter` as above, but additionally includes a default API root view, that returns a response containing hyperlinks to all the list views. It also generates routes for optional `.json` style format suffixes.
Expand All @@ -99,12 +110,12 @@ This router is similar to `SimpleRouter` as above, but additionally includes a d
<tr><td>[.format]</td><td>GET</td><td>automatically generated root view</td><td>api-root</td></tr></tr>
<tr><td rowspan=2>{prefix}/[.format]</td><td>GET</td><td>list</td><td rowspan=2>{basename}-list</td></tr></tr>
<tr><td>POST</td><td>create</td></tr>
<tr><td>{prefix}/{methodname}/[.format]</td><td>GET, or as specified by `methods` argument</td><td>`@list_route` decorated method</td><td>{basename}-{methodname}</td></tr>
<tr><td rowspan=4>{prefix}/{lookup}/[.format]</td><td>GET</td><td>retrieve</td><td rowspan=4>{basename}-detail</td></tr></tr>
<tr><td>PUT</td><td>update</td></tr>
<tr><td>PATCH</td><td>partial_update</td></tr>
<tr><td>DELETE</td><td>destroy</td></tr>
<tr><td rowspan=2>{prefix}/{lookup}/{methodname}/[.format]</td><td>GET</td><td>@link decorated method</td><td rowspan=2>{basename}-{methodname}</td></tr>
<tr><td>POST</td><td>@action decorated method</td></tr>
<tr><td>{prefix}/{lookup}/{methodname}/[.format]</td><td>GET, or as specified by `methods` argument</td><td>`@detail_route` decorated method</td><td>{basename}-{methodname}</td></tr>
</table>

As with `SimpleRouter` the trailing slashes on the URL routes can be removed by setting the `trailing_slash` argument to `False` when instantiating the router.
Expand Down Expand Up @@ -133,28 +144,87 @@ The arguments to the `Route` named tuple are:

**initkwargs**: A dictionary of any additional arguments that should be passed when instantiating the view. Note that the `suffix` argument is reserved for identifying the viewset type, used when generating the view name and breadcrumb links.

## Customizing dynamic routes

You can also customize how the `@list_route` and `@detail_route` decorators are routed.
To route either or both of these decorators, include a `DynamicListRoute` and/or `DynamicDetailRoute` named tuple in the `.routes` list.

The arguments to `DynamicListRoute` and `DynamicDetailRoute` are:

**url**: A string representing the URL to be routed. May include the same format strings as `Route`, and additionally accepts the `{methodname}` and `{methodnamehyphen}` format strings.

**name**: The name of the URL as used in `reverse` calls. May include the following format strings: `{basename}`, `{methodname}` and `{methodnamehyphen}`.

**initkwargs**: A dictionary of any additional arguments that should be passed when instantiating the view.

## Example

The following example will only route to the `list` and `retrieve` actions, and does not use the trailing slash convention.

from rest_framework.routers import Route, SimpleRouter
from rest_framework.routers import Route, DynamicDetailRoute, SimpleRouter

class ReadOnlyRouter(SimpleRouter):
class CustomReadOnlyRouter(SimpleRouter):
"""
A router for read-only APIs, which doesn't use trailing slashes.
"""
routes = [
Route(url=r'^{prefix}$',
mapping={'get': 'list'},
name='{basename}-list',
initkwargs={'suffix': 'List'}),
Route(url=r'^{prefix}/{lookup}$',
mapping={'get': 'retrieve'},
name='{basename}-detail',
initkwargs={'suffix': 'Detail'})
Route(
url=r'^{prefix}$',
mapping={'get': 'list'},
name='{basename}-list',
initkwargs={'suffix': 'List'}
),
Route(
url=r'^{prefix}/{lookup}$',
mapping={'get': 'retrieve'},
name='{basename}-detail',
initkwargs={'suffix': 'Detail'}
),
DynamicDetailRoute(
url=r'^{prefix}/{lookup}/{methodnamehyphen}$',
name='{basename}-{methodnamehyphen}',
initkwargs={}
)
]

The `SimpleRouter` class provides another example of setting the `.routes` attribute.
Let's take a look at the routes our `CustomReadOnlyRouter` would generate for a simple viewset.

`views.py`:

class UserViewSet(viewsets.ReadOnlyModelViewSet):
"""
A viewset that provides the standard actions
"""
queryset = User.objects.all()
serializer_class = UserSerializer
lookup_field = 'username'

@detail_route()
def group_names(self, request):
"""
Returns a list of all the group names that the given
user belongs to.
"""
user = self.get_object()
groups = user.groups.all()
return Response([group.name for group in groups])

`urls.py`:

router = CustomReadOnlyRouter()
router.register('users', UserViewSet)
urlpatterns = router.urls

The following mappings would be generated...

<table border=1>
<tr><th>URL</th><th>HTTP Method</th><th>Action</th><th>URL Name</th></tr>
<tr><td>/users</td><td>GET</td><td>list</td><td>user-list</td></tr>
<tr><td>/users/{username}</td><td>GET</td><td>retrieve</td><td>user-detail</td></tr>
<tr><td>/users/{username}/group-names</td><td>GET</td><td>group_names</td><td>user-group-names</td></tr>
</table>

For another example of setting the `.routes` attribute, see the source code for the `SimpleRouter` class.

## Advanced custom routers

Expand All @@ -180,6 +250,7 @@ The [wq.db package][wq.db] provides an advanced [Router][wq.db-router] class (an
app.router.register_model(MyModel)

[cite]: http://guides.rubyonrails.org/routing.html
[route-decorators]: viewsets.html#marking-extra-actions-for-routing
[drf-nested-routers]: https://github.com/alanjds/drf-nested-routers
[wq.db]: http://wq.io/wq.db
[wq.db-router]: http://wq.io/docs/app.py
6 changes: 6 additions & 0 deletions docs/api-guide/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -377,5 +377,11 @@ The name of a parameter in the URL conf that may be used to provide a format suf

Default: `'format'`

#### NUM_PROXIES

An integer of 0 or more, that may be used to specify the number of application proxies that the API runs behind. This allows throttling to more accurately identify client IP addresses. If set to `None` then less strict IP matching will be used by the throttle classes.

Default: `None`

[cite]: http://www.python.org/dev/peps/pep-0020/
[strftime]: http://docs.python.org/2/library/time.html#time.strftime
Loading
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy