Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #589 -- Added FilePathField. It's available as an ORM field and…

… as a standalone field in django.core.formfields. Thanks, jay@skabber.com

git-svn-id: http://code.djangoproject.com/svn/django/trunk@846 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 5f9fe6d403dcee757778fb2c800e7866cca4b185 1 parent 9fdacc7
Adrian Holovaty authored
1  django/core/db/backends/mysql.py
@@ -143,6 +143,7 @@ def get_relations(cursor, table_name):
143 143
     'DateTimeField':     'datetime',
144 144
     'EmailField':        'varchar(75)',
145 145
     'FileField':         'varchar(100)',
  146
+    'FilePathField':     'varchar(100)',
146 147
     'FloatField':        'numeric(%(max_digits)s, %(decimal_places)s)',
147 148
     'ImageField':        'varchar(100)',
148 149
     'IntegerField':      'integer',
1  django/core/db/backends/postgresql.py
@@ -154,6 +154,7 @@ def get_relations(cursor, table_name):
154 154
     'DateTimeField':     'timestamp with time zone',
155 155
     'EmailField':        'varchar(75)',
156 156
     'FileField':         'varchar(100)',
  157
+    'FilePathField':     'varchar(100)',
157 158
     'FloatField':        'numeric(%(max_digits)s, %(decimal_places)s)',
158 159
     'ImageField':        'varchar(100)',
159 160
     'IntegerField':      'integer',
1  django/core/db/backends/sqlite3.py
@@ -154,6 +154,7 @@ def get_relations(cursor, table_name):
154 154
     'DateTimeField':                'datetime',
155 155
     'EmailField':                   'varchar(75)',
156 156
     'FileField':                    'varchar(100)',
  157
+    'FilePathField':                'varchar(100)',
157 158
     'FloatField':                   'numeric(%(max_digits)s, %(decimal_places)s)',
158 159
     'ImageField':                   'varchar(100)',
159 160
     'IntegerField':                 'integer',
23  django/core/formfields.py
@@ -707,6 +707,29 @@ def html2python(data):
707 707
 # MISCELLANEOUS    #
708 708
 ####################
709 709
 
  710
+class FilePathField(SelectField):
  711
+    "A SelectField whose choices are the files in a given directory."
  712
+    def __init__(self, field_name, path, match=None, recursive=False, is_required=False, validator_list=[]):
  713
+        import os
  714
+        if match is not None:
  715
+            import re
  716
+            match_re = re.compile(match)
  717
+        choices = []
  718
+        if recursive:
  719
+            for root, dirs, files in os.walk(path):
  720
+                for f in files:
  721
+                    if match is None or match_re.search(f):
  722
+                        choices.append((os.path.join(path, f), f))
  723
+        else:
  724
+            try:
  725
+                for f in os.listdir(path):
  726
+                    full_file = os.path.join(path, f)
  727
+                    if os.path.isfile(full_file) and (match is None or match_re.search(f)):
  728
+                        choices.append((full_file, f))
  729
+            except OSError:
  730
+                pass
  731
+        SelectField.__init__(self, field_name, choices, 1, is_required, validator_list)
  732
+
710 733
 class PhoneNumberField(TextField):
711 734
     "A convenience FormField for validating phone numbers (e.g. '630-555-1234')"
712 735
     def __init__(self, field_name, is_required=False, validator_list=[]):
8  django/core/meta/fields.py
@@ -427,6 +427,14 @@ def get_filename(self, filename):
427 427
         f = os.path.join(self.get_directory_name(), get_valid_filename(os.path.basename(filename)))
428 428
         return os.path.normpath(f)
429 429
 
  430
+class FilePathField(Field):
  431
+    def __init__(self, verbose_name=None, name=None, path='', match=None, recursive=False, **kwargs):
  432
+        self.path, self.match, self.recursive = path, match, recursive
  433
+        Field.__init__(self, verbose_name, name, **kwargs)
  434
+
  435
+    def get_manipulator_field_objs(self):
  436
+        return [curry(formfields.FilePathField, path=self.path, match=self.match, recursive=self.recursive)]
  437
+
430 438
 class FloatField(Field):
431 439
     empty_strings_allowed = False
432 440
     def __init__(self, verbose_name=None, name=None, max_digits=None, decimal_places=None, **kwargs):
34  docs/model-api.txt
@@ -272,6 +272,40 @@ Here are all available field types:
272 272
 
273 273
     .. _`strftime formatting`: http://docs.python.org/lib/module-time.html#l2h-1941
274 274
 
  275
+``FilePathField``
  276
+    A field whose choices are limited to the filenames in a certain directory
  277
+    on the filesystem. Has three special arguments, of which the first is
  278
+    required:
  279
+
  280
+        ======================  ===================================================
  281
+        Argument                Description
  282
+        ======================  ===================================================
  283
+        ``path``                Required. The absolute filesystem path to a
  284
+                                directory from which this ``FilePathField`` should
  285
+                                get its choices. Example: ``"/home/images"``.
  286
+
  287
+        ``match``               Optional. A regular expression, as a string, that
  288
+                                ``FilePathField`` will use to filter filenames.
  289
+                                Note that the regex will be applied to the
  290
+                                base filename, not the full path. Example:
  291
+                                ``"foo.*\.txt^"``, which will match a file called
  292
+                                ``foo23.txt`` but not ``bar.txt`` or ``foo23.gif``.
  293
+
  294
+        ``recursive``           Optional. Either ``True`` or ``False``. Default is
  295
+                                ``False``. Specifies whether all subdirectories of
  296
+                                ``path`` should be included.
  297
+
  298
+    Of course, these arguments can be used together.
  299
+
  300
+    The one potential gotcha is that ``match`` applies to the base filename,
  301
+    not the full path. So, this example::
  302
+
  303
+        FilePathField(path="/home/images", match="foo.*", recursive=True)
  304
+
  305
+    ...will match ``/home/images/foo.gif`` but not ``/home/images/foo/bar.gif``
  306
+    because the ``match`` applies to the base filename (``foo.gif`` and
  307
+    ``bar.gif``).
  308
+
275 309
 ``FloatField``
276 310
     A floating-point number. Has two **required** arguments:
277 311
 

0 notes on commit 5f9fe6d

Please sign in to comment.
Something went wrong with that request. Please try again.