Как иметь внешний ключ 'Folder', отсортированный по папкам и подпапкам
У меня есть модели для скриптов и папок, причем скрипты находятся внутри папок. При регистрации нового скрипта (или изменении существующего) на странице Django Admin, папки не представлены как папки и подпапки, а скорее все одновременно в виде списка, без чего-либо, чтобы отличить, какая из них является родительской или дочерней для другой в списке. Я хочу, чтобы они были четко упорядочены, с вложенными папками под их родителем (Или, по крайней мере, отображать путь от корневой папки вместо простого имени папки, чтобы можно было определить, где они находятся, если то, что я хочу, невозможно).
Надеюсь, я понятно объяснил, но чтобы попытаться объяснить по-другому, возьмем ChoiceField со следующими вариантами выбора :
FOLDER_CHOICE= [
('Folder1', (
('folder1-1', 'Folder1-1'),
('folder1-2', 'Folder1-2'),
)
),
('Folder2', (
('folder2-1', 'Folder2-1'),
('folder2-2', 'Folder2-2'),
)
)
,...
]
Код класса models.py :
import importlib.util
import os
import shutil
import types
from django.db import models
from django.urls import reverse
from django.utils.html import format_html
class Folder(models.Model):
folder_name = models.CharField(max_length=200, unique=True)
parent_folder = models.FilePathField(path=r'media/', allow_files=False, allow_folders=True, recursive=True)
def __init__(self, *args, **kwargs):
super(Folder, self).__init__(*args, **kwargs)
self.initial_folder_name = self.folder_name
self.initial_parent_folder = self.parent_folder
def __str__(self):
return self.folder_name
def save(self, *args, **kwargs):
on_creation = self.pk is None
if on_creation:
os.mkdir(os.path.join(self.parent_folder, self.folder_name))
else:
os.rename(os.path.join(self.parent_folder, self.initial_folder_name), os.path.join(self.parent_folder, self.folder_name))
super(Folder, self).save(*args, **kwargs)
def delete(self, *args, **kwargs):
shutil.rmtree(os.path.join(self.parent_folder, self.initial_folder_name), ignore_errors=True)
super(Folder, self).delete(*args, **kwargs)
def script_upload_path(instance, filename):
return f'{instance.folder.parent_folder}/{instance.folder.folder_name}/{filename}'
class Script(models.Model):
script_name = models.CharField(max_length=200, unique=True)
folder = models.ForeignKey(Folder, on_delete=models.CASCADE)
file = models.FileField(upload_to=script_upload_path)
def __init__(self, *args, **kwargs):
super(Script, self).__init__(*args, **kwargs)
if self.pk is not None:
self.initial_filepath = self.filepath()
def __str__(self):
return self.script_name
def save(self, *args, **kwargs):
on_creation = self.pk is None
if not on_creation:
initial_folder_path = self.initial_filepath
new_folder_path = self.filepath()
shutil.move(initial_folder_path, new_folder_path)
self.file = new_folder_path
super(Script, self).save(*args, **kwargs)
def download_link(self):
return format_html('<a href="{}">Download File</a>', reverse('scripts:download_script', args=(self.pk,)))
def get_script(self):
module_path = os.path.join(f'{self.file}')
loader = importlib.machinery.SourceFileLoader('script', module_path)
mod = types.ModuleType(loader.name)
loader.exec_module(mod)
return mod
def filename(self):
return os.path.basename(self.file.name)
def filepath(self):
return os.path.join(self.folder.parent_folder, self.folder.folder_name, self.filename())
И код моего класса admin.py, если необходимо :
from django.contrib import admin
from .models import Script, Folder
class ScriptAdmin(admin.ModelAdmin):
fieldsets = [
(None, {'fields': ['script_name']}),
('Folder', {'fields': ['folder']}),
('Script', {'fields': ['file']}),
]
list_display = ('script_name', 'folder', 'download_link')
class FolderAdmin(admin.ModelAdmin):
fieldsets = [
(None, {'fields': ['folder_name']}),
('Parent Folder', {'fields': ['parent_folder']}),
]
admin.site.register(Script, ScriptAdmin)
admin.site.register(Folder, FolderAdmin)
Надеюсь, мой вопрос был понятен, заранее спасибо за ответы!