Как иметь внешний ключ '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)

Надеюсь, мой вопрос был понятен, заранее спасибо за ответы!

Вернуться на верх