Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-ora2
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
edx-ora2
Commits
47d2fe23
Commit
47d2fe23
authored
Sep 16, 2015
by
Will Daly
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #718 from edx/will/upgrade-django-rest-framework
Upgrade djangorestframework to 3.2.3
parents
782bce7a
aa908378
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
80 additions
and
93 deletions
+80
-93
openassessment/assessment/serializers/base.py
+46
-45
openassessment/assessment/test/test_peer.py
+2
-1
openassessment/assessment/test/test_training.py
+2
-3
openassessment/tests/data/db_fixtures/feedback_on_assessment.json
+3
-4
openassessment/tests/data/db_fixtures/feedback_only_criterion.json
+3
-4
openassessment/tests/data/db_fixtures/peer_assessed.json
+3
-4
openassessment/tests/data/db_fixtures/scored.json
+3
-4
openassessment/tests/data/db_fixtures/self_assessed.json
+2
-2
openassessment/tests/data/db_fixtures/submitted.json
+2
-3
openassessment/tests/data/db_fixtures/unicode.json
+2
-2
openassessment/workflow/serializers.py
+2
-16
openassessment/xblock/data_conversion.py
+2
-2
openassessment/xblock/test/test_validation.py
+5
-1
requirements/base.txt
+3
-2
No files found.
openassessment/assessment/serializers/base.py
View file @
47d2fe23
...
...
@@ -7,6 +7,7 @@ import logging
from
django.core.cache
import
cache
from
rest_framework
import
serializers
from
rest_framework.fields
import
IntegerField
,
DateTimeField
from
openassessment.assessment.models
import
(
Assessment
,
AssessmentPart
,
Criterion
,
CriterionOption
,
Rubric
,
)
...
...
@@ -22,75 +23,41 @@ class InvalidRubric(Exception):
self
.
errors
=
deepcopy
(
errors
)
class
NestedModelSerializer
(
serializers
.
ModelSerializer
):
"""Model Serializer that supports deserialization with arbitrary nesting.
The Django REST Framework does not currently support deserialization more
than one level deep (so a parent and children). We want to be able to
create a :class:`Rubric` → :class:`Criterion` → :class:`CriterionOption`
hierarchy.
Much of the base logic already "just works" and serialization of arbritrary
depth is supported. So we just override the save_object method to
recursively link foreign key relations instead of doing it one level deep.
We don't touch many-to-many relationships because we don't need to for our
purposes, so those still only work one level deep.
"""
def
recursively_link_related
(
self
,
obj
,
**
kwargs
):
if
getattr
(
obj
,
'_related_data'
,
None
):
for
accessor_name
,
related
in
obj
.
_related_data
.
items
():
setattr
(
obj
,
accessor_name
,
related
)
for
related_obj
in
related
:
self
.
recursively_link_related
(
related_obj
,
**
kwargs
)
del
(
obj
.
_related_data
)
def
save_object
(
self
,
obj
,
**
kwargs
):
obj
.
save
(
**
kwargs
)
# The code for many-to-many relationships is just copy-pasted from the
# Django REST Framework ModelSerializer
if
getattr
(
obj
,
'_m2m_data'
,
None
):
for
accessor_name
,
object_list
in
obj
.
_m2m_data
.
items
():
setattr
(
obj
,
accessor_name
,
object_list
)
del
(
obj
.
_m2m_data
)
# This is our only real change from ModelSerializer
self
.
recursively_link_related
(
obj
,
**
kwargs
)
class
CriterionOptionSerializer
(
serializers
.
ModelSerializer
):
"""Serializer for :class:`CriterionOption`"""
# Django Rest Framework v3 no longer requires `PositiveIntegerField`s
# to be positive by default, so we need to explicitly set the `min_value`
# on the serializer field.
points
=
IntegerField
(
min_value
=
0
)
class
CriterionOptionSerializer
(
NestedModelSerializer
):
"""Serializer for :class:`CriterionOption`"""
class
Meta
:
model
=
CriterionOption
fields
=
(
'order_num'
,
'points'
,
'name'
,
'label'
,
'explanation'
)
class
CriterionSerializer
(
Nested
ModelSerializer
):
class
CriterionSerializer
(
serializers
.
ModelSerializer
):
"""Serializer for :class:`Criterion`"""
options
=
CriterionOptionSerializer
(
required
=
True
,
many
=
True
)
points_possible
=
serializers
.
Field
(
source
=
'points_possible'
)
class
Meta
:
model
=
Criterion
fields
=
(
'order_num'
,
'name'
,
'label'
,
'prompt'
,
'options'
,
'points_possible'
)
class
RubricSerializer
(
Nested
ModelSerializer
):
class
RubricSerializer
(
serializers
.
ModelSerializer
):
"""Serializer for :class:`Rubric`."""
criteria
=
CriterionSerializer
(
required
=
True
,
many
=
True
)
points_possible
=
serializers
.
Field
(
source
=
'points_possible'
)
class
Meta
:
model
=
Rubric
fields
=
(
'id'
,
'content_hash'
,
'structure_hash'
,
'criteria'
,
'points_possible'
)
def
validate_criteria
(
self
,
attrs
,
sourc
e
):
def
validate_criteria
(
self
,
valu
e
):
"""Make sure we have at least one Criterion in the Rubric."""
criteria
=
attrs
[
source
]
if
not
criteria
:
if
not
value
:
raise
serializers
.
ValidationError
(
"Must have at least one criterion"
)
return
attrs
return
value
@classmethod
def
serialized_from_cache
(
cls
,
rubric
,
local_cache
=
None
):
...
...
@@ -135,6 +102,33 @@ class RubricSerializer(NestedModelSerializer):
return
rubric_dict
def
create
(
self
,
validated_data
):
"""
Create the rubric model, including its nested models.
Args:
validated_data (dict): Dictionary of validated data for the rubric,
including nested Criterion and CriterionOption data.
Returns:
Rubric
"""
criteria_data
=
validated_data
.
pop
(
"criteria"
)
rubric
=
Rubric
.
objects
.
create
(
**
validated_data
)
# Create each nested criterion in the rubric, linking it to the rubric
for
criterion_dict
in
criteria_data
:
options_data
=
criterion_dict
.
pop
(
"options"
)
criterion
=
Criterion
.
objects
.
create
(
rubric
=
rubric
,
**
criterion_dict
)
# Create each option in the criterion, linking it to the criterion
CriterionOption
.
objects
.
bulk_create
(
CriterionOption
(
criterion
=
criterion
,
**
option_dict
)
for
option_dict
in
options_data
)
return
rubric
class
AssessmentPartSerializer
(
serializers
.
ModelSerializer
):
"""Serializer for :class:`AssessmentPart`."""
...
...
@@ -147,6 +141,13 @@ class AssessmentPartSerializer(serializers.ModelSerializer):
class
AssessmentSerializer
(
serializers
.
ModelSerializer
):
"""Simplified serializer for :class:`Assessment` that's lighter on the DB."""
# Django Rest Framework v3 uses the Django setting `DATETIME_FORMAT`
# when serializing datetimes. This differs from v2, which always
# returned a datetime. To preserve the old behavior, we explicitly
# set `format` to None.
# http://www.django-rest-framework.org/api-guide/fields/#datetimefield
scored_at
=
DateTimeField
(
format
=
None
,
required
=
False
)
class
Meta
:
model
=
Assessment
fields
=
(
...
...
openassessment/assessment/test/test_peer.py
View file @
47d2fe23
...
...
@@ -152,13 +152,14 @@ STEP_REQUIREMENTS = {
}
}
@ddt
class
TestPeerApi
(
CacheResetTest
):
"""
Tests for the peer assessment API functions.
"""
CREATE_ASSESSMENT_NUM_QUERIES
=
5
8
CREATE_ASSESSMENT_NUM_QUERIES
=
5
3
def
test_create_assessment_points
(
self
):
self
.
_create_student_and_submission
(
"Tim"
,
"Tim's answer"
)
...
...
openassessment/assessment/test/test_training.py
View file @
47d2fe23
...
...
@@ -32,8 +32,8 @@ class TrainingExampleSerializerTest(CacheResetTest):
},
{
"order_num"
:
2
,
"name"
:
"єχ¢єℓℓєηт"
,
"explanation"
:
"乇メc乇レレ乇刀イ フo乃!"
,
"name"
:
u
"єχ¢єℓℓєηт"
,
"explanation"
:
u
"乇メc乇レレ乇刀イ フo乃!"
,
"points"
:
2
,
},
]
...
...
@@ -89,7 +89,6 @@ class TrainingExampleSerializerTest(CacheResetTest):
},
]
def
test_duplicate_training_example
(
self
):
# Deserialize some examples for a rubric
deserialize_training_examples
(
self
.
EXAMPLES
[
0
:
2
],
self
.
RUBRIC
)
...
...
openassessment/tests/data/db_fixtures/feedback_on_assessment.json
View file @
47d2fe23
...
...
@@ -780,7 +780,7 @@
"uuid"
:
"387d840a-d0ae-11e3-bb0e-14109fd8dc43"
,
"student_item"
:
2
,
"created_at"
:
"2014-04-30T21:27:24.181Z"
,
"
raw_
answer"
:
"{
\"
text
\"
:
\"
E
\\
u00e3
\\
u00e9um quis d
\\
u00ed
\\
u00e7o
\\
u00e9l
\\
u00e2b
\\
u00f3r
\\
u00e3ret. N
\\
u00e1m in
\\
u00e7
\\
u00f4mmune p
\\
u00f3nder
\\
u00fam apeirian, te
\\
u00e2lii m
\\
u00e1zim
\\
u00ednt
\\
u00e9ll
\\
u00eagat nec, ex
\\
u00e9leif
\\
u00e9nd el
\\
u00f3quenti
\\
u00e2m usu. His no n
\\
u00f3vum lu
\\
u00e7ilius,
\\
u00e0utem
\\
u00e3
\\
u00e9que vix
\\
u00e0d.
\"
}"
,
"answer"
:
"{
\"
text
\"
:
\"
E
\\
u00e3
\\
u00e9um quis d
\\
u00ed
\\
u00e7o
\\
u00e9l
\\
u00e2b
\\
u00f3r
\\
u00e3ret. N
\\
u00e1m in
\\
u00e7
\\
u00f4mmune p
\\
u00f3nder
\\
u00fam apeirian, te
\\
u00e2lii m
\\
u00e1zim
\\
u00ednt
\\
u00e9ll
\\
u00eagat nec, ex
\\
u00e9leif
\\
u00e9nd el
\\
u00f3quenti
\\
u00e2m usu. His no n
\\
u00f3vum lu
\\
u00e7ilius,
\\
u00e0utem
\\
u00e3
\\
u00e9que vix
\\
u00e0d.
\"
}"
,
"attempt_number"
:
1
,
"submitted_at"
:
"2014-04-30T21:27:24.173Z"
}
...
...
@@ -792,7 +792,7 @@
"uuid"
:
"1783758f-d0ae-11e3-b495-14109fd8dc43"
,
"student_item"
:
1
,
"created_at"
:
"2014-04-30T21:26:28.855Z"
,
"
raw_
answer"
:
"{
\"
text
\"
:
\"
L
\\
u00f5r
\\
u00eam
\\
u00edpsum d
\\
u00f4lor sit amet, in d
\\
u00fao p
\\
u00f5pul
\\
u00f3 m
\\
u00e0nd
\\
u00e1mus, alienum cons
\\
u00e9q
\\
u00faat pers
\\
u00e9cuti mel
\\
u00e0n. R
\\
u00eabum de
\\
u00e7or
\\
u00ea
\\
u00e9
\\
u00fam an, s
\\
u00e0ep
\\
u00e9 p
\\
u00f5pulo splendid
\\
u00e9 te p
\\
u00e9r.
\"
}"
,
"answer"
:
"{
\"
text
\"
:
\"
L
\\
u00f5r
\\
u00eam
\\
u00edpsum d
\\
u00f4lor sit amet, in d
\\
u00fao p
\\
u00f5pul
\\
u00f3 m
\\
u00e0nd
\\
u00e1mus, alienum cons
\\
u00e9q
\\
u00faat pers
\\
u00e9cuti mel
\\
u00e0n. R
\\
u00eabum de
\\
u00e7or
\\
u00ea
\\
u00e9
\\
u00fam an, s
\\
u00e0ep
\\
u00e9 p
\\
u00f5pulo splendid
\\
u00e9 te p
\\
u00e9r.
\"
}"
,
"attempt_number"
:
1
,
"submitted_at"
:
"2014-04-30T21:26:28.847Z"
}
...
...
@@ -839,4 +839,4 @@
"latest"
:
2
}
}
]
\ No newline at end of file
]
openassessment/tests/data/db_fixtures/feedback_only_criterion.json
View file @
47d2fe23
...
...
@@ -821,7 +821,7 @@
"uuid"
:
"28cebeca-d0ab-11e3-a6ab-14109fd8dc43"
,
"student_item"
:
2
,
"created_at"
:
"2014-04-30T21:05:29.380Z"
,
"
raw_
answer"
:
"{
\"
text
\"
:
\"
Etiam vel neque id nunc lacinia tincidunt.
\"
}"
,
"answer"
:
"{
\"
text
\"
:
\"
Etiam vel neque id nunc lacinia tincidunt.
\"
}"
,
"attempt_number"
:
1
,
"submitted_at"
:
"2014-04-30T21:05:29.372Z"
}
...
...
@@ -833,9 +833,9 @@
"uuid"
:
"cf5190b8-d0aa-11e3-a734-14109fd8dc43"
,
"student_item"
:
1
,
"created_at"
:
"2014-04-30T21:02:59.241Z"
,
"
raw_
answer"
:
"{
\"
text
\"
:
\"
Lorem ipsum dolor sit amet
\"
}"
,
"answer"
:
"{
\"
text
\"
:
\"
Lorem ipsum dolor sit amet
\"
}"
,
"attempt_number"
:
1
,
"submitted_at"
:
"2014-04-30T21:02:59.234Z"
}
}
]
\ No newline at end of file
]
openassessment/tests/data/db_fixtures/peer_assessed.json
View file @
47d2fe23
...
...
@@ -800,7 +800,7 @@
"uuid"
:
"28cebeca-d0ab-11e3-a6ab-14109fd8dc43"
,
"student_item"
:
2
,
"created_at"
:
"2014-04-30T21:05:29.380Z"
,
"
raw_
answer"
:
"{
\"
text
\"
:
\"
Etiam vel neque id nunc lacinia tincidunt.
\"
}"
,
"answer"
:
"{
\"
text
\"
:
\"
Etiam vel neque id nunc lacinia tincidunt.
\"
}"
,
"attempt_number"
:
1
,
"submitted_at"
:
"2014-04-30T21:05:29.372Z"
}
...
...
@@ -812,9 +812,9 @@
"uuid"
:
"cf5190b8-d0aa-11e3-a734-14109fd8dc43"
,
"student_item"
:
1
,
"created_at"
:
"2014-04-30T21:02:59.241Z"
,
"
raw_
answer"
:
"{
\"
text
\"
:
\"
Lorem ipsum dolor sit amet
\"
}"
,
"answer"
:
"{
\"
text
\"
:
\"
Lorem ipsum dolor sit amet
\"
}"
,
"attempt_number"
:
1
,
"submitted_at"
:
"2014-04-30T21:02:59.234Z"
}
}
]
\ No newline at end of file
]
openassessment/tests/data/db_fixtures/scored.json
View file @
47d2fe23
...
...
@@ -938,7 +938,7 @@
"uuid"
:
"28cebeca-d0ab-11e3-a6ab-14109fd8dc43"
,
"student_item"
:
2
,
"created_at"
:
"2014-04-30T21:05:29.380Z"
,
"
raw_
answer"
:
"{
\"
text
\"
:
\"
Etiam vel neque id nunc lacinia tincidunt.
\"
}"
,
"answer"
:
"{
\"
text
\"
:
\"
Etiam vel neque id nunc lacinia tincidunt.
\"
}"
,
"attempt_number"
:
1
,
"submitted_at"
:
"2014-04-30T21:05:29.372Z"
}
...
...
@@ -950,7 +950,7 @@
"uuid"
:
"cf5190b8-d0aa-11e3-a734-14109fd8dc43"
,
"student_item"
:
1
,
"created_at"
:
"2014-04-30T21:02:59.241Z"
,
"
raw_
answer"
:
"{
\"
text
\"
:
\"
Lorem ipsum dolor sit amet
\"
}"
,
"answer"
:
"{
\"
text
\"
:
\"
Lorem ipsum dolor sit amet
\"
}"
,
"attempt_number"
:
1
,
"submitted_at"
:
"2014-04-30T21:02:59.234Z"
}
...
...
@@ -997,4 +997,4 @@
"latest"
:
2
}
}
]
\ No newline at end of file
]
openassessment/tests/data/db_fixtures/self_assessed.json
View file @
47d2fe23
...
...
@@ -842,7 +842,7 @@
"uuid"
:
"28cebeca-d0ab-11e3-a6ab-14109fd8dc43"
,
"student_item"
:
2
,
"created_at"
:
"2014-04-30T21:05:29.380Z"
,
"
raw_
answer"
:
"{
\"
text
\"
:
\"
Etiam vel neque id nunc lacinia tincidunt.
\"
}"
,
"answer"
:
"{
\"
text
\"
:
\"
Etiam vel neque id nunc lacinia tincidunt.
\"
}"
,
"attempt_number"
:
1
,
"submitted_at"
:
"2014-04-30T21:05:29.372Z"
}
...
...
@@ -854,7 +854,7 @@
"uuid"
:
"cf5190b8-d0aa-11e3-a734-14109fd8dc43"
,
"student_item"
:
1
,
"created_at"
:
"2014-04-30T21:02:59.241Z"
,
"
raw_
answer"
:
"{
\"
text
\"
:
\"
Lorem ipsum dolor sit amet
\"
}"
,
"answer"
:
"{
\"
text
\"
:
\"
Lorem ipsum dolor sit amet
\"
}"
,
"attempt_number"
:
1
,
"submitted_at"
:
"2014-04-30T21:02:59.234Z"
}
...
...
openassessment/tests/data/db_fixtures/submitted.json
View file @
47d2fe23
...
...
@@ -477,9 +477,9 @@
"uuid"
:
"cf5190b8-d0aa-11e3-a734-14109fd8dc43"
,
"student_item"
:
1
,
"created_at"
:
"2014-04-30T21:02:59.241Z"
,
"
raw_
answer"
:
"{
\"
text
\"
:
\"
Lorem ipsum dolor sit amet
\"
}"
,
"answer"
:
"{
\"
text
\"
:
\"
Lorem ipsum dolor sit amet
\"
}"
,
"attempt_number"
:
1
,
"submitted_at"
:
"2014-04-30T21:02:59.234Z"
}
}
]
\ No newline at end of file
]
openassessment/tests/data/db_fixtures/unicode.json
View file @
47d2fe23
...
...
@@ -463,7 +463,7 @@
"uuid"
:
"99765973-d1f9-11e3-841a-14109fd8dc43"
,
"student_item"
:
2
,
"created_at"
:
"2014-05-02T12:59:30.290Z"
,
"
raw_
answer"
:
"{
\"
text
\"
:
\"\\
u0547
\\
ufec9
\\
u0e23
\\
u0547
\\
u0e23
\\
u0547
\\
u027c
\\
u0671
\\
u0e01
\\
ufeed
\"
}"
,
"answer"
:
"{
\"
text
\"
:
\"\\
u0547
\\
ufec9
\\
u0e23
\\
u0547
\\
u0e23
\\
u0547
\\
u027c
\\
u0671
\\
u0e01
\\
ufeed
\"
}"
,
"attempt_number"
:
1
,
"submitted_at"
:
"2014-05-02T12:59:30.283Z"
}
...
...
@@ -475,7 +475,7 @@
"uuid"
:
"8c52cfdc-d1f9-11e3-953c-14109fd8dc43"
,
"student_item"
:
1
,
"created_at"
:
"2014-05-02T12:59:08.243Z"
,
"
raw_
answer"
:
"{
\"
text
\"
:
\"\\
u0442
\\
u0454
\\
u0455
\\
u0442
\\
u0455
\\
u0442
\\
u044f
\\
u03b9
\\
u03b7
\\
ufeed
\"
}"
,
"answer"
:
"{
\"
text
\"
:
\"\\
u0442
\\
u0454
\\
u0455
\\
u0442
\\
u0455
\\
u0442
\\
u044f
\\
u03b9
\\
u03b7
\\
ufeed
\"
}"
,
"attempt_number"
:
1
,
"submitted_at"
:
"2014-05-02T12:59:08.234Z"
}
...
...
openassessment/workflow/serializers.py
View file @
47d2fe23
"""
Serializers are created to ensure models do not have to be accessed outside the
scope of the
Tim
APIs.
scope of the
ORA2
APIs.
"""
from
rest_framework
import
serializers
from
openassessment.workflow.models
import
AssessmentWorkflow
,
AssessmentWorkflowCancellation
class
AssessmentWorkflowSerializer
(
serializers
.
ModelSerializer
):
score
=
serializers
.
Field
(
source
=
'score'
)
score
=
serializers
.
ReadOnlyField
(
required
=
False
)
class
Meta
:
model
=
AssessmentWorkflow
...
...
@@ -22,20 +22,6 @@ class AssessmentWorkflowSerializer(serializers.ModelSerializer):
'score'
)
# Not implemented yet:
#
# class AssessmentWorkflowHistorySerializer(serializers.ModelSerializer):
# class Meta:
# model = AssessmentWorkflowHistory
# fields = (
# 'workflow',
# 'app',
# 'event_type',
# 'event_data',
# 'description',
# 'created_at'
# )
class
AssessmentWorkflowCancellationSerializer
(
serializers
.
ModelSerializer
):
"""
...
...
openassessment/xblock/data_conversion.py
View file @
47d2fe23
...
...
@@ -182,7 +182,7 @@ def prepare_submission_for_serialization(submission_data):
def
create_submission_dict
(
submission
,
prompts
):
"""
1. Convert from legacy format.
3
. Add prompts to submission['answer']['parts'] to simplify iteration in the template.
2
. Add prompts to submission['answer']['parts'] to simplify iteration in the template.
Args:
submission (dict): Submission dictionary.
...
...
@@ -191,7 +191,7 @@ def create_submission_dict(submission, prompts):
Returns:
dict
"""
parts
=
[{
'prompt'
:
prompt
,
'text'
:
''
}
for
prompt
in
prompts
]
parts
=
[{
'prompt'
:
prompt
,
'text'
:
''
}
for
prompt
in
prompts
]
if
'text'
in
submission
[
'answer'
]:
parts
[
0
][
'text'
]
=
submission
[
'answer'
]
.
pop
(
'text'
)
...
...
openassessment/xblock/test/test_validation.py
View file @
47d2fe23
...
...
@@ -86,7 +86,11 @@ class RubricValidationTest(TestCase):
is_released
=
data
.
get
(
'is_released'
,
False
)
is_example_based
=
data
.
get
(
'is_example_based'
,
False
)
success
,
msg
=
validate_rubric
(
data
[
'rubric'
],
current_rubric
,
is_released
,
is_example_based
,
STUB_I18N
data
[
'rubric'
],
current_rubric
,
is_released
,
is_example_based
,
STUB_I18N
)
self
.
assertTrue
(
success
)
self
.
assertEqual
(
msg
,
u''
)
...
...
requirements/base.txt
View file @
47d2fe23
...
...
@@ -6,7 +6,7 @@
git+https://github.com/edx/XBlock.git@9c634481dfc85a17dcb3351ca232d7098a38e10e#egg=XBlock
# edx-submissions
git+https://github.com/edx/edx-submissions.git@
9538ee8a971d04dc1cb05e88f6aa0c36b224455c#egg=edx-submissions
git+https://github.com/edx/edx-submissions.git@
14aeaa9e30f9a408b34ffaf6d78409dedaad015a#egg=edx-submissions==0.1.0
# Third Party Requirements
boto>=2.32.1,<3.0.0
...
...
@@ -16,8 +16,9 @@ django>=1.4,<1.5
django-celery==3.1.16
django-extensions==1.5.5
django-model-utils==2.3.1
djangorestframework
<2.4
djangorestframework
>=3.1,<3.2
dogapi==1.2.1
jsonfield==1.0.3
lazy==1.1
loremipsum==1.0.5
python-dateutil==2.1
...
...
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