Fixed #5894: added FilePathField to newforms. Thanks, Alex Gaynor.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7323 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
bc1f67a6de
commit
4457ba002d
1
AUTHORS
1
AUTHORS
|
@ -146,6 +146,7 @@ answer newbie questions, and generally made Django that much better:
|
||||||
Jorge Gajon <gajon@gajon.org>
|
Jorge Gajon <gajon@gajon.org>
|
||||||
gandalf@owca.info
|
gandalf@owca.info
|
||||||
Marc Garcia <marc.garcia@accopensys.com>
|
Marc Garcia <marc.garcia@accopensys.com>
|
||||||
|
Alex Gaynor <alex.gaynor@gmail.com>
|
||||||
Andy Gayton <andy-django@thecablelounge.com>
|
Andy Gayton <andy-django@thecablelounge.com>
|
||||||
Baishampayan Ghose
|
Baishampayan Ghose
|
||||||
Dimitris Glezos <dimitris@glezos.com>
|
Dimitris Glezos <dimitris@glezos.com>
|
||||||
|
|
|
@ -842,6 +842,16 @@ class FilePathField(Field):
|
||||||
self.path, self.match, self.recursive = path, match, recursive
|
self.path, self.match, self.recursive = path, match, recursive
|
||||||
kwargs['max_length'] = kwargs.get('max_length', 100)
|
kwargs['max_length'] = kwargs.get('max_length', 100)
|
||||||
Field.__init__(self, verbose_name, name, **kwargs)
|
Field.__init__(self, verbose_name, name, **kwargs)
|
||||||
|
|
||||||
|
def formfield(self, **kwargs):
|
||||||
|
defaults = {
|
||||||
|
'path': self.path,
|
||||||
|
'match': self.match,
|
||||||
|
'recursive': self.recursive,
|
||||||
|
'form_class': forms.FilePathField,
|
||||||
|
}
|
||||||
|
defaults.update(kwargs)
|
||||||
|
return super(FilePathField, self).formfield(**defaults)
|
||||||
|
|
||||||
def get_manipulator_field_objs(self):
|
def get_manipulator_field_objs(self):
|
||||||
return [curry(oldforms.FilePathField, path=self.path, match=self.match, recursive=self.recursive)]
|
return [curry(oldforms.FilePathField, path=self.path, match=self.match, recursive=self.recursive)]
|
||||||
|
|
|
@ -4,6 +4,7 @@ Field classes.
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
import datetime
|
import datetime
|
||||||
|
import os
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
# Python 2.3 fallbacks
|
# Python 2.3 fallbacks
|
||||||
|
@ -31,7 +32,7 @@ __all__ = (
|
||||||
'RegexField', 'EmailField', 'FileField', 'ImageField', 'URLField',
|
'RegexField', 'EmailField', 'FileField', 'ImageField', 'URLField',
|
||||||
'BooleanField', 'NullBooleanField', 'ChoiceField', 'MultipleChoiceField',
|
'BooleanField', 'NullBooleanField', 'ChoiceField', 'MultipleChoiceField',
|
||||||
'ComboField', 'MultiValueField', 'FloatField', 'DecimalField',
|
'ComboField', 'MultiValueField', 'FloatField', 'DecimalField',
|
||||||
'SplitDateTimeField', 'IPAddressField',
|
'SplitDateTimeField', 'IPAddressField', 'FilePathField',
|
||||||
)
|
)
|
||||||
|
|
||||||
# These values, if given to to_python(), will trigger the self.required check.
|
# These values, if given to to_python(), will trigger the self.required check.
|
||||||
|
@ -718,6 +719,33 @@ class MultiValueField(Field):
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError('Subclasses must implement this method.')
|
raise NotImplementedError('Subclasses must implement this method.')
|
||||||
|
|
||||||
|
class FilePathField(ChoiceField):
|
||||||
|
def __init__(self, path, match=None, recursive=False, required=True,
|
||||||
|
widget=Select, label=None, initial=None, help_text=None,
|
||||||
|
*args, **kwargs):
|
||||||
|
self.path, self.match, self.recursive = path, match, recursive
|
||||||
|
super(FilePathField, self).__init__(choices=(), required=required,
|
||||||
|
widget=widget, label=label, initial=initial, help_text=help_text,
|
||||||
|
*args, **kwargs)
|
||||||
|
self.choices = []
|
||||||
|
if self.match is not None:
|
||||||
|
self.match_re = re.compile(self.match)
|
||||||
|
if recursive:
|
||||||
|
for root, dirs, files in os.walk(self.path):
|
||||||
|
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)))
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
for f in 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)):
|
||||||
|
self.choices.append((full_file, f))
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
self.widget.choices = self.choices
|
||||||
|
|
||||||
class SplitDateTimeField(MultiValueField):
|
class SplitDateTimeField(MultiValueField):
|
||||||
default_error_messages = {
|
default_error_messages = {
|
||||||
'invalid_date': _(u'Enter a valid date.'),
|
'invalid_date': _(u'Enter a valid date.'),
|
||||||
|
|
|
@ -1333,13 +1333,14 @@ given length.
|
||||||
|
|
||||||
An ``UploadedFile`` object has two attributes:
|
An ``UploadedFile`` object has two attributes:
|
||||||
|
|
||||||
====================== =====================================================
|
====================== ====================================================
|
||||||
Argument Description
|
Attribute Description
|
||||||
====================== =====================================================
|
====================== ====================================================
|
||||||
``filename`` The name of the file, provided by the uploading
|
``filename`` The name of the file, provided by the uploading
|
||||||
client.
|
client.
|
||||||
|
|
||||||
``content`` The array of bytes comprising the file content.
|
``content`` The array of bytes comprising the file content.
|
||||||
====================== =====================================================
|
====================== ====================================================
|
||||||
|
|
||||||
The string representation of an ``UploadedFile`` is the same as the filename
|
The string representation of an ``UploadedFile`` is the same as the filename
|
||||||
attribute.
|
attribute.
|
||||||
|
@ -1349,6 +1350,38 @@ When you use a ``FileField`` on a form, you must also remember to
|
||||||
|
|
||||||
.. _`bind the file data to the form`: `Binding uploaded files to a form`_
|
.. _`bind the file data to the form`: `Binding uploaded files to a form`_
|
||||||
|
|
||||||
|
``FilePathField``
|
||||||
|
~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
**New in Django development version**
|
||||||
|
|
||||||
|
* Default widget: ``Select``
|
||||||
|
* Empty value: ``None``
|
||||||
|
* Normalizes to: A unicode object
|
||||||
|
* Validates that the selected choice exists in the list of choices.
|
||||||
|
* Error message keys: ``required``, ``invalid_choice``
|
||||||
|
|
||||||
|
The field allows choosing from files inside a certain directory. It takes three
|
||||||
|
extra arguments:
|
||||||
|
|
||||||
|
============== ========== ===============================================
|
||||||
|
Argument Required? Description
|
||||||
|
============== ========== ===============================================
|
||||||
|
``path`` Yes The absolute path to the directory whose
|
||||||
|
contents you want listed. This directory must
|
||||||
|
exist.
|
||||||
|
|
||||||
|
``recursive`` No If ``False`` (the default) only the direct
|
||||||
|
contents of ``path`` will be offered as choices.
|
||||||
|
If ``True``, the directory will be descended
|
||||||
|
into recursively and all descendants will be
|
||||||
|
listed as choices.
|
||||||
|
|
||||||
|
``match`` No A regular expression pattern; only files with
|
||||||
|
names matching this expression will be allowed
|
||||||
|
as choices.
|
||||||
|
============== ========== ===============================================
|
||||||
|
|
||||||
``ImageField``
|
``ImageField``
|
||||||
~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -1133,6 +1133,33 @@ u''
|
||||||
>>> f.clean(None)
|
>>> f.clean(None)
|
||||||
u''
|
u''
|
||||||
|
|
||||||
|
# FilePathField ###############################################################
|
||||||
|
|
||||||
|
>>> import os
|
||||||
|
>>> from django import newforms as forms
|
||||||
|
>>> path = forms.__file__
|
||||||
|
>>> path = os.path.dirname(path) + '/'
|
||||||
|
>>> path
|
||||||
|
'.../django/newforms/'
|
||||||
|
>>> f = forms.FilePathField(path=path)
|
||||||
|
>>> f.choices.sort()
|
||||||
|
>>> f.choices
|
||||||
|
[('.../django/newforms/__init__.py', '__init__.py'), ('.../django/newforms/__init__.pyc', '__init__.pyc'), ('.../django/newforms/fields.py', 'fields.py'), ('.../django/newforms/fields.pyc', 'fields.pyc'), ('.../django/newforms/forms.py', 'forms.py'), ('.../django/newforms/forms.pyc', 'forms.pyc'), ('.../django/newforms/models.py', 'models.py'), ('.../django/newforms/models.pyc', 'models.pyc'), ('.../django/newforms/util.py', 'util.py'), ('.../django/newforms/util.pyc', 'util.pyc'), ('.../django/newforms/widgets.py', 'widgets.py'), ('.../django/newforms/widgets.pyc', 'widgets.pyc')]
|
||||||
|
>>> f.clean('fields.py')
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValidationError: [u'Select a valid choice. That choice is not one of the available choices.']
|
||||||
|
>>> f.clean(path + 'fields.py')
|
||||||
|
u'.../django/newforms/fields.py'
|
||||||
|
>>> f = forms.FilePathField(path=path, match='^.*?\.py$')
|
||||||
|
>>> f.choices.sort()
|
||||||
|
>>> f.choices
|
||||||
|
[('.../django/newforms/__init__.py', '__init__.py'), ('.../django/newforms/fields.py', 'fields.py'), ('.../django/newforms/forms.py', 'forms.py'), ('.../django/newforms/models.py', 'models.py'), ('.../django/newforms/util.py', 'util.py'), ('.../django/newforms/widgets.py', 'widgets.py')]
|
||||||
|
>>> f = forms.FilePathField(path=path, recursive=True, match='^.*?\.py$')
|
||||||
|
>>> f.choices.sort()
|
||||||
|
>>> f.choices
|
||||||
|
[('.../django/newforms/__init__.py', '__init__.py'), ('.../django/newforms/extras/__init__.py', 'extras/__init__.py'), ('.../django/newforms/extras/widgets.py', 'extras/widgets.py'), ('.../django/newforms/fields.py', 'fields.py'), ('.../django/newforms/forms.py', 'forms.py'), ('.../django/newforms/models.py', 'models.py'), ('.../django/newforms/util.py', 'util.py'), ('.../django/newforms/widgets.py', 'widgets.py')]
|
||||||
|
|
||||||
# SplitDateTimeField ##########################################################
|
# SplitDateTimeField ##########################################################
|
||||||
|
|
||||||
>>> f = SplitDateTimeField()
|
>>> f = SplitDateTimeField()
|
||||||
|
|
Loading…
Reference in New Issue