Flask 会员列表展示
感谢编程浪子师傅的源码信息分享
web/controllers/member/Member.py
# -*- coding: utf-8 -*-
from flask import Blueprint,request,redirect,jsonify
from common.libs.Helper import ops_render,iPagination,getCurrentDate,getDictFilterField,selectFilterObj
from common.libs.UrlManager import UrlManager
from common.models.member.Member import Member
from common.models.member.MemberComments import MemberComments
from common.models.food.Food import Food
from common.models.pay.PayOrder import PayOrder
from application import app,db
route_member = Blueprint( 'member_page',__name__ )@route_member.route( "/index" )
def index():resp_data = {}req = request.valuespage = int( req['p'] ) if ( 'p' in req and req['p'] ) else 1query = Member.queryif 'mix_kw' in req:query = query.filter( Member.nickname.ilike( "%{0}%".format( req['mix_kw'] ) ) )if 'status' in req and int( req['status'] ) > -1 :query = query.filter( Member.status == int( req['status'] ) )page_params = {'total':query.count(),'page_size': app.config['PAGE_SIZE'],'page':page,'display':app.config['PAGE_DISPLAY'],'url': request.full_path.replace("&p={}".format(page),"")}pages = iPagination( page_params )offset = ( page - 1 ) * app.config['PAGE_SIZE']list = query.order_by( Member.id.desc() ).offset( offset ).limit( app.config['PAGE_SIZE'] ).all()resp_data['list'] = listresp_data['pages'] = pagesresp_data['search_con'] = reqresp_data['status_mapping'] = app.config['STATUS_MAPPING']resp_data['current'] = 'index'return ops_render( "member/index.html",resp_data )@route_member.route( "/info" )
def info():resp_data = {}req = request.argsid = int( req.get( "id",0 ) )reback_url = UrlManager.buildUrl( "/member/index" )if id < 1:return redirect( reback_url )info = Member.query.filter_by( id =id ).first()if not info:return redirect( reback_url )pay_order_list = PayOrder.query.filter_by( member_id = id ).filter( PayOrder.status.in_( [-8,1] ) )\.order_by( PayOrder.id.desc() ).all()comment_list = MemberComments.query.filter_by( member_id = id ).order_by( MemberComments.id.desc() ).all()resp_data['info'] = inforesp_data['pay_order_list'] = pay_order_listresp_data['comment_list'] = comment_listresp_data['current'] = 'index'return ops_render( "member/info.html",resp_data )@route_member.route( "/set",methods = [ "GET","POST" ] )
def set():if request.method == "GET":resp_data = {}req = request.argsid = int( req.get( "id",0 ) )reback_url = UrlManager.buildUrl("/member/index")if id < 1:return redirect(reback_url)info = Member.query.filter_by(id=id).first()if not info:return redirect(reback_url)if info.status != 1:return redirect(reback_url)resp_data['info'] = inforesp_data['current'] = 'index'return ops_render( "member/set.html",resp_data )resp = { 'code':200,'msg':'操作成功~~','data':{} }req = request.valuesid = req['id'] if 'id' in req else 0nickname = req['nickname'] if 'nickname' in req else ''if nickname is None or len( nickname ) < 1:resp['code'] = -1resp['msg'] = "请输入符合规范的姓名~~"return jsonify( resp )member_info = Member.query.filter_by(id=id).first()if not member_info:resp['code'] = -1resp['msg'] = "指定会员不存在~~"return jsonify(resp)member_info.nickname = nicknamemember_info.updated_time = getCurrentDate()db.session.add( member_info )db.session.commit()return jsonify( resp )@route_member.route( "/comment" )
def comment():resp_data = {}req = request.argspage = int(req['p']) if ('p' in req and req['p']) else 1query = MemberComments.querypage_params = {'total': query.count(),'page_size': app.config['PAGE_SIZE'],'page': page,'display': app.config['PAGE_DISPLAY'],'url': request.full_path.replace("&p={}".format(page), "")}pages = iPagination(page_params)offset = (page - 1) * app.config['PAGE_SIZE']comment_list = query.order_by(MemberComments.id.desc()).offset( offset ).limit( app.config['PAGE_SIZE'] ).all()data_list = []if comment_list:member_map = getDictFilterField( Member,Member.id,"id", selectFilterObj( comment_list ,"member_id" ) )food_ids = []for item in comment_list:tmp_food_ids = (item.food_ids[1:-1]).split("_")tmp_food_ids = {}.fromkeys( tmp_food_ids ).keys()food_ids = food_ids + list( tmp_food_ids )food_map = getDictFilterField( Food,Food.id,"id", food_ids )for item in comment_list:tmp_member_info = member_map[ item.member_id ]tmp_foods = []tmp_food_ids = (item.food_ids[1:-1]).split("_")for tmp_food_id in tmp_food_ids:tmp_food_info = food_map[ int( tmp_food_id ) ]tmp_foods.append({'name': tmp_food_info.name,})tmp_data = {"content":item.content,"score":item.score,"member_info":tmp_member_info,"foods":tmp_foods}data_list.append( tmp_data )resp_data['list'] = data_listresp_data['pages'] = pagesresp_data['current'] = 'comment'return ops_render( "member/comment.html",resp_data )@route_member.route("/ops",methods=["POST"])
def ops():resp = { 'code':200,'msg':'操作成功~~','data':{} }req = request.valuesid = req['id'] if 'id' in req else 0act = req['act'] if 'act' in req else ''if not id :resp['code'] = -1resp['msg'] = "请选择要操作的账号~~"return jsonify(resp)if act not in [ 'remove','recover' ]:resp['code'] = -1resp['msg'] = "操作有误,请重试~~"return jsonify(resp)member_info = Member.query.filter_by( id = id ).first()if not member_info:resp['code'] = -1resp['msg'] = "指定会员不存在~~"return jsonify(resp)if act == "remove":member_info.status = 0elif act == "recover":member_info.status = 1member_info.updated_time = getCurrentDate()db.session.add(member_info)db.session.commit()return jsonify( resp )
@route_member.route("/index")
代码段是一个Flask路由函数index()
,它接收一个GET请求并返回一个JSON响应。下面是对代码的详细解析:
- 首先,创建一个空字典
resp_data
来存储响应数据。 - 通过
request.values
获取请求参数,并将其赋值给变量req
。 - 使用条件语句判断是否存在参数
p
,如果存在且不为空,则将其转换为整数并赋值给变量page
,否则将page
设置为1。 - 创建一个
Member
查询对象query
。 - 如果请求参数中存在
mix_kw
,则使用filter()
方法对query
进行过滤,筛选出nickname
字段中包含req['mix_kw']
的记录。
请注意,代码中的Member
是一个模型类,可能是通过SQLAlchemy定义的数据库表的映射类。
这段代码是一个条件判断语句,用于筛选查询结果。如果请求参数中包含名为’status’的键,并且该键对应的值大于-1,则会执行以下操作:
- 将查询对象query的筛选条件设置为Member.status等于请求参数中’status’对应的整数值。
- 创建一个名为page_params的字典,包含以下键值对:
- ‘total’:查询结果的总数。
- ‘page_size’:每页显示的数量。
- ‘page’:当前页数。
- ‘display’:每页显示的页码数量。
- ‘url’:请求的完整路径,将其中的"&p={}".format(page)替换为空字符串。
根据传入的参数进行分页查询,并返回查询结果和分页信息
offset 偏移量
这段代码的功能是根据传入的page_params
参数进行分页查询,查询结果存储在list
变量中。然后将查询结果、分页信息、请求参数、状态映射和当前页面信息存储在resp_data
字典中。最后通过ops_render
函数将查询结果和其他信息渲染到指定的HTML模板中。
问题1: order_by 是什么函数有什么作用?
在给定的代码中,order_by
是SQLAlchemy中的一个函数,用于对查询结果进行排序。它的作用是按照指定的字段对查询结果进行排序,可以按照升序或降序排列。
具体来说,order_by
函数接受一个或多个参数,每个参数表示一个字段,用于指定排序的依据。可以使用点操作符来指定字段,例如Member.id
表示按照Member
表中的id
字段进行排序。
在给定的代码中,query.order_by(Member.id.desc())
表示按照Member
表中的id
字段进行降序排序。
.desc()
表示降序排序, abbr.降序排列
descend 美 /dɪˈsend/ v. 下来,下降;
如果要进行升序排序,可以使用.asc()
。
ascending 美 /əˈsendɪŋ/ adj. 上升的,增长的;升(序)的
sequence 美 /ˈsiːkwəns/ n. 顺序,次序;连续事件(或动作、事物);
总结一下,order_by
函数用于对查询结果进行排序,可以按照一个或多个字段进行排序,可以指定升序或降序。
问题2: .offset 有什么作用
在这段代码中,.offset
用于指定查询结果的偏移量。偏移量表示从查询结果中跳过的行数。在这个例子中,.offset(offset)
表示从查询结果中跳过offset
行。这样可以用来实现分页功能,通过指定不同的偏移量来获取不同页的数据。
例如,如果offset
为0,则表示从查询结果的第一行开始获取数据;如果offset
为10,则表示从查询结果的第11行开始获取数据。
需要注意的是,.offset
方法必须与.limit
方法一起使用,以限制查询结果的数量。.limit
用于指定要获取的行数。
总结起来,.offset
方法用于指定查询结果的偏移量,以实现分页功能。
问题3: .limit有什么作用?
.limit()函数用于限制查询结果的数量。在给定的查询中,它指定了从结果集中返回的记录数的上限。在这段代码中,.limit(app.config[‘PAGE_SIZE’])将查询结果限制为app.config[‘PAGE_SIZE’]指定的页面大小。这通常用于分页查询,以确保每个页面只返回指定数量的记录。
问题4: .all有什么作用?
根据提供的引用内容,代码段.all()
的作用是将查询结果以列表的形式返回。在这个例子中,query.order_by( Member.id.desc() ).offset( offset ).limit( app.config['PAGE_SIZE'] )
是一个查询语句,.all()
将返回满足查询条件的所有结果,并将其存储在名为list
的变量中。
问题5: resp_data是一个对象吗?
在这段代码中,resp_data
是一个字典对象。字典是Python中的一种数据结构,它由键值对组成,可以用来存储和访问数据。在这段代码中,resp_data
被初始化为空字典{}
,然后通过resp_data['search_con'] = req
将键为'search_con'
的值设置为req
。这样,resp_data
就成为了一个包含一个键值对的字典对象。
字典对象可以通过键来访问对应的值。例如,可以使用resp_data['search_con']
来获取'search_con'
键对应的值。在这段代码中,resp_data['search_con']
的值将被传递给ops_render()
函数,用于渲染模板文件"member/index.html"。
总结起来,resp_data
是一个字典对象,用于存储和传递数据。
问题6: req是一个什么样的值?请详细解析
req
是request.values
的值。request.values
是一个字典,包含了请求中的所有参数和值。在这段代码中,req
将包含来自请求的所有参数和值。
这段代码的作用是在resp_data
字典中添加一个键值对,键为search_con
,值为req
。然后将resp_data
传递给ops_render
函数,该函数将渲染member/index.html
模板并返回结果。
请注意,request.values
是一个字典,它包含了请求中的所有参数和值。因此,req
的值将取决于请求中的参数和值。
@route_member.route("/info")
根据提供的引用内容,代码段中的resp_data是一个字典对象,而不是一个普通的对象。在代码中,resp_data被用来存储一些数据,包括info、pay_order_list和comment_list等。这些数据将在返回的HTML页面中使用。
字典对象是一种可变的数据类型,它可以存储键值对,并且可以通过键来访问对应的值。
以下是代码段的解释和示例:
@route_member.route( "/info" )
def info():resp_data = {} # 创建一个空的字典对象req = request.argsid = int( req.get( "id",0 ) )reback_url = UrlManager.buildUrl( "/member/index" )if id < 1:return redirect( reback_url )info = Member.query.filter_by( id =id ).first()if not info:return redirect( reback_url )pay_order_list = PayOrder.query.filter_by( member_id = id ).filter( PayOrder.status.in_( [-8,1] ) )\.order_by( PayOrder.id.desc() ).all()comment_list = MemberComments.query.filter_by( member_id = id ).order_by( MemberComments.id.desc() ).all()resp_data['info'] = info # 将info存储在resp_data字典中的'info'键下resp_data['pay_order_list'] = pay_order_list # 将pay_order_list存储在resp_data字典中的'pay_order_list'键下resp_data['comment_list'] = comment_list # 将comment_list存储在resp_data字典中的'comment_list'键下resp_data['current'] = 'index' # 将'index'存储在resp_data字典中的'current'键下return ops_render( "member/info.html",resp_data ) # 返回HTML页面,并将resp_data作为参数传递给ops_render函数
代码段是一个Flask路由函数,用于处理/member/info的请求。函数名为info(),接受GET请求。
在函数内部,首先定义了一个空字典resp_data用于存储返回的数据。
然后通过request.args获取请求参数,并将id参数转换为整型。
接下来,根据id的值进行条件判断,
如果id小于1,则重定向到/reback_url指定的页面。
如果id大于等于1,则通过Member.query.filter_by(id=id).first()查询数据库中id等于给定id的会员信息,并将结果存储在info变量中。
如果查询结果为空,则同样重定向到/reback_url指定的页面。
接下来,通过PayOrder.query.filter_by(member_id=id).filter(PayOrder.status.in_([-8,1])).order_by(PayOrder.id.desc()).all()查询数据库中member_id等于给定id且status为-8或1的支付订单信息,并将结果存储在pay_order_list变量中。
再通过MemberComments.query.filter_by(member_id=id).order_by(MemberComments.id.desc()).all()查询数据库中member_id等于给定id的会员评论信息,并将结果存储在comment_list变量中。
最后,将info、pay_order_list、comment_list以及其他一些数据存储在resp_data字典中,并返回渲染后的HTML页面。
@route_member.route("/set", methods = ["GET","POST"])
在给定的代码中,@route_member.route( "/set",methods = [ "GET","POST" ] )
是一个装饰器,用于定义一个名为set
的路由函数。该函数可以通过GET和POST方法进行访问。
在GET请求中,函数首先获取请求参数中的id
值,并构建一个重定向URL。然后,它通过查询数据库获取与给定id
匹配的会员信息。
如果找不到会员信息或会员状态不为1,则会重定向到之前构建的URL。
最后,函数将会员信息和当前页面设置为响应数据,并渲染member/set.html
模板。
在POST请求中,函数首先获取请求参数中的id
和nickname
值。
如果nickname
为空或长度小于1,则返回一个错误的JSON响应。否则,函数通过查询数据库获取与给定id
匹配的会员信息。
最后,函数返回一个成功的JSON响应。
主要是对会员信息进行更新的操作。下面是对代码的详细解析:
- 首先,判断
member_info
是否存在,如果不存在,则将resp['code']
设置为-1,resp['msg']
设置为"指定会员不存在~~"。 - 如果
member_info
存在,则将member_info
的nickname
属性更新为nickname
变量的值。 - 将
member_info
的updated_time
属性更新为当前时间。 - 将
member_info
添加到数据库会话中。 - 提交数据库会话,即将更新的数据保存到数据库中。
- 返回更新后的
resp
作为响应。
这段代码的作用是更新会员信息,并返回更新后的响应。
数据库
DROP TABLE IF EXISTS `pay_order`;CREATE TABLE `pay_order` (`id` int(11) unsigned NOT NULL AUTO_INCREMENT,`order_sn` varchar(40) NOT NULL DEFAULT '' COMMENT '随机订单号',`member_id` bigint(11) NOT NULL DEFAULT '0' COMMENT '会员id',`total_price` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '订单应付金额',`yun_price` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '运费金额',`pay_price` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '订单实付金额',`pay_sn` varchar(128) NOT NULL DEFAULT '' COMMENT '第三方流水号',`prepay_id` varchar(128) NOT NULL DEFAULT '' COMMENT '第三方预付id',`note` text NOT NULL COMMENT '备注信息',`status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '1:支付完成 0 无效 -1 申请退款 -2 退款中 -9 退款成功 -8 待支付 -7 完成支付待确认',`express_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '快递状态,-8 待支付 -7 已付款待发货 1:确认收货 0:失败',`express_address_id` int(11) NOT NULL DEFAULT '0' COMMENT '快递地址id',`express_info` varchar(1000) NOT NULL DEFAULT '' COMMENT '快递信息',`comment_status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '评论状态',`pay_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '付款到账时间',`updated_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '最近一次更新时间',`created_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '插入时间',PRIMARY KEY (`id`),UNIQUE KEY `idx_order_sn` (`order_sn`),KEY `idx_member_id_status` (`member_id`,`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='在线购买订单表';DROP TABLE IF EXISTS `member_comments`;CREATE TABLE `member_comments` (`id` int(11) unsigned NOT NULL AUTO_INCREMENT,`member_id` int(11) NOT NULL DEFAULT '0' COMMENT '会员id',`food_ids` varchar(200) NOT NULL DEFAULT '' COMMENT '商品ids',`pay_order_id` int(11) NOT NULL DEFAULT '0' COMMENT '订单id',`score` tinyint(4) NOT NULL DEFAULT '0' COMMENT '评分',`content` varchar(200) NOT NULL DEFAULT '' COMMENT '评论内容',`created_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '插入时间',PRIMARY KEY (`id`),KEY `idx_member_id` (`member_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='会员评论表';DROP TABLE IF EXISTS `food`;CREATE TABLE `food` (`id` int(11) unsigned NOT NULL AUTO_INCREMENT,`cat_id` int(11) NOT NULL DEFAULT '0' COMMENT '分类id',`name` varchar(100) NOT NULL DEFAULT '' COMMENT '书籍名称',`price` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '售卖金额',`main_image` varchar(100) NOT NULL DEFAULT '' COMMENT '主图',`summary` varchar(10000) NOT NULL DEFAULT '' COMMENT '描述',`stock` int(11) NOT NULL DEFAULT '0' COMMENT '库存量',`tags` varchar(200) NOT NULL DEFAULT '' COMMENT 'tag关键字,以","连接',`status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '状态 1:有效 0:无效',`month_count` int(11) NOT NULL DEFAULT '0' COMMENT '月销售数量',`total_count` int(11) NOT NULL DEFAULT '0' COMMENT '总销售量',`view_count` int(11) NOT NULL DEFAULT '0' COMMENT '总浏览次数',`comment_count` int(11) NOT NULL DEFAULT '0' COMMENT '总评论量',`updated_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '最后更新时间',`created_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '最后插入时间',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='食品表';
flask-sqlacodegen 'mysql://root:root@127.0.0.1/food_db' --tables pay_order --outfile "common/models/pay/PayOrder.py" --flaskflask-sqlacodegen 'mysql://root:root@127.0.0.1/food_db' --tables member_comments --outfile "common/models/member/MemberComments.py" --flaskflask-sqlacodegen 'mysql://root:root@127.0.0.1/food_db' --tables food --outfile "common/models/food/Food.py" --flask
common/models/member/Member.py 数据库
# coding: utf-8
from application import db, appclass Member(db.Model):__tablename__ = 'member'id = db.Column(db.Integer, primary_key=True)nickname = db.Column(db.String(100), nullable=False, server_default=db.FetchedValue(), info='会员名')mobile = db.Column(db.String(11), nullable=False, server_default=db.FetchedValue(), info='会员手机号码')sex = db.Column(db.Integer, nullable=False, server_default=db.FetchedValue(), info='性别 1:男 2:女')avatar = db.Column(db.String(200), nullable=False, server_default=db.FetchedValue(), info='会员头像')salt = db.Column(db.String(32), nullable=False, server_default=db.FetchedValue(), info='随机salt')reg_ip = db.Column(db.String(100), nullable=False, server_default=db.FetchedValue(), info='注册ip')status = db.Column(db.Integer, nullable=False, server_default=db.FetchedValue(), info='状态 1:有效 0:无效')updated_time = db.Column(db.DateTime, nullable=False, server_default=db.FetchedValue(), info='最后一次更新时间')created_time = db.Column(db.DateTime, nullable=False, server_default=db.FetchedValue(), info='插入时间')@propertydef status_desc(self):return app.config['STATUS_MAPPING'][str(self.status)]@propertydef sex_desc(self):sex_mapping = {"0":"未知","1":"男","2":"女"}return sex_mapping[str(self.sex)]#status 统一返回sex表格的字段, 虚拟的好处是 直接可以在index.html中直接使用。 虚拟字段不可以查询
该段代码是一个Python类中的两个属性装饰器(@property)方法。这些装饰器方法允许我们在访问类的属性时执行一些自定义的逻辑。
-
@property装饰器用于定义一个getter方法,它允许我们像访问普通属性一样访问该方法。在这段代码中,@property装饰器定义了两个getter方法:status_desc和sex_desc。
-
status_desc方法返回了一个名为app.config[‘STATUS_MAPPING’]的字典中与self.status对应的值。这个字典是一个配置文件中的映射,它将状态码映射到相应的描述。
-
sex_desc方法返回了一个名为sex_mapping的字典中与self.sex对应的值。这个字典将性别码映射到相应的描述。
这两个属性装饰器方法使得我们可以通过访问类的实例属性来获取相应的描述信息,而不需要直接访问底层的状态码或性别码。
如下在index.html中过渡使用
虚拟字段的好处: 可以直接使用的
虚拟字段是不能进入字段查询的, 它只能作为该数据类里的某一种属性
搜索功能是在member/index.js里通过对warp_search 这个form标签及里面的search这个button按钮来设定的click点击事件后并submit提交到py后端flask框架里的member.py后进行判断处理。
py后端收到mix_kw status相关信息,进行筛选后返回并爬着、时刻准备再次进行筛选行为。
templates/member/index.html
{% extends "common/layout_main.html" %}
{% block content %}
{% include "common/tab_member.html" %}
<div class="row"><div class="col-lg-12"><form class="form-inline wrap_search"><div class="row m-t p-w-m"><div class="form-group"><select name="status" class="form-control inline"><option value="-1">请选择状态</option>{# <option value="1"> 正常 </option>#}
{# <option value="0">已删除</option>#}{% for tmp_key in status_mapping %}<option value="{{ tmp_key }}" {% if tmp_key == search_con['status'] %} selected {% endif %}>{{ status_mapping[ tmp_key ] }}</option>{% endfor %}</select></div><div class="form-group"><div class="input-group"><input type="text" name="mix_kw" placeholder="请输入关键字" class="form-control" value="{{ search_con['mix_kw'] }}"><input type="hidden" name="p" value="{{ search_con['p'] }}"><span class="input-group-btn"><button type="button" class="btn btn-primary search"><i class="fa fa-search"></i>搜索</button></span></div></div></div><hr></form><table class="table table-bordered m-t"><thead><tr><th>头像</th><th>姓名</th><th>性别</th><th>状态</th><th>操作</th></tr></thead><tbody>{% if list %}{% for item in list %}<tr><td><img alt="image" class="img-circle" src="{{ item.avatar }}" style="width: 40px;height: 40px;"></td><td>{{ item.nickname }}</td><td>{{ item.sex_desc }}</td><td>{{ item.status_desc }}</td><td><a href="{{ buildUrl('/member/info') }}?id={{ item.id }}"><i class="fa fa-eye fa-lg"></i></a>{% if item.status == 1 %}<a class="m-l" href="{{ buildUrl('/member/set') }}?id={{ item.id }}"><i class="fa fa-edit fa-lg"></i></a><a class="m-l remove" href="javascript:void(0);" data="{{ item.id }}"><i class="fa fa-trash fa-lg"></i></a>{% else %}<a class="m-l recover" href="javascript:void(0);" data="{{ item.id }}"><i class="fa fa-rotate-left fa-lg"></i></a>{% endif %}</td></tr>{% endfor %}{% else %}<tr><td colspan="5">暂无数据</td></tr>{% endif %}</tbody></table><!--分页代码已被封装到统一模板文件中-->{% include 'common/pagenation.html' %}</div>
</div>
{% endblock %}
{% block js %}
<script src="{{ buildStaticUrl('/js/member/index.js') }}"></script>
{% endblock %}
在这个模板中,定义了一个表单,包含一个下拉选择框和一个搜索按钮。
下拉选择框中的选项是通过循环生成的,循环遍历了一个名为status_mapping
的字典,并将字典中的键值对生成为下拉选项。在生成选项时,还判断了当前选项是否与搜索条件中的状态匹配,如果匹配则设置为选中状态。
search_con['status'] 是已经在Member.py中定义的req即request.values,被包装在resp_data里后,使用ops_render渲染并返回resp_data。
问题1: search_con['p'] 是怎样的一个值?
search_con[p]
是一个在HTML中的隐藏输入字段,它的值是search_con
字典中键为p
的值。在这个例子中,search_con
是一个字典,它包含了从请求中获取的数据。search_con[p]
表示获取search_con
字典中键为p
的值。
问题2: 那p又是一个怎样的值呢?
在Member.py中可以发现对p的值的后续获取和条件判断
page = int( req['p'] ) if ( 'p' in req and req['p'] ) else 1
根据提供的引用内容,代码中的p
是一个隐藏的输入字段,它的值来自于search_con['p']
。在这段代码中,p
可能是用来表示页码的参数。根据代码中的注释,它可能用于搜索功能中的分页功能。
<input type="hidden" name="p" value="{{ search_con['p'] }}"> 总结来说,该段代码用于传输分页的数据信息,p表示page
<a href="{{ buildUrl('/member/info') }}?id={{ item.id }}">
<i class="fa fa-eye fa-lg"></i>
内容中还包含了一个HTML标签,其中包含了一个链接和一个图标。根据链接的格式,这可能是一个用于查看成员信息的URL链接。图标可能是一个用于显示成员信息的眼睛图标。
点击该图标后进入info方法对用户信息进行展示查看
问题3: <tr><td colspan="5">暂无数据</td></tr> 是什么意思?
<tr><td colspan=“5”>暂无数据</td></tr>是HTML中的表格标签,用于在表格中创建一行并设置该行的单元格数目。其中,colspan属性用于指定单元格跨越的列数。
以下是一个示例:
<table border="1"><tr><td>姓名</td><td>年龄</td><td>性别</td></tr><tr><td colspan="3">暂无数据</td></tr>
</table>
在上述示例中,表格中的第二行使用了<tr><td colspan="3">暂无数据</td></tr>
来创建一行,并且该行的单元格跨越了3列,显示为"暂无数据"。
问题4: html 中 td tr 分别是什么意思?
在HTML中,td和tr是表格中的两个重要元素。
-
td元素:td代表表格中的单元格(table data)。每个td元素定义了一个表格中的单元格,并且可以包含文本、图像、链接或其他HTML元素。td元素必须位于tr元素内部。
-
tr元素:tr代表表格中的行(table row)。每个tr元素定义了表格中的一行,并且包含一个或多个td元素。tr元素必须位于table元素内部。
以下是一个简单的HTML表格示例:
<table><tr><td>单元格1</td><td>单元格2</td></tr><tr><td>单元格3</td><td>单元格4</td></tr>
</table>
在上面的示例中,有两个tr元素,每个tr元素包含两个td元素。这将创建一个包含两行两列的表格。
mix_kw 是关键字查询, value="{{ search_con['mix_kw'] }}" 是相关展示,没有则输入框点击搜索按钮后里面的内容立刻消失,但是有了value="{{search_con['mix_kw']}}", 则点完搜索按钮后 该值持续存在展示。
templates/member/info.html
{% extends "common/layout_main.html" %}
{% block content %}
{% include "common/tab_member.html" %}
<div class="row m-t"><div class="col-lg-12"><div class="row"><div class="col-lg-12"><div class="m-b-md">{% if info.status == 1 %}<a class="btn btn-outline btn-primary pull-right" href="{{ buildUrl('/member/set') }}?id={{ info.id }}"><i class="fa fa-pencil"></i>编辑</a>{% endif %}<h2>会员信息</h2></div></div></div><div class="row"><div class="col-lg-2 text-center"><img class="img-circle circle-border" src="{{ info.avatar }}"width="100px" height="100px"></div><div class="col-lg-10"><p class="m-t">姓名:{{ info.nickname }}</p><p>性别:{{ info.sex_desc }}</p></div></div><div class="row m-t"><div class="col-lg-12"><div class="panel blank-panel"><div class="panel-heading"><div class="panel-options"><ul class="nav nav-tabs"><li class="active"><a href="#tab-1" data-toggle="tab" aria-expanded="false">会员订单</a></li><li><a href="#tab-2" data-toggle="tab" aria-expanded="true">会员评论</a></li></ul></div></div><div class="panel-body"><div class="tab-content"><div class="tab-pane active" id="tab-1"><table class="table table-striped"><thead><tr><th>订单编号</th><th>支付时间</th><th>支付金额</th><th>订单状态</th></tr></thead><tbody>{% if pay_order_list %}{% for item in pay_order_list %}<tr><td>{{ item.order_number }}</td><td>{{ item.pay_time }}</td><td>{{ item.total_price }}</td><td>{{ item.status_desc }}</td></tr>{% endfor %}{% else %}<td colspan="4">暂无订单</td>{% endif %}</tbody></table></div><div class="tab-pane" id="tab-2"><table class="table table-striped"><thead><tr><th>评论时间</th><th>评分</th><th>评论内容</th></tr></thead><tbody><tr></tr>{% if comment_list %}{% for item in comment_list %}<tr><td>{{ item.created_time }}</td><td>{{ item.score }}</td><td>{{ item.content }}</td></tr>{% endfor %}{% else %}<td colspan="3">暂无评论</td>{% endif %}</tbody></table></div></div></div></div></div></div></div>
</div>
{% endblock %}
<img>
<img>
标签用于在网页中插入图片。class="img-circle circle-border"
指定了图片的样式,img-circle
将图片变为圆形,circle-border
添加了一个圆形边框。src="{{ info.avatar }}"
指定了图片的来源,{{ info.avatar }}
是一个占位符,表示图片的URL将从info
对象的avatar
属性中获取。width="100px" height="100px"
指定了图片的宽度和高度,将图片调整为100像素乘以100像素的大小。
这段代码的作用是在网页中显示一个圆形边框的头像图片,图片的来源和大小可以通过info
对象的avatar
属性和指定的宽度和高度进行设置。
templates/member/set.html
{% extends "common/layout_main.html" %}
{% block content %}
{% include "common/tab_member.html" %}
<div class="row mg-t20 wrap_member_set"><div class="col-lg-12"><h2 class="text-center">会员设置</h2><div class="form-horizontal m-t"><div class="hr-line-dashed"></div><div class="form-group"><label class="col-lg-2 control-label">会员名称:</label><div class="col-lg-10"><input type="text" class="form-control" placeholder="请输入会员名称" name="nickname" value="{{ info.nickname }}"></div></div><div class="hr-line-dashed"></div><div class="form-group"><div class="col-lg-4 col-lg-offset-2"><input type="hidden" name="id" value="{{ info.id }}"><button class="btn btn-w-m btn-outline btn-primary save">保存</button></div></div></div></div>
</div>
{% endblock %}
{% block js %}
<script src="{{ buildStaticUrl('/js/member/set.js') }}"></script>
{% endblock %}
templates/member/comment.html
{% extends "common/layout_main.html" %}
{% block content %}
{% include "common/tab_member.html" %}
<div class="row"><div class="col-lg-12"><table class="table table-bordered m-t"><thead><tr><th>头像</th><th>姓名</th><th>美餐</th><th>评论内容</th><th>打分</th></tr></thead><tbody>{% if list %}{% for item in list %}<tr><td><img alt="image" class="img-circle" src="{{ item.member_info.avatar }}" style="width: 40px;height: 40px;"></td><td>{{ item.member_info.nickname }}</td><td>{% for item_food in item.foods %}{{ item_food.name }}、{% endfor %}</td><td>{{ item.content }}</td><td>{{ item.score }}</td></tr>{% endfor %}{% else %}<tr><td colspan="5">暂无数据</td></tr>{% endif %}</tbody></table><!--分页代码已被封装到统一模板文件中-->{% include 'common/pagenation.html' %}</div>
</div>
{% endblock %}
config/base_setting.py
STATUS_MAPPING = {"1":"正常","0":"已删除"
}
web/static/js/member/index.js
;
var member_index_ops = {init:function(){this.eventBind();},eventBind:function(){var that = this;$(".wrap_search .search").click(function(){$(".wrap_search").submit();});$(".remove").click( function(){that.ops( "remove",$(this).attr("data") );} );$(".recover").click( function(){that.ops( "recover",$(this).attr("data") );} );},ops:function( act,id ){var callback = {'ok':function(){$.ajax({url:common_ops.buildUrl( "/member/ops" ),type:'POST',data:{act:act,id:id},dataType:'json',success:function( res ){var callback = null;if( res.code == 200 ){callback = function(){window.location.href = window.location.href;}}common_ops.alert( res.msg,callback );}});},'cancel':null};common_ops.confirm( ( act == "remove" ? "确定删除?":"确定恢复?" ), callback );}};$(document).ready( function(){member_index_ops.init();
} );
web/static/js/member/set.js
;
var member_set_ops = {init:function(){this.eventBind();},eventBind:function(){$(".wrap_member_set .save").click( function(){var btn_target = $(this);if( btn_target.hasClass( "disabled" ) ){common_ops.alert( "正在处理,请不要重复提交" );return;}var nickname_target = $(".wrap_member_set input[name=nickname]");var nickname = nickname_target.val();if( nickname.length < 1 ){common_ops.tip( "请输入符合规范的姓名",nickname_target );return;}btn_target.addClass("disabled");var data = {nickname:nickname,id:$(".wrap_member_set input[name=id]").val()};$.ajax({url:common_ops.buildUrl("/member/set"),type:'POST',data:data,dataType:'json',success:function(res){btn_target.removeClass("disabled");var callback = null;if( res.code == 200 ){callback = function(){window.location.href = common_ops.buildUrl("/member/index");}}common_ops.alert( res.msg,callback);}});});}
};$(document).ready(function(){member_set_ops.init();
});
这段代码是一个JavaScript的对象,其中包含了一个名为member_set_ops
的变量。该变量具有三个方法:init
、eventBind
和save
。其中,init
方法用于初始化对象,eventBind
方法用于绑定事件,save
方法用于保存数据。
在eventBind
方法中,当点击.wrap_member_set .save
元素时,会执行一个回调函数。在回调函数中,首先判断按钮是否有disabled
类,如果有,则弹出提示信息"正在处理,请不要重复提交",并返回。如果按钮没有disabled
类,则继续执行后续代码。
接下来,通过$(".wrap_member_set input[name=nickname]")
选择器选中一个名为nickname
的输入框,并获取其值赋给变量nickname
。然后,判断nickname
的长度是否小于1,如果是,则通过common_ops.tip
方法弹出提示信息"请输入符合规范的姓名",并返回。如果nickname
的长度大于等于1,则继续执行后续代码。
接着,给按钮添加disabled
类,防止重复提交。然后,创建一个名为data
的对象,其中包含两个属性:nickname
和id
。nickname
属性的值为上面获取的nickname
变量的值,id
属性的值为.wrap_member_set input[name=id]
元素的值。
最后,可以根据具体需求来处理data
对象,例如发送Ajax请求将数据保存到服务器。
该段代码是一个使用jQuery的Ajax请求的示例。下面是对代码的详细解析:
-
$.ajax({})
:这是一个jQuery的Ajax请求方法,用于发送异步HTTP请求。 -
url:common_ops.buildUrl("/member/set")
:指定请求的URL,这里使用了common_ops.buildUrl()
方法来构建URL。 -
type:'POST'
:指定请求的类型为POST。 -
data:data
:指定要发送到服务器的数据,这里的data
是一个变量,表示要发送的数据。 -
dataType:'json'
:指定服务器返回的数据类型为JSON。 -
success:function(res){}
:指定请求成功后的回调函数,res
是服务器返回的数据。 -
btn_target.removeClass("disabled")
:移除按钮的disabled
类,使按钮可用。 -
if( res.code == 200 )
:判断服务器返回的状态码是否为200。 -
callback = function(){ window.location.href = common_ops.buildUrl("/member/index"); }
:定义一个回调函数callback
,如果服务器返回的状态码为200,则将页面重定向到/member/index
。 -
common_ops.alert( res.msg,callback)
:调用common_ops.alert()
方法显示服务器返回的消息,并将回调函数callback
作为参数传递。 -
$(document).ready(function(){ member_set_ops.init(); });
:在文档加载完成后,调用member_set_ops.init()
方法进行初始化操作。
这段js总而言之就是对会员信息进行更改,更改成功后重定向到member/index首页。
相关文章:
Flask 会员列表展示
感谢编程浪子师傅的源码信息分享 web/controllers/member/Member.py # -*- coding: utf-8 -*- from flask import Blueprint,request,redirect,jsonify from common.libs.Helper import ops_render,iPagination,getCurrentDate,getDictFilterField,selectFilterObj from comm…...
光纤知识总结
1光纤概念: 光导纤维(英语:Optical fiber),简称光纤,是一种由玻璃或塑料制成的纤维,利用光在这些纤维中以全内反射原理传输的光传导工具。 微细的光纤封装在塑料护套中,使得它能够…...
LeetCode简单题记录
1、两数之和,给定数组nums,求和为target的两个数组元素的下标 我用了两个for循环,官方解为 哈希表,知识盲区 class Solution { public:vector<int> twoSum(vector<int>& nums, int target) {unordered_map<i…...
【Python学习】Python学习10-列表
目录 【Python学习】Python学习10-列表 前言创建语法访问列表中的值更新和删除列表元素操作列表列表截取Python列表函数&方法参考 文章所属专区 Python学习 前言 本章节主要说明Python的列表List。 创建语法 创建一个列表 通过方括号和逗号分割创建,列表数据…...
MySQL四大引擎,数据库管理,数据表管理,数据库账号管理
MySQL四大引擎 InnoDB InnoDB引擎是MySQL默认的存储引擎。它支持事务和行级锁定,并具有高并发性和数据完整性保护的特性。InnoDB适用于具有复杂查询和高并发读写操作的应用程序。MyISAM InnoDB引擎特点和优势 事务支持:InnoDB支持ACID(原子…...
CentOS找回root密码
很悲伤,你忘记了root密码。。。 那就来重置它吧~ 1、在启动时选择操作系统:在引导过程中,选择CentOS操作系统并按下键盘上的任意键来停止引导。 2、 进入编辑模式:在启动菜单中,找到并选择要编辑的CentOS条目&…...
react输入框检索树形(tree)结构
input搜索框搜索树形子级内容1. input框输入搜索内容2. 获取tree结构数据3. 与tree匹配输入的内容,tree是多维数组,一级一级的对比输入的内容是否匹配,用forEach循环遍历数据,匹配不到在往下找,直到找到为null &#x…...
云原生学习系列之基础环境准备(虚拟机搭建)
最近由于工作需要开始学习云原生相关内容,为方便学习操作,准备在外网搭建自己的环境,然后进行相关的练习,搭建环境的第一步便是虚拟机的安装。 基础软件 这里我用到的是CentOS-7-x86_64的操作系统。 链接:https://pa…...
Python入门知识点分享——(十三)内置函数
先向大家致歉,这几天忙于单片机的复习和考试,耽误了Python知识的分享。今天在回顾的时候发现数据计算还有些遗漏的部分,基本上都属于Python的内置函数,就一并补充在这篇文章中。 Python内置函数是在Python解释器中已经预定义的函…...
手拉手springboot3整合mybatis-plus多数据源
环境介绍 技术栈 springbootmybatis-plusmysql 软件 版本 mysql 8 IDEA IntelliJ IDEA 2022.2.1 JDK 17 Spring Boot 3.1.7 dynamic-datasource 3.6.1 mybatis-plus 3.5.3.2 加入依赖 <dependency><groupId>com.baomidou</groupId><arti…...
【JAVA】Java8开始ConcurrentHashMap,为什么舍弃分段锁
🍎个人博客:个人主页 🏆个人专栏: JAVA ⛳️ 功不唐捐,玉汝于成 目录 前言 正文 分段锁的好处: 结语 我的其他博客 前言 在Java 8中,ConcurrentHashMap的实现经历了重大的改进&am…...
基于JAVA+SpringBoot的咖啡商城
✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取项目下载方式🍅 一、项目背景介绍: 随着互联网的普及和发…...
[AutoSar]基础部分 RTE 08 runnable mapping
目录 关键词平台说明一、runnable mapping的必要性二、runnable mapping 通用规则三、Task type四、可以不用mapping的runnbale 关键词 嵌入式、C语言、autosar、runnable 平台说明 项目ValueOSautosar OSautosar厂商vector芯片厂商TI编程语言C,C编译器HighTec (…...
云消息队列 Kafka 版生态谈第一期:无代码转储能力介绍
作者:娜米 云消息队列 Kafka 版为什么需要做无代码转储 云消息队列 Kafka 版本身是一个分布式流处理平台,具有高吞吐量、低延迟和可扩展性等特性。它被广泛应用于实时数据处理和流式数据传输的场景。然而,为了将云消息队列 Kafka 版与其他数…...
java: 从HBase中读取数据
一、添加依赖: <dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-client</artifactId><version>2.6.0</version></dependency><dependency><groupId>org.apache.hbase</groupI…...
Lumeical Script------Script Prompt 中的两种输出方式
Lumeical Script------Script Prompt 中的两种输出方式 引言正文方法1方法2 引言 有时候,和众多编程语言一样,我们需要在 Script Prompt 中打印一些我们已经得到的数据,这样可以方便我们调试代码和查看代码中是否有错误。关于在 Script Prom…...
什么是OOM error
OOM error是"Out of Memory"(内存不足)错误的简称。它通常发生在计算机程序执行过程中,当程序需要更多内存空间来执行操作,但系统没有足够的可用内存时,就会触发OOM错误。 当程序尝试使用超过其可用内存的量…...
IO进程线程 day7
使用消息队列完成两个进程之间相互通信 #include<my_head.h> struct msgbuf {long mtype;char mtext[128]; }; #define SIZE (sizeof(struct msgbuf) - sizeof(long))//分支线程从消息队列中读取类型2的消息 void *task(void *arg) {int msgid *((int *)arg);struct msg…...
扩展学习|数据融合助推商务智能与分析
文献来源:[1]李爱华,续维佳,石勇.基于数据融合的商务智能与分析架构研究[J].计算机科学,2022,49(12):185-194. 一、信息融合 (一)信息融合定义演变 早期信息融合的定义指出,其主要任务是综合分析若干传感器观测到的信息[9,…...
Java项目:112SSM在线电影订票系统
博主主页:Java旅途 简介:分享计算机知识、学习路线、系统源码及教程 文末获取源码 一、项目介绍 在线电影订票系统基于SpringSpringMVCMybatis开发,系统分为前台和后台,前台主要用来用户浏览电影信息,订票,…...
Echarts——使用graphic组件在一个option内同时设置两个饼图的背景图
使用echarts的graphic原生图形元素组件,为两个饼图设置对应背景。 <template><div id"app"><div class"charts" ref"charts"></div></div> </template><script> import * as echarts from…...
编程笔记 html5cssjs 027 HTML输入属性(1/2)
[TOC](编程笔记 html5&css&js 027 HTML输入属性(1/2)) <input>元素除了type属性表示输入类型,后面还跟上其他属性,叫输入属性。 value 属性 value 属性规定输入字段的初始值: <form action"">First name:<…...
请求参数乱码问题
POST请求方式解决乱码问题 在web.xml里面设置编码过滤器 <filter><filter-name>CharacterEncodingFilter</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><!-- 设置过滤器中的属性值 -…...
【leetcode】力扣热门之反转链表【简单难度】
题目描述 给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。 用例 输入:head [1,2,3,4,5] 输出:[5,4,3,2,1] 输入:head [1,2] 输出:[2,1] 输入:head [] 输出:[…...
【sgPasswordInput】自定义组件:带前端校验密码强度的密码输入框,能够提供密码强度颜色提示和文字提示
特性: 有密码强度颜色提示密码强度进度条提示支持设置默认输入提示和密码长度 sgPasswordInput源码 <template><div :class"$options.name" style"width: 100%"><el-inputstyle"width: 100%"ref"psw"type&…...
1599 - Ideal Path (UVA)
题目链接如下: https://onlinejudge.org/index.php?optioncom_onlinejudge&Itemid8&category448&pageshow_problem&problem4474 这道题也是看了刘汝佳的思路才写出来的.... 代码如下: #include <cstdio> #include <deque&…...
计算机网络(超级详细笔记)
使用教材计算机网络(第8版)(谢希仁) 第一章:概述 第二章:物理层 第三章:数据链路层 第四章:网络层 第五章:运输层 第六章:应用层 目…...
老杨说运维 | 年末大讲回顾:运维的尽头也是大模型吗?
哈喽~朋友们,这么快又见面啦。前阵子我们给CEO老杨安排了一场年末大讲,主要是跟大家聊聊智能运维的“智”与“能”以及剖析时下热点----运维大模型。后台收到了不少朋友的反馈,小编看了大受鼓舞并暗下决心----新的一年,希望能多安…...
Unity 利用UGUI之Scrollbar制作进度条
在Unity中除了用Slider、Image做进度条,其实用Scrollbar也可以做进度条。 首先,在场景中新建一个Scrollbar组件和一个Text组件: 其次,创建模拟进度的一个脚本,Scrollbar_Progressbar.cs: using System.Collections; …...
MySQL之导入、导出
文章目录 1.navicat导入导出2.mysqldump命令导入导出2.1导出2.2导入 3.load data infile命令导入导出4.远程备份5.思维导图 1.navicat导入导出 使用Navicat工具导入t_log 共耗时 55s 2.mysqldump命令导入导出 2.1导出 导出表数据和表结构 语法: mysqldump -u用…...
网站建设的展望/win10系统优化软件
SSH 登录太慢可能是 DNS 解析的问题,默认配置下 sshd 初次接受 ssh 客户端连接的时候会自动反向解析客户端 IP 以得到 ssh 客户端的域名或主机名。如果这个时候 DNS 的反向解析不正确,sshd 就会等到 DNS 解析超时后才提供 ssh 连接,这样就造成…...
毕业设计做网站做不出/磁力链最好用的搜索引擎
开始尝试使用除法,但是有0比较难受,之后… 左边:a01; a1a0; a2a0a1; a3a0a1a2; 右边:a31; a2a3; a1a3a2; a0a3a2a1; 然后左右两边相乘。就是最后的结果集。 public static int[] productExceptSelf(int[] nums) {int n nums.le…...
阿里 网站备案核验单/网站怎么做出来的
下载地址 https://www.consul.io/downloads windows上安装consul 下载完成后解压只有一个consul.exe文件,双击运行,查看版本号信息 开发模式启动 可以通过以下地址访问consul的首页 http://localhost:8500/ui/dc1/services...
成都有哪些网站建设/地推接单平台网
下面用自启动apache为例;自启动脚本:/usr/local/apache2/bin;./apachectl start文件位于/etc/rc.d/init.d下,名为apached, 注意要可执行.#chmod x /etc/rc.d/init.d/apached //设置文件的属性为可执行#ln -s /etc/rc.d/init.d/apached /etc/rc3.d/S90apache //建立软…...
郑州web网站建设公司/如何推广网站
一、创造价值的公司 选择好公司,才是长期投资的锚! 二、价值匹配公司的成长性 这里是赚公司成长的钱! 三、价值的精华需要时间去洗涤! 这里是赚公司估值修复的钱!...
网上接网站开发类订单的平台/网络营销推广的方式有哪些
了解完函数的调用区域是如何影响this 对象的,还有this 的各种绑定方式以及各种绑定方式的优先级后 最后一部分,来了解一下this 的一些例外情况 1、被忽略的this 例如在使用bind 方法时候进行函数柯里化,如果此时函数并没有打算绑定任何对象在…...