如何让Flask-admin面板调用模型的__init__方法?为何通过面板添加集合时图片压缩逻辑未执行?
Hey there, let's break down your Flask-admin issues step by step:
__init__ method? Flask-admin's ModelView doesn't use your model's custom __init__ method by default when creating instances via the admin panel. Instead, it directly constructs the SQLAlchemy object and sets attributes using setattr, completely bypassing your __init__ logic.
You have two reliable approaches to fix this:
Approach 1: Override create_model in your ModelView
Redefine how new instances are created in the CollectionsView class to explicitly call your model's __init__:
class CollectionsView(ModelView): form_columns = ['name', 'preview_photo'] def create_model(self, form): # Extract data from the form that matches your __init__ parameters name = form.name.data preview_photo = form.preview_photo.data # Create instance using your custom __init__ method model = Collections(name, preview_photo) # Add to database session and commit self.session.add(model) self.session.commit() return model
This forces the admin panel to use your model's constructor, including the collections_resize call.
Approach 2: Use SQLAlchemy event listeners (more robust)
Instead of relying on __init__ (which can be bypassed by ORM operations), use SQLAlchemy's before_insert and before_update events to run your resize logic. This ensures the code runs whenever a Collection is created or updated—no matter if it's from the admin panel, Python console, or other parts of your app:
from sqlalchemy import event class Collections(db.Model): __tablename__ = 'collections' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String, nullable=False) preview_photo = db.Column(db.String, nullable=False) def __init__(self, name, preview_photo): self.name = name self.preview_photo = collections_resize(preview_photo) def __repr__(self): return f'{self.name}' # Trigger resize before inserting a new Collection @event.listens_for(Collections, 'before_insert') def before_insert_collection(mapper, connection, target): target.preview_photo = collections_resize(target.preview_photo) # Optional: Trigger resize when updating the preview photo @event.listens_for(Collections, 'before_update') def before_update_collection(mapper, connection, target): # Check if the preview_photo field was modified state = db.inspect(target) if state.attrs.preview_photo.history.has_changes(): target.preview_photo = collections_resize(target.preview_photo)
This is the better long-term solution because it decouples your image resizing logic from instance creation, making it more reliable across your application.
collections_resize() running in Flask-admin, but works in the console? The core issue is how instances are created:
- When you add a Collection in the Python console, you explicitly call
Collections(name, preview_photo), which triggers your__init__method and runscollections_resize. - In the Flask-admin panel, the framework creates instances differently under the hood:
model = Collections() model.name = form.name.data model.preview_photo = form.preview_photo.data # Then adds to session and commits
It skips your custom __init__ entirely, so collections_resize never gets executed. The solutions above (either overriding create_model or using SQLAlchemy events) will resolve this.
Bonus: Handle file uploads properly
If preview_photo is a file upload field, make sure you've configured Flask-admin to handle file uploads first. Update your CollectionsView to use FileUploadField:
from flask_admin.form import FileUploadField import os class CollectionsView(ModelView): form_extra_fields = { 'preview_photo': FileUploadField( 'Preview Photo', base_path=os.path.join(app.root_path, 'static/uploads'), allowed_extensions=['jpg', 'png', 'jpeg'] ) } form_columns = ['name', 'preview_photo'] # If using Approach 1, adjust create_model to handle the uploaded file def create_model(self, form): name = form.name.data uploaded_file = form.preview_photo.data # Pass the file object/path to your resize function resized_photo_path = collections_resize(uploaded_file) model = Collections(name, resized_photo_path) self.session.add(model) self.session.commit() return model
Ensure your collections_resize function can handle the file object that Flask-admin passes (not just a filename string).
内容的提问来源于stack exchange,提问作者nnekkitt

