Commit 3c5ff9d7 authored by Alex Gaynor's avatar Alex Gaynor
Browse files

Fixed #5893 -- Added a flag to FilePathField to allow listing folders, in...

Fixed #5893 -- Added a flag to FilePathField to allow listing folders, in addition to regular files.  Thank you to Brian Rosner, for encouraging me to first contribute to Django 4 years ago.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@17925 bcc190cf-cafb-0310-a4f2-bffc1f526a37
parent 83fc9651
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -89,6 +89,8 @@ def get_validation_errors(outfile, app=None):
                        e.add(opts, '"%s": To use ImageFields, you need to install the Python Imaging Library. Get it at http://www.pythonware.com/products/pil/ .' % f.name)
            if isinstance(f, models.BooleanField) and getattr(f, 'null', False):
                e.add(opts, '"%s": BooleanFields do not accept null values. Use a NullBooleanField instead.' % f.name)
            if isinstance(f, models.FilePathField) and not (f.allow_files or f.allow_folders):
                e.add(opts, '"%s": FilePathFields must have either allow_files or allow_folders set to True.' % f.name)
            if f.choices:
                if isinstance(f.choices, basestring) or not is_iterable(f.choices):
                    e.add(opts, '"%s": "choices" should be iterable (e.g., a tuple or list).' % f.name)
+4 −1
Original line number Diff line number Diff line
@@ -909,8 +909,9 @@ class FilePathField(Field):
    description = _("File path")

    def __init__(self, verbose_name=None, name=None, path='', match=None,
                 recursive=False, **kwargs):
                 recursive=False, allow_files=True, allow_folders=False, **kwargs):
        self.path, self.match, self.recursive = path, match, recursive
        self.allow_files, self.allow_folders =  allow_files, allow_folders
        kwargs['max_length'] = kwargs.get('max_length', 100)
        Field.__init__(self, verbose_name, name, **kwargs)

@@ -920,6 +921,8 @@ class FilePathField(Field):
            'match': self.match,
            'recursive': self.recursive,
            'form_class': forms.FilePathField,
            'allow_files': self.allow_files,
            'allow_folders': self.allow_folders,
        }
        defaults.update(kwargs)
        return super(FilePathField, self).formfield(**defaults)
+17 −8
Original line number Diff line number Diff line
@@ -909,10 +909,11 @@ class MultiValueField(Field):
        raise NotImplementedError('Subclasses must implement this method.')

class FilePathField(ChoiceField):
    def __init__(self, path, match=None, recursive=False, required=True,
                 widget=None, label=None, initial=None, help_text=None,
                 *args, **kwargs):
    def __init__(self, path, match=None, recursive=False, allow_files=True,
                 allow_folders=False, required=True, widget=None, label=None,
                 initial=None, help_text=None, *args, **kwargs):
        self.path, self.match, self.recursive = path, match, recursive
        self.allow_files, self.allow_folders = allow_files, allow_folders
        super(FilePathField, self).__init__(choices=(), required=required,
            widget=widget, label=label, initial=initial, help_text=help_text,
            *args, **kwargs)
@@ -927,15 +928,23 @@ class FilePathField(ChoiceField):

        if recursive:
            for root, dirs, files in sorted(os.walk(self.path)):
                if self.allow_files:
                    for f in files:
                        if self.match is None or self.match_re.search(f):
                            f = os.path.join(root, f)
                            self.choices.append((f, f.replace(path, "", 1)))
                if self.allow_folders:
                    for f in dirs:
                        if self.match is None or self.match_re.search(f):
                            f = os.path.join(root, f)
                            self.choices.append((f, f.replace(path, "", 1)))
        else:
            try:
                for f in sorted(os.listdir(self.path)):
                    full_file = os.path.join(self.path, f)
                    if os.path.isfile(full_file) and (self.match is None or self.match_re.search(f)):
                    if (((self.allow_files and os.path.isfile(full_file)) or
                        (self.allow_folders and os.path.isdir(full_file))) and
                        (self.match is None or self.match_re.search(f))):
                        self.choices.append((full_file, f))
            except OSError:
                pass
+17 −0
Original line number Diff line number Diff line
@@ -555,6 +555,23 @@ For each field, we describe the default widget used if you don't specify
        A regular expression pattern; only files with names matching this expression
        will be allowed as choices.

    .. attribute:: allow_files

        .. versionadded:: 1.5

        Optional.  Either ``True`` or ``False``.  Default is ``True``.  Specifies
        whether files in the specified location should be included.  Either this or
        :attr:`allow_folders` must be ``True``.

    .. attribute:: allow_folders

        .. versionadded:: 1.5

        Optional.  Either ``True`` or ``False``.  Default is ``False``.  Specifies
        whether folders in the specified location should be included.  Either this or
        :attr:`allow_files` must be ``True``.


``FloatField``
~~~~~~~~~~~~~~

+17 −0
Original line number Diff line number Diff line
@@ -691,6 +691,23 @@ directory on the filesystem. Has three special arguments, of which the first is
    Optional. Either ``True`` or ``False``. Default is ``False``. Specifies
    whether all subdirectories of :attr:`~FilePathField.path` should be included

.. attribute:: FilePathField.allow_files

    .. versionadded:: 1.5

    Optional.  Either ``True`` or ``False``.  Default is ``True``.  Specifies
    whether files in the specified location should be included.  Either this or
    :attr:`~FilePathField.allow_folders` must be ``True``.

.. attribute:: FilePathField.allow_folders

    .. versionadded:: 1.5

    Optional.  Either ``True`` or ``False``.  Default is ``False``.  Specifies
    whether folders in the specified location should be included.  Either this
    or :attr:`~FilePathField.allow_files` must be ``True``.


Of course, these arguments can be used together.

The one potential gotcha is that :attr:`~FilePathField.match` applies to the
Loading