Commit 7f80a2e0 by Tom Christie

Merge pull request #3211 from tomchristie/Ins1ne-feature/filepathfield

Add `FilePathField`
parents 650866cc bf35906d
...@@ -20,7 +20,7 @@ Each serializer field class constructor takes at least these arguments. Some Fi ...@@ -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 ...@@ -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 ...@@ -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
......
...@@ -12,6 +12,7 @@ from django.conf import settings ...@@ -12,6 +12,7 @@ from django.conf import settings
from django.core.exceptions import ValidationError as DjangoValidationError from django.core.exceptions import ValidationError as DjangoValidationError
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.core.validators import RegexValidator, ip_address_validators from django.core.validators import RegexValidator, ip_address_validators
from django.forms import FilePathField as DjangoFilePathField
from django.forms import ImageField as DjangoImageField from django.forms import ImageField as DjangoImageField
from django.utils import six, timezone from django.utils import six, timezone
from django.utils.dateparse import parse_date, parse_datetime, parse_time from django.utils.dateparse import parse_date, parse_datetime, parse_time
...@@ -1178,6 +1179,23 @@ class MultipleChoiceField(ChoiceField): ...@@ -1178,6 +1179,23 @@ class MultipleChoiceField(ChoiceField):
]) ])
class FilePathField(ChoiceField):
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):
# Defer to Django's FilePathField implmentation to get the
# valid set of choices.
field = DjangoFilePathField(
path, match=match, recursive=recursive, allow_files=allow_files,
allow_folders=allow_folders, required=required
)
kwargs['choices'] = field.choices
super(FilePathField, self).__init__(**kwargs)
# File types... # File types...
class FileField(Field): class FileField(Field):
......
...@@ -191,6 +191,7 @@ class DjangoObjectPermissionsFilter(BaseFilterBackend): ...@@ -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): ...@@ -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): ...@@ -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
......
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): ...@@ -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):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment