Một tính năng mà tôi đang cố gắng thực hiện trong bình-quản trị là khi người dùng chỉnh sửa biểu mẫu, hạn chế giá trị của Trường 2 sau khi Trường 1 có đã được thiết lập.dạng bình chứa-quản trị: Giá trị giới hạn của trường 2 tùy thuộc vào giá trị của trường 1
Hãy để tôi đưa ra một ví dụ đơn giản bằng các từ (trường hợp sử dụng thực tế phức tạp hơn). Sau đó, tôi sẽ hiển thị một ý chính đầy đủ để thực hiện ví dụ đó, trừ đi tính năng "hạn chế".
Giả sử chúng tôi có cơ sở dữ liệu theo dõi một số "công thức nấu ăn" phần mềm để báo cáo đầu ra ở nhiều định dạng khác nhau. Bảng recipe
của cơ sở dữ liệu mẫu của chúng tôi có hai công thức: "Báo cáo nghiêm trọng", "Nghệ thuật ASCII".
Để thực hiện từng công thức, chúng tôi chọn một trong một số phương pháp. Bảng method
của cơ sở dữ liệu của chúng tôi có hai phương thức: "tabulate_results", "pretty_print".
Mỗi phương pháp có tham số. Bảng methodarg
có hai tên thông số cho "tabulate_results" ("hàng", "display_total") và hai tham số cho "pretty_print" ("embellishment_character", "lines_to_jump").
Bây giờ cho mỗi công thức ("Báo cáo nghiêm túc", "Nghệ thuật ASCII"), chúng tôi cần cung cấp giá trị của các đối số của các phương thức tương ứng của chúng ("tabulate_results", "pretty_print").
Đối với mỗi bản ghi, bảng recipearg
cho phép chúng tôi chọn công thức (đó là Trường 1, ví dụ "Báo cáo nghiêm trọng") và tên đối số (đó là Trường 2). Vấn đề là tất cả các tên đối số có thể được hiển thị, trong khi chúng cần phải bị ràng buộc dựa trên giá trị của trường 1.
Cơ chế lọc/ràng buộc nào có thể thực hiện như vậy khi chúng tôi chọn "Báo cáo nghiêm trọng", chúng tôi biết sẽ sử dụng phương pháp "tabulate_results" để chỉ có các đối số "hàng" và "display_total" có sẵn?
Tôi đang nghĩ một số thuật sĩ AJAX kiểm tra trường 1 và đặt truy vấn cho giá trị trường 2, nhưng không biết cách tiến hành.
Bạn có thể thấy điều này bằng cách chơi với ý chính: nhấp vào tab Recipe Arg
. Trong hàng đầu tiên ("Báo cáo nghiêm trọng"), nếu bạn cố gắng chỉnh sửa giá trị "Methodarg" bằng cách nhấp vào nó, tất cả bốn tên đối số đều có sẵn, thay vì chỉ hai.
# full gist: please run this
from flask import Flask
from flask_admin import Admin
from flask_admin.contrib import sqla
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import Column, ForeignKey, Integer, String
from sqlalchemy.orm import relationship
# Create application
app = Flask(__name__)
# Create dummy secrey key so we can use sessions
app.config['SECRET_KEY'] = '123456790'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///a_sample_database.sqlite'
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)
# Create admin app
admin = Admin(app, name="Constrain Values", template_mode='bootstrap3')
# Flask views
@app.route('/')
def index():
return '<a href="/admin/">Click me to get to Admin!</a>'
class Method(db.Model):
__tablename__ = 'method'
mid = Column(Integer, primary_key=True)
method = Column(String(20), nullable=False, unique=True)
methodarg = relationship('MethodArg', backref='method')
recipe = relationship('Recipe', backref='method')
def __str__(self):
return self.method
class MethodArg(db.Model):
__tablename__ = 'methodarg'
maid = Column(Integer, primary_key=True)
mid = Column(ForeignKey('method.mid', ondelete='CASCADE', onupdate='CASCADE'), nullable=False)
methodarg = Column(String(20), nullable=False, unique=True)
recipearg = relationship('RecipeArg', backref='methodarg')
inline_models = (Method,)
def __str__(self):
return self.methodarg
class Recipe(db.Model):
__tablename__ = 'recipe'
rid = Column(Integer, primary_key=True)
mid = Column(ForeignKey('method.mid', ondelete='CASCADE', onupdate='CASCADE'), nullable=False)
recipe = Column(String(20), nullable=False, index=True)
recipearg = relationship('RecipeArg', backref='recipe')
inline_models = (Method,)
def __str__(self):
return self.recipe
class RecipeArg(db.Model):
__tablename__ = 'recipearg'
raid = Column(Integer, primary_key=True)
rid = Column(ForeignKey('recipe.rid', ondelete='CASCADE', onupdate='CASCADE'), nullable=False)
maid = Column(ForeignKey('methodarg.maid', ondelete='CASCADE', onupdate='CASCADE'), nullable=False)
strvalue = Column(String(80), nullable=False)
inline_models = (Recipe, MethodArg)
def __str__(self):
return self.strvalue
class MethodArgAdmin(sqla.ModelView):
column_list = ('method', 'methodarg')
column_editable_list = column_list
class RecipeAdmin(sqla.ModelView):
column_list = ('recipe', 'method')
column_editable_list = column_list
class RecipeArgAdmin(sqla.ModelView):
column_list = ('recipe', 'methodarg', 'strvalue')
column_editable_list = column_list
admin.add_view(RecipeArgAdmin(RecipeArg, db.session))
# More submenu
admin.add_view(sqla.ModelView(Method, db.session, category='See Other Tables'))
admin.add_view(MethodArgAdmin(MethodArg, db.session, category='See Other Tables'))
admin.add_view(RecipeAdmin(Recipe, db.session, category='See Other Tables'))
if __name__ == '__main__':
db.drop_all()
db.create_all()
db.session.add(Method(mid=1, method='tabulate_results'))
db.session.add(Method(mid=2, method='pretty_print'))
db.session.commit()
db.session.add(MethodArg(maid=1, mid=1, methodarg='rows'))
db.session.add(MethodArg(maid=2, mid=1, methodarg='display_total'))
db.session.add(MethodArg(maid=3, mid=2, methodarg='embellishment_character'))
db.session.add(MethodArg(maid=4, mid=2, methodarg='lines_to_jump'))
db.session.add(Recipe(rid=1, mid=1, recipe='Serious Report'))
db.session.add(Recipe(rid=2, mid=2, recipe='ASCII Art'))
db.session.commit()
db.session.add(RecipeArg(raid=1, rid=1, maid=2, strvalue='true'))
db.session.add(RecipeArg(raid=2, rid=1, maid=1, strvalue='12'))
db.session.add(RecipeArg(raid=3, rid=2, maid=4, strvalue='3'))
db.session.commit()
# Start app
app.run(debug=True)
Đối với giao diện cơ sở dữ liệu linh hoạt, tính năng này phải có. Một câu trả lời hay sẽ giúp ích cho nhiều người. Chắc chắn dữ liệu chính nó có thể cấu trúc khác nhau nhưng đó không phải là điểm. Thêm tiền thưởng. :) –