Ticket #5893: filepath-folders.3.diff

File filepath-folders.3.diff, 11.0 KB (added by Alex Gaynor, 15 years ago)

Merge conflicts!

  • django/core/management/validation.py

    diff --git a/django/core/management/validation.py b/django/core/management/validation.py
    index 97164d7..185edd1 100644
    a b def get_validation_errors(outfile, app=None):  
    5353                    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)
    5454            if isinstance(f, models.BooleanField) and getattr(f, 'null', False):
    5555                e.add(opts, '"%s": BooleanFields do not accept null values. Use a NullBooleanField instead.' % f.name)
     56            if isinstance(f, models.FilePathField) and not (f.allow_files or f.allow_folders):
     57                e.add(opts, '"%s": FilePathFields must have either allow_files or allow_folders set to True.' % f.name)
    5658            if f.choices:
    5759                if isinstance(f.choices, basestring) or not is_iterable(f.choices):
    5860                    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 29de8c7..e5aa74a 100644
    a b class CharField(Field):  
    567567
    568568    def get_prep_value(self, value):
    569569        return self.to_python(value)
    570    
     570
    571571    def formfield(self, **kwargs):
    572572        # Passing max_length to forms.CharField means that the value's length
    573573        # will be validated twice. This is considered acceptable since we want
    class EmailField(CharField):  
    813813class FilePathField(Field):
    814814    description = _("File path")
    815815
    816     def __init__(self, verbose_name=None, name=None, path='', match=None, recursive=False, **kwargs):
     816    def __init__(self, verbose_name=None, name=None, path='', match=None,
     817        recursive=False, allow_files=True, allow_folders=False, **kwargs):
    817818        self.path, self.match, self.recursive = path, match, recursive
     819        self.allow_files, self.allow_folders =  allow_files, allow_folders
    818820        kwargs['max_length'] = kwargs.get('max_length', 100)
    819821        Field.__init__(self, verbose_name, name, **kwargs)
    820822
    class FilePathField(Field):  
    824826            'match': self.match,
    825827            'recursive': self.recursive,
    826828            'form_class': forms.FilePathField,
     829            'allow_files': self.allow_files,
     830            'allow_folders': self.allow_folders,
    827831        }
    828832        defaults.update(kwargs)
    829833        return super(FilePathField, self).formfield(**defaults)
    class XMLField(TextField):  
    11131117    def __init__(self, verbose_name=None, name=None, schema_path=None, **kwargs):
    11141118        self.schema_path = schema_path
    11151119        Field.__init__(self, verbose_name, name, **kwargs)
    1116 
  • django/forms/fields.py

    diff --git a/django/forms/fields.py b/django/forms/fields.py
    index 2e6eb82..55d4096 100644
    a b try:  
    1414except ImportError:
    1515    from StringIO import StringIO
    1616
     17
    1718from django.core.exceptions import ValidationError
    1819from django.core import validators
    19 import django.utils.copycompat as copy
     20from django.utils import copycompat as copy
    2021from django.utils.translation import ugettext_lazy as _
    2122from django.utils.encoding import smart_unicode, smart_str
    2223from django.utils.formats import get_format
    class ChoiceField(Field):  
    579580
    580581    def __init__(self, choices=(), required=True, widget=None, label=None,
    581582                 initial=None, help_text=None, *args, **kwargs):
    582         super(ChoiceField, self).__init__(required=required, widget=widget, label=label, 
     583        super(ChoiceField, self).__init__(required=required, widget=widget, label=label,
    583584                                        initial=initial, help_text=help_text, *args, **kwargs)
    584585        self.choices = choices
    585586
    class MultiValueField(Field):  
    779780        raise NotImplementedError('Subclasses must implement this method.')
    780781
    781782class FilePathField(ChoiceField):
    782     def __init__(self, path, match=None, recursive=False, required=True,
    783                  widget=None, label=None, initial=None, help_text=None,
    784                 *args, **kwargs):
     783    def __init__(self, path, match=None, recursive=False, allow_files=True,
     784        allow_folders=False, required=True, widget=Select, label=None,
     785        initial=None, help_text=None, *args, **kwargs):
    785786        self.path, self.match, self.recursive = path, match, recursive
     787        self.allow_files, self.allow_folders = allow_files, allow_folders
    786788        super(FilePathField, self).__init__(choices=(), required=required,
    787789            widget=widget, label=label, initial=initial, help_text=help_text,
    788790            *args, **kwargs)
    class FilePathField(ChoiceField):  
    797799
    798800        if recursive:
    799801            for root, dirs, files in os.walk(self.path):
    800                 for f in files:
    801                     if self.match is None or self.match_re.search(f):
    802                         f = os.path.join(root, f)
    803                         self.choices.append((f, f.replace(path, "", 1)))
     802                if self.allow_files:
     803                    for f in files:
     804                        if self.match is None or self.match_re.search(f):
     805                            f = os.path.join(root, f)
     806                            self.choices.append((f, f.replace(path, "", 1)))
     807                if self.allow_folders:
     808                    for f in dirs:
     809                        if self.match is None or self.match_re.search(f):
     810                            f = os.path.join(root, f)
     811                            self.choices.append((f, f.replace(path, "", 1)))
    804812        else:
    805813            try:
    806814                for f in os.listdir(self.path):
    807815                    full_file = os.path.join(self.path, f)
    808                     if os.path.isfile(full_file) and (self.match is None or self.match_re.search(f)):
     816                    if (((self.allow_files and os.path.isfile(full_file)) or
     817                        (self.allow_folders and os.path.isdir(full_file))) and
     818                        (self.match is None or self.match_re.search(f))):
    809819                        self.choices.append((full_file, f))
    810820            except OSError:
    811821                pass
  • docs/ref/forms/fields.txt

    diff --git a/docs/ref/forms/fields.txt b/docs/ref/forms/fields.txt
    index 6440d2e..b91eebb 100644
    a b extra arguments; only ``path`` is required:  
    534534    A regular expression pattern; only files with names matching this expression
    535535    will be allowed as choices.
    536536
     537.. attribute:: FilePathField.allow_files
     538
     539    .. versionadded:: 1.2
     540
     541    Optional.  Either ``True`` or ``False``.  Default is ``True``.  Specifies
     542    whether files in the specified location should be included.  Either this or
     543    :attr:`~FilePathField.allow_folders` must be ``True``.
     544
     545.. attribute:: FilePathField.allow_folders
     546
     547    .. versionadded:: 1.2
     548
     549    Optional.  Either ``True`` or ``False``.  Default is ``False``.  Specifies
     550    whether folders in the specified location should be included.  Either this
     551    or :attr:`~FilePathField.allow_files` must be ``True``.
     552
    537553``FloatField``
    538554~~~~~~~~~~~~~~
    539555
  • docs/ref/models/fields.txt

    diff --git a/docs/ref/models/fields.txt b/docs/ref/models/fields.txt
    index 6a98afb..1e68a3d 100644
    a b directory on the filesystem. Has three special arguments, of which the first is  
    605605    Optional. Either ``True`` or ``False``. Default is ``False``. Specifies
    606606    whether all subdirectories of :attr:`~FilePathField.path` should be included
    607607
     608.. attribute:: FilePathField.allow_files
     609
     610    .. versionadded:: 1.2
     611
     612    Optional.  Either ``True`` or ``False``.  Default is ``True``.  Specifies
     613    whether files in the specified location should be included.  Either this or
     614    :attr:`~FilePathField.allow_folders` must be ``True``.
     615
     616.. attribute:: FilePathField.allow_folders
     617
     618    .. versionadded:: 1.2
     619
     620    Optional.  Either ``True`` or ``False``.  Default is ``False``.  Specifies
     621    whether folders in the specified location should be included.  Either this
     622    or :attr:`~FilePathField.allow_files` must be ``True``.
     623
     624
    608625Of course, these arguments can be used together.
    609626
    610627The one potential gotcha is that :attr:`~FilePathField.match` applies to the
  • tests/regressiontests/forms/fields.py

    diff --git a/tests/regressiontests/forms/fields.py b/tests/regressiontests/forms/fields.py
    index 8733090..081e886 100644
    a b Each Field's __init__() takes at least these parameters:  
    2424Other than that, the Field subclasses have class-specific options for
    2525__init__(). For example, CharField has a max_length option.
    2626"""
     27
    2728import datetime
    2829import time
    2930import re
    3031import os
    3132
     33from decimal import Decimal
    3234from unittest import TestCase
    3335
    3436from django.core.files.uploadedfile import SimpleUploadedFile
    3537from django.forms import *
    3638from django.forms.widgets import RadioFieldRenderer
    3739
    38 try:
    39     from decimal import Decimal
    40 except ImportError:
    41     from django.utils._decimal import Decimal
    42 
    4340
    4441def fix_os_paths(x):
    4542    if isinstance(x, basestring):
    class FieldsTests(TestCase):  
    819816        for exp, got in zip(expected, fix_os_paths(f.choices)):
    820817            self.assertEqual(exp[1], got[1])
    821818            assert got[0].endswith(exp[0])
     819   
     820    def test_filepathfield_folders(self):
     821        path = forms.__file__
     822        path = os.path.dirname(path) + '/'
     823        f = FilePathField(path=path, allow_folders=True, allow_files=False)
     824        f.choices.sort()
     825        expected = [
     826            ('/django/forms/extras', 'extras'),
     827        ]
     828        for exp, got in zip(expected, fix_os_paths(f.choices)):
     829            self.assertEqual(exp[1], got[1])
     830            self.assert_(got[0].endswith(exp[0]))
     831       
     832        f = FilePathField(path=path, allow_folders=True, allow_files=True)
     833        f.choices.sort()
     834        expected = [
     835            ('/django/forms/__init__.py', '__init__.py'),
     836            ('/django/forms/__init__.pyc', '__init__.pyc'),
     837            ('/django/forms/extras', 'extras'),
     838            ('/django/forms/fields.py', 'fields.py'),
     839            ('/django/forms/fields.pyc', 'fields.pyc'),
     840            ('/django/forms/forms.py', 'forms.py'),
     841            ('/django/forms/forms.pyc', 'forms.pyc'),
     842            ('/django/forms/formsets.py', 'formsets.py'),
     843            ('/django/forms/formsets.pyc', 'formsets.pyc'),
     844            ('/django/forms/models.py', 'models.py'),
     845            ('/django/forms/models.pyc', 'models.pyc'),
     846            ('/django/forms/util.py', 'util.py'),
     847            ('/django/forms/util.pyc', 'util.pyc'),
     848            ('/django/forms/widgets.py', 'widgets.py'),
     849            ('/django/forms/widgets.pyc', 'widgets.pyc')
     850        ]
     851        for exp, got in zip(expected, fix_os_paths(f.choices)):
     852            self.assertEqual(exp[1], got[1])
     853            self.assert_(got[0].endswith(exp[0]))
     854
    822855
    823856    # SplitDateTimeField ##########################################################
    824857
Back to Top