flask-admin+Flask-WTF 实现实现增删改查

news/2024/12/26 20:25:17/

背景:

flask-admin+flask-wtf在网上可以搜索到很多资料,但有价值的很少,或许是太简单,或者是很少人这么用,或者。。。,本文将作者近礼拜摸索到的一点经验分享出来,给自己做个记录。

材料:

1、Flask==3.1.0

2、flask-babel==4.0.0

3、Flask-SQLAlchemy==3.1.1

4、Flask-WTF==1.2.2

5、WTForms==3.2.1

制作:

1、安装响应库:依托于pip 安装很简单,省略)

2、应用集成:Flask-WTF 无需集成,安装库文件后直接可以使用

3、flask-admin的集成与配置:

a、项目目录如下

b、在admin 目录下创建base_admin.py文件,便于工程化配置

python">class MyAdminIndexView(AdminIndexView):# def is_accessible(self):#     return current_user.is_authenticated# def inaccessible_callback(self, name, **kwargs):#     return redirect('/admin/login')@expose("/")def homepage(self):isAuth = current_user.is_authenticatedreturn self.render("admin/index.html", isAuth=isAuth)class BaseAdmin:# admin视图初始化.def init_app(app):admin = Admin(app,  name=u"AI阅读管理系统",index_view=MyAdminIndexView(name="首页"),template_mode='bootstrap3')admin.add_view(MyOrganView(name='机构管理', endpoint="/org"))admin.add_view(MyUserView(name="用户管理", endpoint="/user", category='系统管理'))admin.add_view(MyCategoryView(name="权限管理", endpoint="/cate", category='系统管理'))admin.add_view(MyRoleView(name="角色管理", endpoint="role", category='系统管理'))admin.add_view(MyAiConfigView(db.session, name='Dify配置', category='Dify管理'))admin.add_view(MyAiFlowView(db.session, name='Dify工作流', category='Dify管理'))admin.add_view(DifyFlowTypeView(db.session, name='工作流类型', category='Dify管理'))admin.add_view(MyUrlsView(name="网站管理", endpoint="/urls", category='AI阅读'))admin.add_view(MyNewsView(name="今日要闻", endpoint="/news", category='AI阅读'))return admin

c、 基于flask-admin的视图基础的有2种,自定义视图(BaseView)和模型视图(ModelView)下面分别介绍本文作者理解的2种视图及用法。

自定义视图(BaseView)

1、自定义视图需要集成baseview基类,特点是集成这个基类后增删改查都需要自己去实现

2、务必要实现 @expose('/')的函数重构(默认进入这个视图模块的路径)

3、样例代码:

python">from flask_admin import BaseView, expose
from flask_login import current_user
from flask import redirect, url_forclass MyUrlsView(BaseView):def is_accessible(self):return current_user.is_authenticated and current_user.is_pass('SYS_URLS_ITEM')def inaccessible_callback(self, name, **kwargs):return redirect('/admin/login')@expose('/')def index(self):isAuth = current_user.is_authenticatedreturn self.render('/urlsSetList.html', isAuth=isAuth)@expose('/detail/<string:news_id>')def detail(self, news_id):return self.render('newsDetail.html', news_id=news_id)

4、样例代码中的@expose('/detail/<string:news_id>') 只是演示传参方式 ,将业务导流到了其他的API实现

5、样例代码中的is_accessible与inaccessible_callback 函数是权限控制用的,本文不做介绍。

6、如果想把自定义的页面集成到flask-admin 中,切记自己的视图文件需要集成自{% extends 'admin/master.html' %}

{% extends 'admin/master.html' %}
{% block head %}
<script type="text/javascript" src="/static/bootstrap-3.4.1/js/jquery.min.js"></script>
<style>.myactive{z-index: 2;color: #ffffff;background-color: #2fa4e7;border-color: #2fa4e7;background-image: glyphicon glyphicon-ok;}</style>
{% endblock %}
{% block body %}自己的html
{% endblock %}
{% block tail_js %}
<script src="/static/bootstrap-3.4.1/js/bootstrap.min.js"></script>
<script type="text/javascript">自己的js及控制
</script>
{% endblock %}

8、效果:

9、如果实现其他的视图需要集成flask-admin响应的模板的,可以直接从flask-admin/flask_admin/templates/bootstrap3/admin/base.html at v1.6.1 · pallets-eco/flask-admin · GitHubSimple and extensible administrative interface framework for Flask - flask-admin/flask_admin/templates/bootstrap3/admin/base.html at v1.6.1 · pallets-eco/flask-adminicon-default.png?t=O83Ahttps://github.com/pallets-eco/flask-admin/blob/v1.6.1/flask_admin/templates/bootstrap3/admin/base.html

 10、位置

11、学习它的最好方式是抄袭它的源码 

模型视图(ModelView)

1、直接上代码

a、视图代码

from flask_admin.babel import gettext
from flask_admin.contrib.sqla import ModelView
from apps.src.db.entity.dify_flow_type import DifyFlowType
from apps.src.services.vo.news_dify_flow_type_vo import NewsDifyFlowTypeVo
from flask_login import current_user
from flask_admin import expose
from flask import redirect, url_for, request, flash
from apps.src.db.entity.exts import db
from wtforms import form, fields, validators
from wtforms.widgets import TextAreaclass DivyFlowTypeForm(form.Form):status = fields.HiddenField('状态', default=0)type_name = fields.StringField('类型名称', validators=[validators.DataRequired()])type_code = fields.StringField('类型CODE', validators=[validators.DataRequired()])description = fields.TextAreaField('描述', widget=TextArea())class DifyFlowTypeView(ModelView):def is_accessible(self):return current_user.is_authenticated and current_user.is_admin == 1def inaccessible_callback(self, name, **kwargs):return redirect(url_for('admin/login'))# 列表中文翻译column_labels = {'created_at': '创建时间','updated_at': '修改时间','type_name': '类型名称','type_code': '类型CODE','description': '工作流描述'}# 重写新增@expose('/new/', methods=('GET', 'POST'))def create_view(self):bean = DifyFlowType()form = DivyFlowTypeForm(request.form, obj=bean)if self.validate_form(form):model = self.create_model(form)if model:flash(gettext('Record was successfully created.'), 'success')return redirect(self.get_save_return_url(model, is_created=True))if self.create_modal and request.args.get('modal'):template = self.create_modal_templateelse:template = self.create_templatereturn self.render(template, form=form)@expose('/edit/', methods=('GET', 'POST'))def edit_view(self):id = request.args['id']return_url = request.values.get('url') or self.get_url('.index_view')model = self.get_one(id)if model is None:flash(gettext('Record does not exist.'), 'error')return redirect(return_url)form = DivyFlowTypeForm(request.form, obj=model)if self.validate_form(form):if self.update_model(form, model):flash(gettext('Record was successfully saved.'), 'success')# save buttonreturn redirect(self.get_save_return_url(model, is_created=False))   if request.method == 'GET' or form.errors:self.on_form_prefill(form, id)if self.edit_modal and request.args.get('modal'):template = self.edit_modal_templateelse:template = self.edit_templatereturn self.render(template, form=form)# 隐藏主键column_display_pk = False# 列表排序,默认倒序column_default_sort = [('updated_at', True), ('created_at', True)]# 有此项会显示分页page_size = 10# 列表查询column_searchable_list = ['type_name']# 列表显示的字段column_list = ('updated_at', 'type_name', 'description')# 编辑页面有用form_columns = ('type_name', 'type_code', 'description')def __init__(self, session, **kwargs):# You can pass name and other parameters if you want tosuper(DifyFlowTypeView, self).__init__(DifyFlowType, session, **kwargs)

b、模型代码

from .exts import db
from flask_login import UserMixinclass DifyFlowType(db.Model, UserMixin):__tablename__ = 'dify_flow_type'id = db.Column(db.Integer, primary_key=True, autoincrement=True)created_at = db.Column(db.TIMESTAMP)updated_at = db.Column(db.TIMESTAMP)status = db.Column(db.Integer)type_name = db.Column(db.String(128))type_code = db.Column(db.Integer)description = db.Column(db.String(200))

c、关联类代码

from flask_sqlalchemy import SQLAlchemydb = SQLAlchemy()

2、直接上效果

a、列表

 

b、新增

 

c、修改

 

3、难点解说:

a、flask-admin 默认的表单中针对下拉框选择的支持感觉很弱,或许是我没接触好,找了很久只找到了主子表的这种内联表单和下拉框选择,效果很是不行,直接显示类名,受不了

    # form_ajax_refs = {#                 'ai_config': {#                     'fields': ['ai_name', 'ai_code'],#                     'placeholder': '请输入',#                     'page_size': 10,#                     'minimum_input_length': 0,#                 },'organ':{#                     'fields': ['org_name'],#                     'placeholder': '请输入',#                     'page_size': 10,#                     'minimum_input_length': 0,#                 }#             }

b、使用flask-admin 内嵌wtforms 表单的方式务必处理好 实体外键和relationship 的使用

 org_id = db.Column(db.Integer(), db.ForeignKey('organs.id'))organ = db.relationship('Organ',  backref=db.backref('ai_config', lazy='dynamic'))

c、自定义类中只能使用模型中的relationship 对应的实体映射名,否则很难处理编辑时的绑定

class AiConfigForm(form.Form):def get_countries():return Organ.query.order_by('updated_at').all()organ = QuerySelectField('机构名称', validators=[validators.DataRequired()], query_factory=get_countries, get_label='org_name') 

d、 当然可以使用自定义的方式实现,但不推荐,不太好处理。

    @expose('/new/', methods=('GET', 'POST'))def create_view(self):# if request.method == 'POST':#     form = AiFlowForm(request.form)#     if form.validate:#         form.populate_obj(AiFlow)#         aiflow = NewsAiFlowVo.to_entity(AiFlow)#         db.session.add(aiflow)#         db.session.commit()#         return redirect('/admin/aiflow/')# else:#     form = AiFlowForm(request.form)

 下篇介绍

国际化

 


http://www.ppmy.cn/news/1557929.html

相关文章

JavaWeb(一) | 基本概念(web服务器、Tomcat、HTTP、Maven)、Servlet 简介

1. 基本概念 1.1、前言 web开发&#xff1a; web&#xff0c;网页的意思&#xff0c;www.baidu.com静态 web html,css提供给所有人看的数据始终不会发生变化&#xff01; 动态 web 淘宝&#xff0c;几乎是所有的网站&#xff1b;提供给所有人看的数据始终会发生变化&#xf…

Java 类文件具有错误的版本 65.0, 应为 52.0问题解决

问题描述&#xff1a; D:\idea\xudongbase\src\test\java\com\xudongbase\doc\jotenberg\JotenbergTest.java:5:17 java: 无法访问dev.inaka.Jotenberg 错误的类文件: /C:/Users/xudongmaster/.m2/repository/dev/inaka/jotenberg/1.1.0/jotenberg-1.1.0.jar!/dev/inaka/Jot…

八股(One Day one)

最近老是看到一些面试的视频&#xff0c;对于视频内部面试所提到的八股文&#xff0c;感觉是知道是什么&#xff0c;但是要说的话&#xff0c;却又不知道该怎么说&#xff08;要不咋称之为八股文呢&#xff09;&#xff0c;所以就想到写一篇八股文总结的博客&#xff0c;以便进…

Java字符操作:Character类的使用技巧

在本文中&#xff0c;我们将探讨Java中的Character类及其使用方法。 Java Character类 当我们处理字符时&#xff0c;最常用的是基本数据类型char。例如&#xff1a; char ch a;// Unicode表示的大写希腊字母Omega char uniChar \u039A; // 字符数组 char[] charArray { a…

重温设计模式--迭代器模式

文章目录 迭代器模式&#xff08;Iterator Pattern&#xff09;概述迭代器模式的结构迭代器模式UML图C 代码示例应用场景 迭代器模式&#xff08;Iterator Pattern&#xff09;概述 定义&#xff1a; 迭代器模式是一种行为型设计模式&#xff0c;它提供了一种方法来顺序访问一个…

Windows电脑部署SD 3.5结合内网穿透随时随地生成高质量AI图像

文章目录 前言1. 本地部署ComfyUI2. 下载 Stable Diffusion3.5 模型3. 演示文生图4. 公网使用Stable Diffusion 3.5 大模型4.1 创建远程连接公网地址 5. 固定远程访问公网地址 前言 在数字化创意时代&#xff0c;AI技术的发展为我们带来了无限可能。尤其是对于那些追求高效和高…

电脑不小心删除了msvcr120.dll文件怎么办?“缺失msvcr120.dll文件”要怎么解决?

一、文件丢失与损坏的常见原因及解决办法 1. 不小心删除系统文件 常见情况&#xff1a;有时在清理电脑垃圾文件时&#xff0c;可能会不小心删除一些重要的系统文件&#xff0c;如msvcr120.dll等。解决办法&#xff1a; 恢复文件&#xff1a;如果刚删除不久&#xff0c;可以尝…

【C++ 基础】内存管理

动态内存 内存一般可分为四个区域 <一> 全局数据区(静态区) 全局变量和静态变量存放在此. 里面细分有一个常量区, 字符串常量和其他常量也存放在此. 该区域是在程序结束后由操作系统释放. <二> 代码区 这个区域存放函数体的二进制代码.也是由操作系统进行管理的…