Ticket #5893: filepath-flolders-final.diff

File filepath-flolders-final.diff, 8.9 KB (added by Alex Gaynor, 12 years ago)

Final patch (note to others, please don't review/commit; this is an example patch for a "contributing to django" event).

  • django/core/management/validation.py

    diff --git a/django/core/management/validation.py b/django/core/management/validation.py
    index 4833337..272ac5b 100644
    a b def get_validation_errors(outfile, app=None):  
    8989                        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)
    9090            if isinstance(f, models.BooleanField) and getattr(f, 'null', False):
    9191                e.add(opts, '"%s": BooleanFields do not accept null values. Use a NullBooleanField instead.' % f.name)
     92            if isinstance(f, models.FilePathField) and not (f.allow_files or f.allow_folders):
     93                e.add(opts, '"%s": FilePathFields must have either allow_files or allow_folders set to True.' % f.name)
    9294            if f.choices:
    9395                if isinstance(f.choices, basestring) or not is_iterable(f.choices):
    9496                    e.add(opts, '"%s": "choices" should be iterable (e.g., a tuple or list).' % f.name)
  • django/db/models/fields/__init__.py

    diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py
    index 121797a..e240d39 100644
    a b class FilePathField(Field):  
    909909    description = _("File path")
    910910
    911911    def __init__(self, verbose_name=None, name=None, path='', match=None,
    912                  recursive=False, **kwargs):
     912                 recursive=False, allow_files=True, allow_folders=False, **kwargs):
    913913        self.path, self.match, self.recursive = path, match, recursive
     914        self.allow_files, self.allow_folders =  allow_files, allow_folders
    914915        kwargs['max_length'] = kwargs.get('max_length', 100)
    915916        Field.__init__(self, verbose_name, name, **kwargs)
    916917
    class FilePathField(Field):  
    920921            'match': self.match,
    921922            'recursive': self.recursive,
    922923            'form_class': forms.FilePathField,
     924            'allow_files': self.allow_files,
     925            'allow_folders': self.allow_folders,
    923926        }
    924927        defaults.update(kwargs)
    925928        return super(FilePathField, self).formfield(**defaults)
  • django/forms/fields.py

    diff --git a/django/forms/fields.py b/django/forms/fields.py
    index 49f29db..3cf730e 100644
    a b class MultiValueField(Field):  
    909909        raise NotImplementedError('Subclasses must implement this method.')
    910910
    911911class FilePathField(ChoiceField):
    912     def __init__(self, path, match=None, recursive=False, required=True,
    913                  widget=None, label=None, initial=None, help_text=None,
    914                  *args, **kwargs):
     912    def __init__(self, path, match=None, recursive=False, allow_files=True,
     913                 allow_folders=False, required=True, widget=None, label=None,
     914                 initial=None, help_text=None, *args, **kwargs):
    915915        self.path, self.match, self.recursive = path, match, recursive
     916        self.allow_files, self.allow_folders = allow_files, allow_folders
    916917        super(FilePathField, self).__init__(choices=(), required=required,
    917918            widget=widget, label=label, initial=initial, help_text=help_text,
    918919            *args, **kwargs)
    class FilePathField(ChoiceField):  
    927928
    928929        if recursive:
    929930            for root, dirs, files in sorted(os.walk(self.path)):
    930                 for f in files:
    931                     if self.match is None or self.match_re.search(f):
    932                         f = os.path.join(root, f)
    933                         self.choices.append((f, f.replace(path, "", 1)))
     931                if self.allow_files:
     932                    for f in files:
     933                        if self.match is None or self.match_re.search(f):
     934                            f = os.path.join(root, f)
     935                            self.choices.append((f, f.replace(path, "", 1)))
     936                if self.allow_folders:
     937                    for f in dirs:
     938                        if self.match is None or self.match_re.search(f):
     939                            f = os.path.join(root, f)
     940                            self.choices.append((f, f.replace(path, "", 1)))
    934941        else:
    935942            try:
    936943                for f in sorted(os.listdir(self.path)):
    937944                    full_file = os.path.join(self.path, f)
    938                     if os.path.isfile(full_file) and (self.match is None or self.match_re.search(f)):
     945                    if (((self.allow_files and os.path.isfile(full_file)) or
     946                        (self.allow_folders and os.path.isdir(full_file))) and
     947                        (self.match is None or self.match_re.search(f))):
    939948                        self.choices.append((full_file, f))
    940949            except OSError:
    941950                pass
  • docs/ref/forms/fields.txt

    diff --git a/docs/ref/forms/fields.txt b/docs/ref/forms/fields.txt
    index 4956a71..fa58006 100644
    a b For each field, we describe the default widget used if you don't specify  
    555555        A regular expression pattern; only files with names matching this expression
    556556        will be allowed as choices.
    557557
     558    .. attribute:: allow_files
     559
     560        .. versionadded:: 1.5
     561
     562        Optional.  Either ``True`` or ``False``.  Default is ``True``.  Specifies
     563        whether files in the specified location should be included.  Either this or
     564        :attr:`allow_folders` must be ``True``.
     565
     566    .. attribute:: allow_folders
     567
     568        .. versionadded:: 1.5
     569
     570        Optional.  Either ``True`` or ``False``.  Default is ``False``.  Specifies
     571        whether folders in the specified location should be included.  Either this or
     572        :attr:`allow_files` must be ``True``.
     573
     574
    558575``FloatField``
    559576~~~~~~~~~~~~~~
    560577
  • docs/ref/models/fields.txt

    diff --git a/docs/ref/models/fields.txt b/docs/ref/models/fields.txt
    index 5521a0e..d1f12ff 100644
    a b directory on the filesystem. Has three special arguments, of which the first is  
    691691    Optional. Either ``True`` or ``False``. Default is ``False``. Specifies
    692692    whether all subdirectories of :attr:`~FilePathField.path` should be included
    693693
     694.. attribute:: FilePathField.allow_files
     695
     696    .. versionadded:: 1.5
     697
     698    Optional.  Either ``True`` or ``False``.  Default is ``True``.  Specifies
     699    whether files in the specified location should be included.  Either this or
     700    :attr:`~FilePathField.allow_folders` must be ``True``.
     701
     702.. attribute:: FilePathField.allow_folders
     703
     704    .. versionadded:: 1.5
     705
     706    Optional.  Either ``True`` or ``False``.  Default is ``False``.  Specifies
     707    whether folders in the specified location should be included.  Either this
     708    or :attr:`~FilePathField.allow_files` must be ``True``.
     709
     710
    694711Of course, these arguments can be used together.
    695712
    696713The one potential gotcha is that :attr:`~FilePathField.match` applies to the
  • tests/regressiontests/forms/tests/fields.py

    diff --git a/tests/regressiontests/forms/tests/fields.py b/tests/regressiontests/forms/tests/fields.py
    index 6e4a544..4e942a1 100644
    a b class FieldsTests(SimpleTestCase):  
    981981            self.assertEqual(exp[1], got[1])
    982982            self.assertTrue(got[0].endswith(exp[0]))
    983983
     984    def test_filepathfield_folders(self):
     985        path = forms.__file__
     986        path = os.path.dirname(path) + '/'
     987        f = FilePathField(path=path, allow_folders=True, allow_files=False)
     988        f.choices.sort()
     989        expected = [
     990            ('/django/forms/extras', 'extras'),
     991        ]
     992        for exp, got in zip(expected, fix_os_paths(f.choices)):
     993            self.assertEqual(exp[1], got[1])
     994            self.assert_(got[0].endswith(exp[0]))
     995
     996        f = FilePathField(path=path, allow_folders=True, allow_files=True)
     997        f.choices.sort()
     998        expected = [
     999            ('/django/forms/__init__.py', '__init__.py'),
     1000            ('/django/forms/__init__.pyc', '__init__.pyc'),
     1001            ('/django/forms/extras', 'extras'),
     1002            ('/django/forms/fields.py', 'fields.py'),
     1003            ('/django/forms/fields.pyc', 'fields.pyc'),
     1004            ('/django/forms/forms.py', 'forms.py'),
     1005            ('/django/forms/forms.pyc', 'forms.pyc'),
     1006            ('/django/forms/formsets.py', 'formsets.py'),
     1007            ('/django/forms/formsets.pyc', 'formsets.pyc'),
     1008            ('/django/forms/models.py', 'models.py'),
     1009            ('/django/forms/models.pyc', 'models.pyc'),
     1010            ('/django/forms/util.py', 'util.py'),
     1011            ('/django/forms/util.pyc', 'util.pyc'),
     1012            ('/django/forms/widgets.py', 'widgets.py'),
     1013            ('/django/forms/widgets.pyc', 'widgets.pyc')
     1014        ]
     1015        for exp, got in zip(expected, fix_os_paths(f.choices)):
     1016            self.assertEqual(exp[1], got[1])
     1017            self.assertEqual(exp[1], got[1])
     1018
     1019
    9841020    # SplitDateTimeField ##########################################################
    9851021
    9861022    def test_splitdatetimefield_1(self):
Back to Top