Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FileAdmin View Collisions #1683

Open
austinv11 opened this issue Jul 31, 2018 · 1 comment
Open

FileAdmin View Collisions #1683

austinv11 opened this issue Jul 31, 2018 · 1 comment

Comments

@austinv11
Copy link

I am currently trying to add two FileAdmin views as I would like to have one for each of two different directories. However, the FileAdmin class has a hardcoded name for its own blueprint. This means attempts to use two instances will cause clashes due to the name clash. Would it be possible to allow me to pass in arbitrary names to prevent such collisions?

@Nixellion
Copy link

Nixellion commented Oct 4, 2023

A few years late, but there is a working solution. You just need to set a different .endpoint property for the file admin class instance. Here's an example:

admin.add_view(FileAdmin(UPLOADS_DIR, '/static/', name='Static Files'))

# Place instance into a variable, don't pass it directly to add_view just yet, and you can find out that there's a ton of interesting options you can change
file_admin = FileAdmin(CONFIG_DIR, '/config/', name='Config Files')
file_admin.endpoint = "config" # This is the line you need
file_admin.editable_extensions = ['yaml']
admin.add_view(file_admin)

For available options you can refer to the BaseFileAdmin class, for example here:
https://flask-admin.readthedocs.io/en/v1.6.0/_modules/flask_admin/contrib/fileadmin/

Or when using a code editor like VSCode you can Ctrl+Click on any class to open it's source.

I'm unsure if there's any documentation for these options, and I'm unsure why there's no way to pass them as kwargs or smth. However if you'd like you can also use a dict to set them:

options = dict(endpoint="my_endpoint", rename_modal=True)
file_admin = FileAdmin(CONFIG_DIR, '/config/', name='Config Files')
for key, value in options.items():
    set_attr(file_admin, key, value)

Also useful to patch LocalFileStorage if you plan on editing text files with unicode in them:

from flask_admin.contrib.fileadmin import LocalFileStorage, BaseFileAdmin

# Patches to add support for unicode
class UnicodeFileStorage(LocalFileStorage):
    def write_file(self, path, content):
        """
            Writes `content` to the file located at `file_path`.
        """
        with open(path, 'w', encoding="utf-8") as f:
            return f.write(content)

class UnicodeFileAdmin(BaseFileAdmin):
    def __init__(self, base_path, *args, **kwargs):
        storage = UnicodeFileStorage(base_path)
        super(UnicodeFileAdmin, self).__init__(*args, storage=storage, **kwargs)


admin.add_view(UnicodeFileAdmin(UPLOADS_DIR, '/static/', name='Static Files'))

# Place instance into a variable, don't pass it directly to add_view just yet, and you can find out that there's a ton of interesting options you can change
file_admin = UnicodeFileAdmin(CONFIG_DIR, '/config/', name='Config Files')
file_admin.endpoint = "config" # This is the line you need
file_admin.editable_extensions = ['yaml']
admin.add_view(file_admin)

And I'm not sure why, but with the above code I was getting extra newlines in file. Explicitly encoding it to utf bytes and then writing as bytes solved the problem. But I have no idea why, never before I had this issue when writing files, outside of flask admin.

class UnicodeFileStorage(LocalFileStorage):
    def write_file(self, path, content):
        """
            Writes `content` to the file located at `file_path`.
        """
        content = content.encode('utf-8')
        with open(path, 'wb') as f:
            return f.write(content)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants