В прошлый раз я выкладывал пример создания класса, который рекурсивно выводил список директорий. Конечно же там были ограничения.
Вот здесь новые классы, которые помогут полностью реализовать функционал старого FilePathField применительно к директориям. Не знаю, почему в django до сих пор не добавят ?
from django.forms import fields
from django.db import models
import os, re
class DirectoryPathField(models.FilePathField):
def __init__(self, *args, **kwargs):
super(DirectoryPathField, self).__init__(*args, **kwargs)
def formfield(self, **kwargs):
defaults = {
"path": self.path,
"match": self.match,
"recursive": self.recursive,
"form_class": DirectoryPathFieldWidget,
}
defaults.update(kwargs)
return super(DirectoryPathField, self).formfield(**defaults)
kwargs["widget"] = DirectoryPathFieldWidget()
return super(DirectoryPathField, self).formfield(**kwargs)
def get_internal_type(self):
return "DirectoryPathField"
class DirectoryPathFieldWidget(fields.ChoiceField):
def __init__(self, path, match=None, recursive=False, required=True,
widget=None, label=None, initial=None, help_text=None,
*args, **kwargs):
self.path, self.match, self.recursive = path, match, recursive
super(DirectoryPathFieldWidget, self).__init__(choices=(), required=required,
widget=widget, label=label, initial=initial, help_text=help_text,
*args, **kwargs)
if self.required:
self.choices = []
else:
self.choices = [("", "---------")]
if self.match is not None:
self.match_re = re.compile(self.match)
if recursive:
for root, dirs, files in sorted(os.walk(self.path)):
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).replace("\\", "/")))
else:
try:
for f in sorted(os.listdir(self.path)):
full_file = os.path.join(self.path, f)
if 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
self.widget.choices = sorted(self.choices, key=lambda title: title[1])