2017-03-22 5 views
2

Flask-Adminは、標準編集ビューでリレーションシップによって定義された子オブジェクトを表示します。たとえば、Userオブジェクトの子がAddressの場合、Userの編集ビューでは、Addressの子が適切なフィールドに表示されます。ユーザーはオブジェクトを削除したり、別のオブジェクトを追加したりすることができます。フラスコ管理クリックして子オブジェクトを編集

私は、ユーザーがクリックしたり、子オブジェクトの編集ビューを入力できるようにしたいと考えています。説明している例では、ユーザはUserオブジェクトの編集ビューからAddressオブジェクトの編集ビューに直接アクセスできます。

私が見つけた唯一のことは、inline_modelsですが、これは解決策ではありません。実装は非常に脆弱です(たとえば遠距離の関係は処理できません)。 Flask-Adminは子オブジェクトを認識しています!私はそれらを見ることができます!それらを自分の編集ビューへのリンクにするだけです...

これをどのように達成するか考えているか、例にリンクできますか?

答えて

2

他のモデルの編集ビューへのリンクを編集ビューで表示する簡単な例を以下に示します。それはあなたを助けるかもしれません。

enter image description here

私は、ユーザーを使用しました - アドレスの関係、ユーザーはアドレスおよびアドレスを持つには、多くのユーザーを持つことができます。

Fakerを使用してサンプルデータを生成しましたので、ご使用の環境にpip install fakerが必要です。

Flask-Admin form rulesを使用し、この場合はform_edit_rulesを設定しています。

私は2つのカスタムルールを作成しました:BaseRuleを継承し、

Linkを。コンストラクタには3つの値があります。エンドポイント、Flask url_forメソッドでエンドポイントと一緒に渡す属性の名前、最後にリンクとして表示されるテキスト。この例では、リンク先のビューであるため、エンドポイントは'address.edit_view'です。

MultiLinkと同様に、Linkと同様に関係で動作します。

from random import randint 
from flask import Flask, url_for 
from flask_admin.contrib import sqla 
from flask_admin import Admin 
from flask_admin.form.rules import BaseRule 
from faker import Faker 
from flask_sqlalchemy import SQLAlchemy 
from markupsafe import Markup 
from sqlalchemy import func, select 
from sqlalchemy.ext.hybrid import hybrid_property 

fake = Faker() 

# Create application 
app = Flask(__name__) 

# Create dummy secrey key so we can use sessions 
app.config['SECRET_KEY'] = '123456790' 

# Create in-memory database 
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:' 
# app.config['SQLALCHEMY_ECHO'] = True 
db = SQLAlchemy(app) 


# Flask views 
@app.route('/') 
def index(): 
    return '<a href="/admin/">Click me to get to Admin!</a>' 


class Address(db.Model): 

    __tablename__ = 'addresses' 

    id = db.Column(db.Integer, primary_key=True) 
    number = db.Column(db.String(255)) 
    street = db.Column(db.String(255)) 
    city = db.Column(db.String(255)) 
    country = db.Column(db.String(255)) 

    @hybrid_property 
    def user_count(self): 
     return len(self.users) 

    @user_count.expression 
    def user_count(cls): 
     return select([func.count(User.id)]).where(User.address_id == cls.id).label("user_count") 

    def __unicode__(self): 
     return ', '.join(filter(None, [self.number, self.street, self.city, self.country])) 


class User(db.Model): 
    __tablename__ = 'users' 
    id = db.Column(db.Integer, primary_key=True) 
    first_name = db.Column(db.String(255)) 
    last_name = db.Column(db.String(255)) 
    email = db.Column(db.String(254)) 

    address_id = db.Column(db.Integer, db.ForeignKey('addresses.id'), index=True) 
    address = db.relationship(Address, backref=db.backref('users')) 

    def __str__(self): 
     return unicode(self).encode('utf-8') 

    def __unicode__(self): 
     return '{} {}'.format(self.first_name, self.last_name) 


class Link(BaseRule): 
    def __init__(self, endpoint, attribute, text): 
     super(Link, self).__init__() 
     self.endpoint = endpoint 
     self.text = text 
     self.attribute = attribute 

    def __call__(self, form, form_opts=None, field_args={}): 

     _id = getattr(form._obj, self.attribute, None) 

     if _id: 
      return Markup('<a href="{url}">{text}</a>'.format(url=url_for(self.endpoint, id=_id), text=self.text)) 


class MultiLink(BaseRule): 
    def __init__(self, endpoint, relation, attribute): 
     super(MultiLink, self).__init__() 
     self.endpoint = endpoint 
     self.relation = relation 
     self.attribute = attribute 

    def __call__(self, form, form_opts=None, field_args={}): 

     _hrefs = [] 
     _objects = getattr(form._obj, self.relation) 
     for _obj in _objects: 
      _id = getattr(_obj, self.attribute, None) 
      _link = '<a href="{url}">Edit {text}</a>'.format(url=url_for(self.endpoint, id=_id), text=str(_obj)) 
      _hrefs.append(_link) 

     return Markup('<br>'.join(_hrefs)) 


class UserAdmin(sqla.ModelView): 
    can_view_details = True 

    form_edit_rules = (
     'first_name', 
     'last_name', 
     'email', 
     'address', 
     Link(endpoint='address.edit_view', attribute='address_id', text='Edit Address') 
    ) 


class AddressAdmin(sqla.ModelView): 
    can_view_details = True 

    column_list = ['number', 'street', 'city', 'country', 'user_count', 'users'] 

    form_edit_rules = (
     'number', 
     'street', 
     'city', 
     'country', 
     'users', 
     MultiLink(endpoint='user.edit_view', relation='users', attribute='id') 
    ) 


admin = Admin(app, template_mode="bootstrap3") 
admin.add_view(UserAdmin(User, db.session)) 
admin.add_view(AddressAdmin(Address, db.session)) 


def build_db(): 
    db.drop_all() 
    db.create_all() 

    for _ in range(0, 20): 
     _users = [] 
     for _ in range(0, randint(1, 10)): 
      _user = User(
       first_name=fake.first_name(), 
       last_name=fake.last_name(), 
       email=fake.safe_email(), 
      ) 
      _users.append(_user) 

     _address = Address(
      number=fake.random_digit_not_null(), 
      street=fake.secondary_address(), 
      city=fake.city(), 
      country=fake.country(), 
      users = _users 
     ) 

     db.session.add(_address) 

    db.session.commit() 


@app.before_first_request 
def first_request(): 
    build_db() 


if __name__ == '__main__': 
    app.run(port=5000, debug=True) 
+0

あなたが子供のコレクションに対処する方法を説明するために、これを更新することができるだろう:

ここでは、コード(チェック少しの誤差があります)ですか?たとえば、ユーザーが複数のアドレスを持つことができますか? – melchoir55

+1

@ melchoir55 - リレーションで動作する 'MultiLink'フォームルールを追加しました。 – pjcunningham

関連する問題