简体   繁体   中英

flask-admin imposes required attribute on relationship

flask-admin marks db.relationship fields of model views as required, so there is no way to add a record if the table to which relationship goes is empty.

Example:

class Type(db.Model):
    id           = db.Column(db.Integer, primary_key=True)
    name         = db.Column(db.String(50), nullable=False, unique=True, index=True)
    area_id      = db.Column(db.Integer, db.ForeignKey("area.id", onupdate='CASCADE', ondelete='CASCADE'), nullable=False, index=True)
    description  = db.Column(db.Text)

class Area(db.Model):
    id           = db.Column(db.Integer, primary_key=True)
    name         = db.Column(db.String(50), nullable=False, unique=True, index=True)
    description  = db.Column(db.Text)
    types = db.relationship('Type', backref='Area', lazy='dynamic', cascade='all, delete-orphan')

types field is required during creation of area record through flask-admin, but If type table is empty, there is no way to add any information to the database. flask-admin wouldn't allow to add anything to Area table because of backref to Type table which makes the field required, but there is nothing in Type table yet. flask-admin wouldn't allow to add anything to Area table as well, because the field types is required on the page.

I couldn't find anything on the subject. There are some topics discussing workarounds for many-to-many relationships, but this is the simplest one-to-many relationship which to my understanding should just work out of the box.

I figured out that if I add Type to inline_models under Area model then I will see a button "Add Types" on create Area page, but if the inline_model itself has a relationship then that wouldn't help either, because of the same reason.

class ModelViewArea(ModelView):
    inline_models = ( models.Type, )

admin.add_view(ModelViewProductArea (models.Area, db.session, name="Area",  category='Product'))
admin.add_view(ModelViewProductType (models.Type, db.session, name="Type",  category='Product'))

It turned out that if a foreign key associated with the relationship has nullable=False then flask-admin marks the field as required in flask-wtf . Once I removed nullable=False from attributes of the foreign key of Type class, flask-admin stopped showing the field as required in both Type model view and Area model view.

However, as I removed nullable=False there was no more reason for ondelete="CASCADE" and cascade behavior on relationship. Default cascade suits better. The final code looks like:

class Type(db.Model):
    id           = db.Column(db.Integer, primary_key=True)
    name         = db.Column(db.String(50), nullable=False, unique=True, index=True)
    area_id      = db.Column(db.Integer, db.ForeignKey("area.id", onupdate='CASCADE', ondelete='SET NULL'), index=True)
    description  = db.Column(db.Text)

class Area(db.Model):
    id           = db.Column(db.Integer, primary_key=True)
    name         = db.Column(db.String(50), nullable=False, unique=True, index=True)
    description  = db.Column(db.Text)
    types = db.relationship('Type', backref='Area', lazy='dynamic')

This problem has been fixed in git master. Flask-Admin 1.0.7 is a few months old already and the git version has accumulated quite a few changes since then.

Sergey's answer of removing nullable=False from the foreign key changes the semantics and is therefore a workaround. With Flask-Admin from master, the nullable=False can be left in.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM