Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
D
django-rest-framework
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
django-rest-framework
Commits
f6c19e5e
Commit
f6c19e5e
authored
Jul 14, 2017
by
Ryan P Kilby
Committed by
Carlton Gibson
Sep 20, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Remove DjangoFilterBackend and associated tests
parent
cb6e7e0f
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
2 additions
and
479 deletions
+2
-479
rest_framework/compat.py
+0
-7
rest_framework/filters.py
+1
-40
tests/models.py
+0
-9
tests/test_filters.py
+1
-423
No files found.
rest_framework/compat.py
View file @
f6c19e5e
...
...
@@ -182,13 +182,6 @@ except ImportError:
coreschema
=
None
# django-filter is optional
try
:
import
django_filters
except
ImportError
:
django_filters
=
None
# django-crispy-forms is optional
try
:
import
crispy_forms
...
...
rest_framework/filters.py
View file @
f6c19e5e
...
...
@@ -5,7 +5,6 @@ returned by list views.
from
__future__
import
unicode_literals
import
operator
import
warnings
from
functools
import
reduce
from
django.core.exceptions
import
ImproperlyConfigured
...
...
@@ -18,7 +17,7 @@ from django.utils.encoding import force_text
from
django.utils.translation
import
ugettext_lazy
as
_
from
rest_framework.compat
import
(
coreapi
,
coreschema
,
distinct
,
django_filters
,
guardian
,
template_render
coreapi
,
coreschema
,
distinct
,
guardian
,
template_render
)
from
rest_framework.settings
import
api_settings
...
...
@@ -40,44 +39,6 @@ class BaseFilterBackend(object):
return
[]
if
django_filters
:
from
django_filters.rest_framework.filterset
import
FilterSet
as
DFFilterSet
class
FilterSet
(
DFFilterSet
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
warnings
.
warn
(
"The built in 'rest_framework.filters.FilterSet' is deprecated. "
"You should use 'django_filters.rest_framework.FilterSet' instead."
,
DeprecationWarning
,
stacklevel
=
2
)
return
super
(
FilterSet
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
DFBase
=
django_filters
.
rest_framework
.
DjangoFilterBackend
else
:
def
FilterSet
():
assert
False
,
'django-filter must be installed to use the `FilterSet` class'
DFBase
=
BaseFilterBackend
class
DjangoFilterBackend
(
DFBase
):
"""
A filter backend that uses django-filter.
"""
def
__new__
(
cls
,
*
args
,
**
kwargs
):
assert
django_filters
,
'Using DjangoFilterBackend, but django-filter is not installed'
assert
django_filters
.
VERSION
>=
(
0
,
15
,
3
),
'django-filter 0.15.3 and above is required'
warnings
.
warn
(
"The built in 'rest_framework.filters.DjangoFilterBackend' is deprecated. "
"You should use 'django_filters.rest_framework.DjangoFilterBackend' instead."
,
DeprecationWarning
,
stacklevel
=
2
)
return
super
(
DjangoFilterBackend
,
cls
)
.
__new__
(
cls
,
*
args
,
**
kwargs
)
class
SearchFilter
(
BaseFilterBackend
):
# The URL query parameter used for the search.
search_param
=
api_settings
.
SEARCH_PARAM
...
...
tests/models.py
View file @
f6c19e5e
...
...
@@ -24,15 +24,6 @@ class BasicModel(RESTFrameworkModel):
)
class
BaseFilterableItem
(
RESTFrameworkModel
):
text
=
models
.
CharField
(
max_length
=
100
)
class
FilterableItem
(
BaseFilterableItem
):
decimal
=
models
.
DecimalField
(
max_digits
=
4
,
decimal_places
=
2
)
date
=
models
.
DateField
()
# Models for relations tests
# ManyToMany
class
ManyToManyTarget
(
RESTFrameworkModel
):
...
...
tests/test_filters.py
View file @
f6c19e5e
...
...
@@ -2,125 +2,21 @@ from __future__ import unicode_literals
import
datetime
import
unittest
import
warnings
from
decimal
import
Decimal
import
django
import
pytest
from
django.conf.urls
import
url
from
django.core.exceptions
import
ImproperlyConfigured
from
django.db
import
models
from
django.test
import
TestCase
from
django.test.utils
import
override_settings
from
django.utils.dateparse
import
parse_date
from
django.utils.six.moves
import
reload_module
from
rest_framework
import
filters
,
generics
,
serializers
,
status
from
rest_framework.compat
import
django_filters
,
reverse
from
rest_framework
import
filters
,
generics
,
serializers
from
rest_framework.test
import
APIRequestFactory
from
.models
import
BaseFilterableItem
,
BasicModel
,
FilterableItem
factory
=
APIRequestFactory
()
if
django_filters
:
class
FilterableItemSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
FilterableItem
fields
=
'__all__'
# Basic filter on a list view.
class
FilterFieldsRootView
(
generics
.
ListCreateAPIView
):
queryset
=
FilterableItem
.
objects
.
all
()
serializer_class
=
FilterableItemSerializer
filter_fields
=
[
'decimal'
,
'date'
]
filter_backends
=
(
filters
.
DjangoFilterBackend
,)
# These class are used to test a filter class.
class
SeveralFieldsFilter
(
django_filters
.
FilterSet
):
text
=
django_filters
.
CharFilter
(
lookup_expr
=
'icontains'
)
decimal
=
django_filters
.
NumberFilter
(
lookup_expr
=
'lt'
)
date
=
django_filters
.
DateFilter
(
lookup_expr
=
'gt'
)
class
Meta
:
model
=
FilterableItem
fields
=
[
'text'
,
'decimal'
,
'date'
]
class
FilterClassRootView
(
generics
.
ListCreateAPIView
):
queryset
=
FilterableItem
.
objects
.
all
()
serializer_class
=
FilterableItemSerializer
filter_class
=
SeveralFieldsFilter
filter_backends
=
(
filters
.
DjangoFilterBackend
,)
# These classes are used to test a misconfigured filter class.
class
MisconfiguredFilter
(
django_filters
.
FilterSet
):
text
=
django_filters
.
CharFilter
(
lookup_expr
=
'icontains'
)
class
Meta
:
model
=
BasicModel
fields
=
[
'text'
]
class
IncorrectlyConfiguredRootView
(
generics
.
ListCreateAPIView
):
queryset
=
FilterableItem
.
objects
.
all
()
serializer_class
=
FilterableItemSerializer
filter_class
=
MisconfiguredFilter
filter_backends
=
(
filters
.
DjangoFilterBackend
,)
class
FilterClassDetailView
(
generics
.
RetrieveAPIView
):
queryset
=
FilterableItem
.
objects
.
all
()
serializer_class
=
FilterableItemSerializer
filter_class
=
SeveralFieldsFilter
filter_backends
=
(
filters
.
DjangoFilterBackend
,)
# These classes are used to test base model filter support
class
BaseFilterableItemFilter
(
django_filters
.
FilterSet
):
text
=
django_filters
.
CharFilter
()
class
Meta
:
model
=
BaseFilterableItem
fields
=
'__all__'
# Test the same filter using the deprecated internal FilterSet class.
class
BaseFilterableItemFilterWithProxy
(
filters
.
FilterSet
):
text
=
django_filters
.
CharFilter
()
class
Meta
:
model
=
BaseFilterableItem
fields
=
'__all__'
class
BaseFilterableItemFilterRootView
(
generics
.
ListCreateAPIView
):
queryset
=
FilterableItem
.
objects
.
all
()
serializer_class
=
FilterableItemSerializer
filter_class
=
BaseFilterableItemFilter
filter_backends
=
(
filters
.
DjangoFilterBackend
,)
class
BaseFilterableItemFilterWithProxyRootView
(
BaseFilterableItemFilterRootView
):
filter_class
=
BaseFilterableItemFilterWithProxy
# Regression test for #814
class
FilterFieldsQuerysetView
(
generics
.
ListCreateAPIView
):
queryset
=
FilterableItem
.
objects
.
all
()
serializer_class
=
FilterableItemSerializer
filter_fields
=
[
'decimal'
,
'date'
]
filter_backends
=
(
filters
.
DjangoFilterBackend
,)
class
GetQuerysetView
(
generics
.
ListCreateAPIView
):
serializer_class
=
FilterableItemSerializer
filter_class
=
SeveralFieldsFilter
filter_backends
=
(
filters
.
DjangoFilterBackend
,)
def
get_queryset
(
self
):
return
FilterableItem
.
objects
.
all
()
urlpatterns
=
[
url
(
r'^(?P<pk>\d+)/$'
,
FilterClassDetailView
.
as_view
(),
name
=
'detail-view'
),
url
(
r'^$'
,
FilterClassRootView
.
as_view
(),
name
=
'root-view'
),
url
(
r'^get-queryset/$'
,
GetQuerysetView
.
as_view
(),
name
=
'get-queryset-view'
),
]
class
BaseFilterTests
(
TestCase
):
def
setUp
(
self
):
self
.
original_coreapi
=
filters
.
coreapi
...
...
@@ -142,288 +38,6 @@ class BaseFilterTests(TestCase):
assert
self
.
filter_backend
.
get_schema_fields
({})
==
[]
class
CommonFilteringTestCase
(
TestCase
):
def
_serialize_object
(
self
,
obj
):
return
{
'id'
:
obj
.
id
,
'text'
:
obj
.
text
,
'decimal'
:
str
(
obj
.
decimal
),
'date'
:
obj
.
date
.
isoformat
()}
def
setUp
(
self
):
"""
Create 10 FilterableItem instances.
"""
base_data
=
(
'a'
,
Decimal
(
'0.25'
),
datetime
.
date
(
2012
,
10
,
8
))
for
i
in
range
(
10
):
text
=
chr
(
i
+
ord
(
base_data
[
0
]))
*
3
# Produces string 'aaa', 'bbb', etc.
decimal
=
base_data
[
1
]
+
i
date
=
base_data
[
2
]
-
datetime
.
timedelta
(
days
=
i
*
2
)
FilterableItem
(
text
=
text
,
decimal
=
decimal
,
date
=
date
)
.
save
()
self
.
objects
=
FilterableItem
.
objects
self
.
data
=
[
self
.
_serialize_object
(
obj
)
for
obj
in
self
.
objects
.
all
()
]
class
IntegrationTestFiltering
(
CommonFilteringTestCase
):
"""
Integration tests for filtered list views.
"""
@unittest.skipUnless
(
django_filters
,
'django-filter not installed'
)
def
test_backend_deprecation
(
self
):
with
warnings
.
catch_warnings
(
record
=
True
)
as
w
:
warnings
.
simplefilter
(
"always"
)
view
=
FilterFieldsRootView
.
as_view
()
request
=
factory
.
get
(
'/'
)
response
=
view
(
request
)
.
render
()
assert
response
.
status_code
==
status
.
HTTP_200_OK
assert
response
.
data
==
self
.
data
self
.
assertTrue
(
issubclass
(
w
[
-
1
]
.
category
,
DeprecationWarning
))
self
.
assertIn
(
"'rest_framework.filters.DjangoFilterBackend' is deprecated."
,
str
(
w
[
-
1
]
.
message
))
@unittest.skipUnless
(
django_filters
,
'django-filter not installed'
)
def
test_no_df_deprecation
(
self
):
with
warnings
.
catch_warnings
(
record
=
True
)
as
w
:
warnings
.
simplefilter
(
"always"
)
import
django_filters.rest_framework
class
DFFilterFieldsRootView
(
FilterFieldsRootView
):
filter_backends
=
(
django_filters
.
rest_framework
.
DjangoFilterBackend
,)
view
=
DFFilterFieldsRootView
.
as_view
()
request
=
factory
.
get
(
'/'
)
response
=
view
(
request
)
.
render
()
assert
response
.
status_code
==
status
.
HTTP_200_OK
assert
response
.
data
==
self
.
data
assert
len
(
w
)
==
0
@unittest.skipUnless
(
django_filters
,
'django-filter not installed'
)
def
test_backend_mro
(
self
):
class
CustomBackend
(
filters
.
DjangoFilterBackend
):
def
filter_queryset
(
self
,
request
,
queryset
,
view
):
assert
False
,
"custom filter_queryset should run"
class
DFFilterFieldsRootView
(
FilterFieldsRootView
):
filter_backends
=
(
CustomBackend
,)
view
=
DFFilterFieldsRootView
.
as_view
()
request
=
factory
.
get
(
'/'
)
with
pytest
.
raises
(
AssertionError
,
message
=
"custom filter_queryset should run"
):
view
(
request
)
.
render
()
@unittest.skipUnless
(
django_filters
,
'django-filter not installed'
)
def
test_get_filtered_fields_root_view
(
self
):
"""
GET requests to paginated ListCreateAPIView should return paginated results.
"""
view
=
FilterFieldsRootView
.
as_view
()
# Basic test with no filter.
request
=
factory
.
get
(
'/'
)
response
=
view
(
request
)
.
render
()
assert
response
.
status_code
==
status
.
HTTP_200_OK
assert
response
.
data
==
self
.
data
# Tests that the decimal filter works.
search_decimal
=
Decimal
(
'2.25'
)
request
=
factory
.
get
(
'/'
,
{
'decimal'
:
'
%
s'
%
search_decimal
})
response
=
view
(
request
)
.
render
()
assert
response
.
status_code
==
status
.
HTTP_200_OK
expected_data
=
[
f
for
f
in
self
.
data
if
Decimal
(
f
[
'decimal'
])
==
search_decimal
]
assert
response
.
data
==
expected_data
# Tests that the date filter works.
search_date
=
datetime
.
date
(
2012
,
9
,
22
)
request
=
factory
.
get
(
'/'
,
{
'date'
:
'
%
s'
%
search_date
})
# search_date str: '2012-09-22'
response
=
view
(
request
)
.
render
()
assert
response
.
status_code
==
status
.
HTTP_200_OK
expected_data
=
[
f
for
f
in
self
.
data
if
parse_date
(
f
[
'date'
])
==
search_date
]
assert
response
.
data
==
expected_data
@unittest.skipUnless
(
django_filters
,
'django-filter not installed'
)
def
test_filter_with_queryset
(
self
):
"""
Regression test for #814.
"""
view
=
FilterFieldsQuerysetView
.
as_view
()
# Tests that the decimal filter works.
search_decimal
=
Decimal
(
'2.25'
)
request
=
factory
.
get
(
'/'
,
{
'decimal'
:
'
%
s'
%
search_decimal
})
response
=
view
(
request
)
.
render
()
assert
response
.
status_code
==
status
.
HTTP_200_OK
expected_data
=
[
f
for
f
in
self
.
data
if
Decimal
(
f
[
'decimal'
])
==
search_decimal
]
assert
response
.
data
==
expected_data
@unittest.skipUnless
(
django_filters
,
'django-filter not installed'
)
def
test_filter_with_get_queryset_only
(
self
):
"""
Regression test for #834.
"""
view
=
GetQuerysetView
.
as_view
()
request
=
factory
.
get
(
'/get-queryset/'
)
view
(
request
)
.
render
()
# Used to raise "issubclass() arg 2 must be a class or tuple of classes"
# here when neither `model' nor `queryset' was specified.
@unittest.skipUnless
(
django_filters
,
'django-filter not installed'
)
def
test_get_filtered_class_root_view
(
self
):
"""
GET requests to filtered ListCreateAPIView that have a filter_class set
should return filtered results.
"""
view
=
FilterClassRootView
.
as_view
()
# Basic test with no filter.
request
=
factory
.
get
(
'/'
)
response
=
view
(
request
)
.
render
()
assert
response
.
status_code
==
status
.
HTTP_200_OK
assert
response
.
data
==
self
.
data
# Tests that the decimal filter set with 'lt' in the filter class works.
search_decimal
=
Decimal
(
'4.25'
)
request
=
factory
.
get
(
'/'
,
{
'decimal'
:
'
%
s'
%
search_decimal
})
response
=
view
(
request
)
.
render
()
assert
response
.
status_code
==
status
.
HTTP_200_OK
expected_data
=
[
f
for
f
in
self
.
data
if
Decimal
(
f
[
'decimal'
])
<
search_decimal
]
assert
response
.
data
==
expected_data
# Tests that the date filter set with 'gt' in the filter class works.
search_date
=
datetime
.
date
(
2012
,
10
,
2
)
request
=
factory
.
get
(
'/'
,
{
'date'
:
'
%
s'
%
search_date
})
# search_date str: '2012-10-02'
response
=
view
(
request
)
.
render
()
assert
response
.
status_code
==
status
.
HTTP_200_OK
expected_data
=
[
f
for
f
in
self
.
data
if
parse_date
(
f
[
'date'
])
>
search_date
]
assert
response
.
data
==
expected_data
# Tests that the text filter set with 'icontains' in the filter class works.
search_text
=
'ff'
request
=
factory
.
get
(
'/'
,
{
'text'
:
'
%
s'
%
search_text
})
response
=
view
(
request
)
.
render
()
assert
response
.
status_code
==
status
.
HTTP_200_OK
expected_data
=
[
f
for
f
in
self
.
data
if
search_text
in
f
[
'text'
]
.
lower
()]
assert
response
.
data
==
expected_data
# Tests that multiple filters works.
search_decimal
=
Decimal
(
'5.25'
)
search_date
=
datetime
.
date
(
2012
,
10
,
2
)
request
=
factory
.
get
(
'/'
,
{
'decimal'
:
'
%
s'
%
(
search_decimal
,),
'date'
:
'
%
s'
%
(
search_date
,)
})
response
=
view
(
request
)
.
render
()
assert
response
.
status_code
==
status
.
HTTP_200_OK
expected_data
=
[
f
for
f
in
self
.
data
if
parse_date
(
f
[
'date'
])
>
search_date
and
Decimal
(
f
[
'decimal'
])
<
search_decimal
]
assert
response
.
data
==
expected_data
@unittest.skipUnless
(
django_filters
,
'django-filter not installed'
)
def
test_incorrectly_configured_filter
(
self
):
"""
An error should be displayed when the filter class is misconfigured.
"""
view
=
IncorrectlyConfiguredRootView
.
as_view
()
request
=
factory
.
get
(
'/'
)
self
.
assertRaises
(
AssertionError
,
view
,
request
)
@unittest.skipUnless
(
django_filters
,
'django-filter not installed'
)
def
test_base_model_filter
(
self
):
"""
The `get_filter_class` model checks should allow base model filters.
"""
view
=
BaseFilterableItemFilterRootView
.
as_view
()
request
=
factory
.
get
(
'/?text=aaa'
)
response
=
view
(
request
)
.
render
()
assert
response
.
status_code
==
status
.
HTTP_200_OK
assert
len
(
response
.
data
)
==
1
@unittest.skipUnless
(
django_filters
,
'django-filter not installed'
)
def
test_base_model_filter_with_proxy
(
self
):
"""
The `get_filter_class` model checks should allow base model filters.
"""
view
=
BaseFilterableItemFilterWithProxyRootView
.
as_view
()
request
=
factory
.
get
(
'/?text=aaa'
)
response
=
view
(
request
)
.
render
()
assert
response
.
status_code
==
status
.
HTTP_200_OK
assert
len
(
response
.
data
)
==
1
@unittest.skipUnless
(
django_filters
,
'django-filter not installed'
)
def
test_unknown_filter
(
self
):
"""
GET requests with filters that aren't configured should return 200.
"""
view
=
FilterFieldsRootView
.
as_view
()
search_integer
=
10
request
=
factory
.
get
(
'/'
,
{
'integer'
:
'
%
s'
%
search_integer
})
response
=
view
(
request
)
.
render
()
assert
response
.
status_code
==
status
.
HTTP_200_OK
@override_settings
(
ROOT_URLCONF
=
'tests.test_filters'
)
class
IntegrationTestDetailFiltering
(
CommonFilteringTestCase
):
"""
Integration tests for filtered detail views.
"""
def
_get_url
(
self
,
item
):
return
reverse
(
'detail-view'
,
kwargs
=
dict
(
pk
=
item
.
pk
))
@unittest.skipUnless
(
django_filters
,
'django-filter not installed'
)
def
test_get_filtered_detail_view
(
self
):
"""
GET requests to filtered RetrieveAPIView that have a filter_class set
should return filtered results.
"""
item
=
self
.
objects
.
all
()[
0
]
data
=
self
.
_serialize_object
(
item
)
# Basic test with no filter.
response
=
self
.
client
.
get
(
self
.
_get_url
(
item
))
assert
response
.
status_code
==
status
.
HTTP_200_OK
assert
response
.
data
==
data
# Tests that the decimal filter set that should fail.
search_decimal
=
Decimal
(
'4.25'
)
high_item
=
self
.
objects
.
filter
(
decimal__gt
=
search_decimal
)[
0
]
response
=
self
.
client
.
get
(
'{url}'
.
format
(
url
=
self
.
_get_url
(
high_item
)),
{
'decimal'
:
'{param}'
.
format
(
param
=
search_decimal
)})
assert
response
.
status_code
==
status
.
HTTP_404_NOT_FOUND
# Tests that the decimal filter set that should succeed.
search_decimal
=
Decimal
(
'4.25'
)
low_item
=
self
.
objects
.
filter
(
decimal__lt
=
search_decimal
)[
0
]
low_item_data
=
self
.
_serialize_object
(
low_item
)
response
=
self
.
client
.
get
(
'{url}'
.
format
(
url
=
self
.
_get_url
(
low_item
)),
{
'decimal'
:
'{param}'
.
format
(
param
=
search_decimal
)})
assert
response
.
status_code
==
status
.
HTTP_200_OK
assert
response
.
data
==
low_item_data
# Tests that multiple filters works.
search_decimal
=
Decimal
(
'5.25'
)
search_date
=
datetime
.
date
(
2012
,
10
,
2
)
valid_item
=
self
.
objects
.
filter
(
decimal__lt
=
search_decimal
,
date__gt
=
search_date
)[
0
]
valid_item_data
=
self
.
_serialize_object
(
valid_item
)
response
=
self
.
client
.
get
(
'{url}'
.
format
(
url
=
self
.
_get_url
(
valid_item
)),
{
'decimal'
:
'{decimal}'
.
format
(
decimal
=
search_decimal
),
'date'
:
'{date}'
.
format
(
date
=
search_date
)
})
assert
response
.
status_code
==
status
.
HTTP_200_OK
assert
response
.
data
==
valid_item_data
class
SearchFilterModel
(
models
.
Model
):
title
=
models
.
CharField
(
max_length
=
20
)
text
=
models
.
CharField
(
max_length
=
100
)
...
...
@@ -720,42 +334,6 @@ class DjangoFilterOrderingSerializer(serializers.ModelSerializer):
fields
=
'__all__'
class
DjangoFilterOrderingTests
(
TestCase
):
def
setUp
(
self
):
data
=
[{
'date'
:
datetime
.
date
(
2012
,
10
,
8
),
'text'
:
'abc'
},
{
'date'
:
datetime
.
date
(
2013
,
10
,
8
),
'text'
:
'bcd'
},
{
'date'
:
datetime
.
date
(
2014
,
10
,
8
),
'text'
:
'cde'
}]
for
d
in
data
:
DjangoFilterOrderingModel
.
objects
.
create
(
**
d
)
@unittest.skipUnless
(
django_filters
,
'django-filter not installed'
)
def
test_default_ordering
(
self
):
class
DjangoFilterOrderingView
(
generics
.
ListAPIView
):
serializer_class
=
DjangoFilterOrderingSerializer
queryset
=
DjangoFilterOrderingModel
.
objects
.
all
()
filter_backends
=
(
filters
.
DjangoFilterBackend
,)
filter_fields
=
[
'text'
]
ordering
=
(
'-date'
,)
view
=
DjangoFilterOrderingView
.
as_view
()
request
=
factory
.
get
(
'/'
)
response
=
view
(
request
)
assert
response
.
data
==
[
{
'id'
:
3
,
'date'
:
'2014-10-08'
,
'text'
:
'cde'
},
{
'id'
:
2
,
'date'
:
'2013-10-08'
,
'text'
:
'bcd'
},
{
'id'
:
1
,
'date'
:
'2012-10-08'
,
'text'
:
'abc'
}
]
class
OrderingFilterTests
(
TestCase
):
def
setUp
(
self
):
# Sequence of title/text is:
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment