Skip to content

Commit 4d32ee1

Browse files
author
Nicolae Godina
authored
Merge pull request #275 from uoxiu/Betalos-master
Support latest drf@3.11.0 and django@3.0.0 from Betalos master
2 parents 95c3fe8 + 95d93ab commit 4d32ee1

File tree

11 files changed

+84
-71
lines changed

11 files changed

+84
-71
lines changed

.travis.yml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,8 @@ services: mongodb
88
sudo: false
99

1010
env:
11-
- TOX_ENV=dj111-py36-me016
12-
- TOX_ENV=dj111-py36-me018
13-
- TOX_ENV=dj22-py36-me016
14-
- TOX_ENV=dj22-py36-me018
11+
- TOX_ENV=dj2-py36-me019
12+
- TOX_ENV=dj30-py36-me019
1513

1614
matrix:
1715
fast_finish: true

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ The features and differences of this package are described in [API documentation
1717

1818
## Requirements
1919

20-
* Django == 1.* | 2.*
20+
* Django == 2.* | 3.0
2121
* djangorestframework == 3.*
22-
* mongoengine == 0.16.* | 0.17.* | 0.18.*
22+
* mongoengine == 0.18.* | 0.19.*
2323
* blinker == 1.* (for mongoengine referencefields to work)
2424

2525
## Installation
@@ -93,6 +93,6 @@ Documentation available [here](https://github.com/umutbozkurt/django-rest-framew
9393
@qwiglydee
9494
@BurkovBA
9595
@Vayel
96-
@uixou
96+
@uoxiu
9797

9898
Feel free to mail me if you consider being a maintainer.

requirements/requirements-testing.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,4 @@ pytest
22
pytest-cov
33
pytest-django
44
mock
5-
six
65
pytz

rest_framework_mongoengine/fields.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,19 @@
22

33
from bson import DBRef, ObjectId
44
from bson.errors import InvalidId
5-
from django.utils import six
6-
from django.utils.encoding import smart_text
7-
from django.utils.translation import ugettext_lazy as _
8-
from mongoengine import fields as me_fields
5+
from django.utils.encoding import smart_str
6+
from django.utils.translation import gettext_lazy as _
97
from mongoengine import Document, EmbeddedDocument
8+
from mongoengine import fields as me_fields
109
from mongoengine.base import get_document
1110
from mongoengine.base.common import _document_registry
12-
from mongoengine.errors import ValidationError as MongoValidationError
1311
from mongoengine.errors import DoesNotExist, NotRegistered
12+
from mongoengine.errors import ValidationError as MongoValidationError
1413
from mongoengine.queryset import QuerySet, QuerySetManager
1514
from rest_framework import serializers
1615
from rest_framework.exceptions import ValidationError
17-
from rest_framework.fields import empty, html
16+
from rest_framework.fields import empty
17+
from rest_framework.utils import html
1818
from rest_framework.settings import api_settings
1919

2020

@@ -23,12 +23,12 @@ class ObjectIdField(serializers.Field):
2323

2424
def to_internal_value(self, value):
2525
try:
26-
return ObjectId(smart_text(value))
26+
return ObjectId(smart_str(value))
2727
except InvalidId:
2828
raise serializers.ValidationError("'%s' is not a valid ObjectId" % value)
2929

3030
def to_representation(self, value):
31-
return smart_text(value)
31+
return smart_str(value)
3232

3333

3434
class DocumentField(serializers.Field):
@@ -60,13 +60,13 @@ def to_representation(self, obj):
6060
6161
DRF ModelField uses ``value_to_string`` for this purpose. Mongoengine fields do not have such method.
6262
63-
This implementation uses ``django.utils.encoding.smart_text`` to convert everything to text, while keeping json-safe types intact.
63+
This implementation uses ``django.utils.encoding.smart_str`` to convert everything to text, while keeping json-safe types intact.
6464
6565
NB: The argument is whole object, instead of attribute value. This is upstream feature.
6666
Probably because the field can be represented by a complicated method with nontrivial way to extract data.
6767
"""
6868
value = self.model_field.__get__(obj, None)
69-
return smart_text(value, strings_only=True)
69+
return smart_str(value, strings_only=True)
7070

7171
def run_validators(self, value):
7272
""" validate value.
@@ -121,7 +121,7 @@ class GenericField(serializers.Field):
121121
""" Field for generic values.
122122
123123
Recursively traverses lists and dicts.
124-
Primitive values are serialized using ``django.utils.encoding.smart_text`` (keeping json-safe intact).
124+
Primitive values are serialized using ``django.utils.encoding.smart_str`` (keeping json-safe intact).
125125
Embedded documents handled using temporary GenericEmbeddedField.
126126
127127
No validation performed.
@@ -143,7 +143,7 @@ def represent_data(self, data):
143143
elif data is None:
144144
return None
145145
else:
146-
return smart_text(data, strings_only=True)
146+
return smart_str(data, strings_only=True)
147147

148148
def to_internal_value(self, value):
149149
return self.parse_data(value)
@@ -250,7 +250,7 @@ def choices(self):
250250

251251
return OrderedDict([
252252
(
253-
six.text_type(self.to_representation(item)),
253+
str(self.to_representation(item)),
254254
self.display_value(item)
255255
)
256256
for item in queryset
@@ -261,7 +261,7 @@ def grouped_choices(self):
261261
return self.choices
262262

263263
def display_value(self, instance):
264-
return six.text_type(instance)
264+
return str(instance)
265265

266266
def parse_id(self, value):
267267
try:
@@ -529,7 +529,7 @@ def to_internal_value(self, data):
529529
api_settings.NON_FIELD_ERRORS_KEY: [message]
530530
})
531531
return {
532-
six.text_type(key): self.child.run_validation(value)
532+
str(key): self.child.run_validation(value)
533533
for key, value in data.items()
534534
}
535535

@@ -547,7 +547,7 @@ class FileField(serializers.FileField):
547547
"""
548548

549549
def to_representation(self, value):
550-
return smart_text(value.grid_id) if hasattr(value, 'grid_id') else None
550+
return smart_str(value.grid_id) if hasattr(value, 'grid_id') else None
551551

552552

553553
class ImageField(FileField):

rest_framework_mongoengine/repr.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
import re
88

9-
from django.utils import six
109
from django.utils.encoding import force_str
1110
from mongoengine.base import BaseDocument
1211
from mongoengine.fields import BaseField
@@ -33,7 +32,7 @@ def mongo_field_repr(value):
3332
def mongo_doc_repr(value):
3433
# mimic django models.Model.__repr__
3534
try:
36-
u = six.text_type(value)
35+
u = str(value)
3736
except (UnicodeEncodeError, UnicodeDecodeError):
3837
u = '[Bad Unicode data]'
3938
return force_str('<%s: %s>' % (value.__class__.__name__, u))

rest_framework_mongoengine/routers.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ class MongoRouterMixin(object):
66
77
Determines base_name from mongo queryset
88
"""
9-
def get_default_base_name(self, viewset):
9+
10+
def get_default_basename(self, viewset):
1011
queryset = getattr(viewset, 'queryset', None)
1112
assert queryset is not None, ('`base_name` argument not specified, and could '
1213
'not automatically determine the name from the viewset, as '

rest_framework_mongoengine/serializers.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
import warnings
33
from collections import OrderedDict, namedtuple
44

5-
from django.utils.six import get_unbound_function
65
from mongoengine import fields as me_fields
76
from mongoengine.errors import ValidationError as me_ValidationError
87
from rest_framework import fields as drf_fields
@@ -225,7 +224,7 @@ def recursive_save(self, validated_data, instance=None):
225224

226225
# for EmbeddedDocumentSerializers, call recursive_save
227226
if isinstance(field, EmbeddedDocumentSerializer):
228-
me_data[key] = field.recursive_save(value)
227+
me_data[key] = field.recursive_save(value) if value is not None else value # issue when the value is none
229228

230229
# same for lists of EmbeddedDocumentSerializers i.e.
231230
# ListField(EmbeddedDocumentField) or EmbeddedDocumentListField
@@ -534,7 +533,7 @@ def get_customization_for_nested_field(self, field_name):
534533
nested_validate_methods = {}
535534
for attr in dir(self.__class__):
536535
if attr.startswith('validate_%s__' % field_name.replace('.', '__')):
537-
method = get_unbound_function(getattr(self.__class__, attr))
536+
method = getattr(self.__class__, attr)
538537
method_name = 'validate_' + attr[len('validate_%s__' % field_name.replace('.', '__')):]
539538
nested_validate_methods[method_name] = method
540539

rest_framework_mongoengine/validators.py

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88

99

1010
class MongoValidatorMixin():
11-
def exclude_current_instance(self, queryset):
12-
if self.instance is not None:
13-
return queryset.filter(pk__ne=self.instance.pk)
11+
def exclude_current_instance(self, queryset, instance):
12+
if instance is not None:
13+
return queryset.filter(pk__ne=instance.pk)
1414
return queryset
1515

1616

@@ -19,10 +19,26 @@ class UniqueValidator(MongoValidatorMixin, validators.UniqueValidator):
1919
2020
Used by :class:`DocumentSerializer` for fields, present in unique indexes.
2121
"""
22-
def __call__(self, value):
22+
23+
def __init__(self, queryset, message=None, lookup=''):
24+
"""
25+
Setting empty string as default lookup for UniqueValidator.
26+
For Mongoengine exact is a shortcut to query with regular experission.
27+
This fixes https://github.com/umutbozkurt/django-rest-framework-mongoengine/issues/264
28+
"""
29+
super(UniqueValidator, self).__init__(queryset, message, lookup)
30+
31+
def __call__(self, value, serializer_field):
32+
# Determine the underlying model field name. This may not be the
33+
# same as the serializer field name if `source=<>` is set.
34+
field_name = serializer_field.source_attrs[-1]
35+
# Determine the existing instance, if this is an update operation.
36+
instance = getattr(serializer_field.parent, 'instance', None)
37+
2338
queryset = self.queryset
24-
queryset = self.filter_queryset(value, queryset)
25-
queryset = self.exclude_current_instance(queryset)
39+
queryset = self.filter_queryset(value, queryset, field_name)
40+
queryset = self.exclude_current_instance(queryset, instance)
41+
2642
if queryset.first():
2743
raise ValidationError(self.message.format())
2844

@@ -38,14 +54,19 @@ class UniqueTogetherValidator(MongoValidatorMixin, validators.UniqueTogetherVali
3854
3955
Used by :class:`DocumentSerializer` for fields, present in unique indexes.
4056
"""
41-
def __call__(self, attrs):
57+
def __call__(self, attrs, serializer):
4258
try:
43-
self.enforce_required_fields(attrs)
59+
self.enforce_required_fields(attrs, serializer)
4460
except SkipField:
4561
return
62+
63+
# Determine the existing instance, if this is an update operation.
64+
instance = getattr(serializer, 'instance', None)
65+
4666
queryset = self.queryset
47-
queryset = self.filter_queryset(attrs, queryset)
48-
queryset = self.exclude_current_instance(queryset)
67+
queryset = self.filter_queryset(attrs, queryset, serializer)
68+
queryset = self.exclude_current_instance(queryset, instance)
69+
4970
# Ignore validation if any field is None
5071
checked_values = [
5172
value for field, value in attrs.items() if field in self.fields
@@ -66,9 +87,10 @@ class OptionalUniqueTogetherValidator(UniqueTogetherValidator):
6687
"""
6788
This validator passes validation if all of validation fields are missing. (for use with partial data)
6889
"""
69-
def enforce_required_fields(self, attrs):
90+
91+
def enforce_required_fields(self, attrs, serializer):
7092
try:
71-
super(OptionalUniqueTogetherValidator, self).enforce_required_fields(attrs)
93+
super(OptionalUniqueTogetherValidator, self).enforce_required_fields(attrs, serializer)
7294
except ValidationError as e:
7395
if set(e.detail.keys()) == set(self.fields):
7496
raise SkipField()

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def get_package_data(package):
2929

3030
setup(
3131
name='django-rest-framework-mongoengine',
32-
version='3.4.0',
32+
version='3.4.1',
3333
description='MongoEngine support for Django Rest Framework.',
3434
packages=get_packages('rest_framework_mongoengine'),
3535
package_data=get_package_data('rest_framework_mongoengine'),

0 commit comments

Comments
 (0)