mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-29 13:04:03 +03:00
Merge branch 'feature/filepathfield' of https://github.com/Ins1ne/django-rest-framework into Ins1ne-feature/filepathfield
This commit is contained in:
commit
8d7c0a8474
|
@ -20,7 +20,7 @@ Each serializer field class constructor takes at least these arguments. Some Fi
|
||||||
|
|
||||||
### `read_only`
|
### `read_only`
|
||||||
|
|
||||||
Read-only fields are included in the API output, but should not be included in the input during create or update operations. Any 'read_only' fields that are incorrectly included in the serializer input will be ignored.
|
Read-only fields are included in the API output, but should not be included in the input during create or update operations. Any 'read_only' fields that are incorrectly included in the serializer input will be ignored.
|
||||||
|
|
||||||
Set this to `True` to ensure that the field is used when serializing a representation, but is not used when creating or updating an instance during deserialization.
|
Set this to `True` to ensure that the field is used when serializing a representation, but is not used when creating or updating an instance during deserialization.
|
||||||
|
|
||||||
|
@ -194,6 +194,20 @@ A field that ensures the input is a valid UUID string. The `to_internal_value` m
|
||||||
- `'urn'` - RFC 4122 URN representation of the UUID: `"urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a"`
|
- `'urn'` - RFC 4122 URN representation of the UUID: `"urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a"`
|
||||||
Changing the `format` parameters only affects representation values. All formats are accepted by `to_internal_value`
|
Changing the `format` parameters only affects representation values. All formats are accepted by `to_internal_value`
|
||||||
|
|
||||||
|
## FilePathField
|
||||||
|
|
||||||
|
A field whose choices are limited to the filenames in a certain directory on the filesystem
|
||||||
|
|
||||||
|
Corresponds to `django.forms.fields.FilePathField`.
|
||||||
|
|
||||||
|
**Signature:** `FilePathField(path, match=None, recursive=False, allow_files=True, allow_folders=False, required=None, **kwargs)`
|
||||||
|
|
||||||
|
- `path` - The absolute filesystem path to a directory from which this FilePathField should get its choice.
|
||||||
|
- `match` - A regular expression, as a string, that FilePathField will use to filter filenames.
|
||||||
|
- `recursive` - Specifies whether all subdirectories of path should be included. Default is `False`.
|
||||||
|
- `allow_files` - Specifies whether files in the specified location should be included. Default is `True`. Either this or `allow_folders` must be `True`.
|
||||||
|
- `allow_folders` - Specifies whether folders in the specified location should be included. Default is `False`. Either this or `allow_files` must be `True`.
|
||||||
|
|
||||||
## IPAddressField
|
## IPAddressField
|
||||||
|
|
||||||
A field that ensures the input is a valid IPv4 or IPv6 string.
|
A field that ensures the input is a valid IPv4 or IPv6 string.
|
||||||
|
|
|
@ -12,6 +12,7 @@ import django
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.db import connection, transaction
|
from django.db import connection, transaction
|
||||||
|
from django.forms import FilePathField as DjangoFilePathField
|
||||||
from django.test.client import FakePayload
|
from django.test.client import FakePayload
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
|
@ -256,3 +257,21 @@ def set_rollback():
|
||||||
else:
|
else:
|
||||||
# transaction not managed
|
# transaction not managed
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def get_filepathfield(path, match=None, recursive=False, allow_files=True,
|
||||||
|
allow_folders=False, required=None):
|
||||||
|
"""Create proper Django FilePathField with allowed kwargs."""
|
||||||
|
|
||||||
|
if django.VERSION < (1, 5):
|
||||||
|
# django field doesn't have allow_folders, allow_files kwargs
|
||||||
|
field = DjangoFilePathField(
|
||||||
|
path, match=match, recursive=recursive, required=required
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
field = DjangoFilePathField(
|
||||||
|
path, match=match, recursive=recursive, allow_files=allow_files,
|
||||||
|
allow_folders=allow_folders, required=required
|
||||||
|
)
|
||||||
|
|
||||||
|
return field
|
||||||
|
|
|
@ -23,7 +23,7 @@ from rest_framework import ISO_8601
|
||||||
from rest_framework.compat import (
|
from rest_framework.compat import (
|
||||||
EmailValidator, MaxLengthValidator, MaxValueValidator, MinLengthValidator,
|
EmailValidator, MaxLengthValidator, MaxValueValidator, MinLengthValidator,
|
||||||
MinValueValidator, OrderedDict, URLValidator, duration_string,
|
MinValueValidator, OrderedDict, URLValidator, duration_string,
|
||||||
parse_duration, unicode_repr, unicode_to_repr
|
get_filepathfield, parse_duration, unicode_repr, unicode_to_repr
|
||||||
)
|
)
|
||||||
from rest_framework.exceptions import ValidationError
|
from rest_framework.exceptions import ValidationError
|
||||||
from rest_framework.settings import api_settings
|
from rest_framework.settings import api_settings
|
||||||
|
@ -704,6 +704,41 @@ class IPAddressField(CharField):
|
||||||
return super(IPAddressField, self).to_internal_value(data)
|
return super(IPAddressField, self).to_internal_value(data)
|
||||||
|
|
||||||
|
|
||||||
|
class FilePathField(CharField):
|
||||||
|
default_error_messages = {
|
||||||
|
'invalid_choice': _('"{input}" is not a valid path choice.')
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, path, match=None, recursive=False, allow_files=True,
|
||||||
|
allow_folders=False, required=None, **kwargs):
|
||||||
|
super(FilePathField, self).__init__(**kwargs)
|
||||||
|
|
||||||
|
# create field and get options to avoid code duplication
|
||||||
|
field = get_filepathfield(
|
||||||
|
path, match=match, recursive=recursive, allow_files=allow_files,
|
||||||
|
allow_folders=allow_folders, required=required
|
||||||
|
)
|
||||||
|
|
||||||
|
self.choices = OrderedDict(field.choices)
|
||||||
|
self.choice_strings_to_values = dict([
|
||||||
|
(six.text_type(key), key) for key in self.choices.keys()
|
||||||
|
])
|
||||||
|
|
||||||
|
def to_internal_value(self, data):
|
||||||
|
if data == '' and self.allow_blank:
|
||||||
|
return ''
|
||||||
|
|
||||||
|
try:
|
||||||
|
return self.choice_strings_to_values[six.text_type(data)]
|
||||||
|
except KeyError:
|
||||||
|
self.fail('invalid_choice', input=data)
|
||||||
|
|
||||||
|
def to_representation(self, value):
|
||||||
|
if value in ('', None):
|
||||||
|
return value
|
||||||
|
return self.choice_strings_to_values[six.text_type(value)]
|
||||||
|
|
||||||
|
|
||||||
# Number types...
|
# Number types...
|
||||||
|
|
||||||
class IntegerField(Field):
|
class IntegerField(Field):
|
||||||
|
|
|
@ -191,6 +191,7 @@ class DjangoObjectPermissionsFilter(BaseFilterBackend):
|
||||||
perm_format = '%(app_label)s.view_%(model_name)s'
|
perm_format = '%(app_label)s.view_%(model_name)s'
|
||||||
|
|
||||||
def filter_queryset(self, request, queryset, view):
|
def filter_queryset(self, request, queryset, view):
|
||||||
|
extra = {}
|
||||||
user = request.user
|
user = request.user
|
||||||
model_cls = queryset.model
|
model_cls = queryset.model
|
||||||
kwargs = {
|
kwargs = {
|
||||||
|
|
|
@ -305,7 +305,10 @@ class HTMLFormRenderer(BaseRenderer):
|
||||||
},
|
},
|
||||||
serializers.ListSerializer: {
|
serializers.ListSerializer: {
|
||||||
'base_template': 'list_fieldset.html'
|
'base_template': 'list_fieldset.html'
|
||||||
}
|
},
|
||||||
|
serializers.FilePathField: {
|
||||||
|
'base_template': 'select.html',
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
def render_field(self, field, parent_style):
|
def render_field(self, field, parent_style):
|
||||||
|
|
|
@ -771,6 +771,7 @@ class ModelSerializer(Serializer):
|
||||||
models.TimeField: TimeField,
|
models.TimeField: TimeField,
|
||||||
models.URLField: URLField,
|
models.URLField: URLField,
|
||||||
models.GenericIPAddressField: IPAddressField,
|
models.GenericIPAddressField: IPAddressField,
|
||||||
|
models.FilePathField: FilePathField,
|
||||||
}
|
}
|
||||||
if ModelDurationField is not None:
|
if ModelDurationField is not None:
|
||||||
serializer_field_mapping[ModelDurationField] = DurationField
|
serializer_field_mapping[ModelDurationField] = DurationField
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import datetime
|
import datetime
|
||||||
|
import os
|
||||||
import uuid
|
import uuid
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
|
@ -637,6 +638,24 @@ class TestIPv6AddressField(FieldValues):
|
||||||
field = serializers.IPAddressField(protocol='IPv6')
|
field = serializers.IPAddressField(protocol='IPv6')
|
||||||
|
|
||||||
|
|
||||||
|
class TestFilePathField(FieldValues):
|
||||||
|
"""
|
||||||
|
Valid and invalid values for `FilePathField`
|
||||||
|
"""
|
||||||
|
|
||||||
|
valid_inputs = {
|
||||||
|
__file__: __file__,
|
||||||
|
}
|
||||||
|
invalid_inputs = {
|
||||||
|
'wrong_path': ['"wrong_path" is not a valid path choice.']
|
||||||
|
}
|
||||||
|
outputs = {
|
||||||
|
}
|
||||||
|
field = serializers.FilePathField(
|
||||||
|
path=os.path.abspath(os.path.dirname(__file__))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# Number types...
|
# Number types...
|
||||||
|
|
||||||
class TestIntegerField(FieldValues):
|
class TestIntegerField(FieldValues):
|
||||||
|
|
Loading…
Reference in New Issue
Block a user