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响应。下面是对代码的详细解析:

  1. 首先,创建一个空字典resp_data来存储响应数据。
  2. 通过request.values获取请求参数,并将其赋值给变量req
  3. 使用条件语句判断是否存在参数p,如果存在且不为空,则将其转换为整数并赋值给变量page,否则将page设置为1。
  4. 创建一个Member查询对象query
  5. 如果请求参数中存在mix_kw,则使用filter()方法对query进行过滤,筛选出nickname字段中包含req['mix_kw']的记录。

请注意,代码中的Member是一个模型类,可能是通过SQLAlchemy定义的数据库表的映射类。

这段代码是一个条件判断语句,用于筛选查询结果。如果请求参数中包含名为’status’的键,并且该键对应的值大于-1,则会执行以下操作:

  1. 将查询对象query的筛选条件设置为Member.status等于请求参数中’status’对应的整数值。
  2. 创建一个名为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是一个什么样的值?请详细解析

reqrequest.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函数

数据库


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)方法。这些装饰器方法允许我们在访问类的属性时执行一些自定义的逻辑

  1. @property装饰器用于定义一个getter方法,它允许我们像访问普通属性一样访问该方法。在这段代码中,@property装饰器定义了两个getter方法:status_desc和sex_desc。

  2. status_desc方法返回了一个名为app.config[‘STATUS_MAPPING’]的字典中与self.status对应的值。这个字典是一个配置文件中的映射,它将状态码映射到相应的描述。

  3. 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是表格中的两个重要元素。

  1. td元素:td代表表格中的单元格(table data)。每个td元素定义了一个表格中的单元格,并且可以包含文本、图像、链接或其他HTML元素。td元素必须位于tr元素内部。

  2. 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 %}

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();
} );

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/600814.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring学习之——AOP(面向切面)

AOP 概念 AOP&#xff1a;全称是Aspect Oriented Programming即&#xff1a;面向切面编程。 简单的说它就是把我们程序重复的代码抽取出来&#xff0c;在需要执行的时候&#xff0c;使用动态代理的技术&#xff0c;在不修改源码的基础上&#xff0c;对程序进行增强&#xff…

24年初级会计资格考试报名信息采集流程共10大步骤,千万不要搞错

2024年初级会计资格考试报名信息采集流程共10大步骤&#xff0c;不要搞错哦&#xff1b; 第一步&#xff1a;输入证件号、点击登录 第二步&#xff1a;阅读采集须知 第三步&#xff1a;填写个人信息&#xff08;支付宝搜索"亿鸣证件照"或者微信搜索"随时照&q…

数据结构与算法教程,数据结构C语言版教程!(第二部分、线性表详解:数据结构线性表10分钟入门)八

第二部分、线性表详解&#xff1a;数据结构线性表10分钟入门 线性表&#xff0c;数据结构中最简单的一种存储结构&#xff0c;专门用于存储逻辑关系为"一对一"的数据。 线性表&#xff0c;基于数据在实际物理空间中的存储状态&#xff0c;又可细分为顺序表&#xff…

【c语言】指针小结

一、指针是什么&#xff1f; 可以通过运算符&来取得变量实际保存的 起始地址 。 &#xff08;这个地址是虚拟地址&#xff0c;并不是真正物理内存上的地址。&#xff09; 数据类型 *标识符 &变量; int *pa &a; int *pa NULL; (NULL表示地址为0的内存空间&a…

Apache SeaTunnel:探索下一代高性能分布式数据集成工具

大家下午好&#xff0c;我叫刘广东&#xff0c;然后是来自Apache SeaTunnel社区的一名Committer。今天给大家分享的议题是下一代高性能分布式海量数据集成工具&#xff0c;后面的整个的PPT&#xff0c;主要是基于开发者的视角去看待Apache SeaTunnel。后续所有的讲解主要是可能…

52、Flink的应用程序参数处理-ParameterTool介绍及使用示例

Flink 系列文章 一、Flink 专栏 Flink 专栏系统介绍某一知识点&#xff0c;并辅以具体的示例进行说明。 1、Flink 部署系列 本部分介绍Flink的部署、配置相关基础内容。 2、Flink基础系列 本部分介绍Flink 的基础部分&#xff0c;比如术语、架构、编程模型、编程指南、基本的…

LeetCode第102题 - 二叉树的层序遍历

题目 解答 class Solution {List<List<Integer>> nodeLevels new ArrayList<>();public List<List<Integer>> levelOrder(TreeNode root) {levelOrder(root, 0);return nodeLevels;}public void levelOrder(TreeNode root, int k) {if (root …

噬菌体序列分析工具PhaVa的使用和使用方法

github: 25280841/PhaVa: Adapting the phasefinder approach for identifying phase variation to long reads (github.com) 挺简单的&#xff0c;这里就不翻译了&#xff0c;大家看着直接用吧。 PhaVa PhaVa is an approach for finding potentially Phase Variable invert…

第7章-第1节-Java中的异常处理

1、异常Exception概述&#xff1a; 1&#xff09;、异常的概念&#xff1a; 现实生活中万物在发展和变化会出现各种各样不正常的现象。 例如&#xff1a;人的成长过程中会生病。 实际工作中&#xff0c;遇到的情况不可能是非常完美的。 比如&#xff1a;你写的某个模块&…

使用jmeter从0开始完成性能测试

使用JMeter从0开始完成性能测试 介绍 在软件开发过程中&#xff0c;性能测试是一项关键任务&#xff0c;它可以帮助我们评估系统在不同负载条件下的性能表现&#xff0c;发现潜在的性能瓶颈。JMeter是一款功能强大且易于使用的性能测试工具&#xff0c;它可以帮助我们完成各种…

欧洲最好的AI大模型:Mistral 7B!(开源、全面超越Llama 2)

你可能已经听说过Meta&#xff08;原Facebook&#xff09;的Llama 2&#xff0c;这是一款拥有13亿参数的语言模型&#xff0c;能够生成文本、代码、图像等多种内容。 但是你知道吗&#xff0c;有一家法国的创业公司Mistral AI&#xff0c;推出了一款只有7.3亿参数的语言模型&am…

GitHub Copilot 最佳免费平替:阿里通义灵码

之前分享了不少关于 GitHub Copilot 的文章&#xff0c;不少粉丝都评论让我试试阿里的通义灵码&#xff0c;这让我对通义灵码有了不少的兴趣。 今天&#xff0c;阿七就带大家了解一下阿里的通义灵码&#xff0c;我们按照之前 GitHub Copilot 的顺序分享通义灵码在相同场景下的…

Vue 之 修饰符汇总

一、简介 在Vue中&#xff0c;修饰符是一种特殊的语法&#xff0c;用于修改指令或事件绑定的行为&#xff0c;它们以点号&#xff08;.&#xff09;的形式添加到指令或事件的后面&#xff0c;并可以改变其默认行为或添加额外的功能&#xff0c;如&#xff1a;禁止事件冒泡、数…

java 中数组常用排序方法举例说明

java 中数组常用排序方法举例说明 在Java中&#xff0c;数组的排序是常见的操作之一&#xff0c;而Java提供了多种排序方法来满足不同场景的需求。下面详细介绍5种常用的数组排序方法&#xff1a; 冒泡排序&#xff08;Bubble Sort&#xff09;&#xff1a; 冒泡排序是一种简单…

【mars3d】new mars3d.layer.GeoJsonLayer(实现环状面应该怎么传data

问题&#xff1a;【mars3d】new mars3d.layer.GeoJsonLayer(实现环状面应该怎么传data 解决方案&#xff1a; 1.在示例中修改showDraw()方法的data数据&#xff0c;实现以下环状面效果 2.示例链接&#xff1a; 功能示例(Vue版) | Mars3D三维可视化平台 | 火星科技 export f…

Ubuntu20.04安装ROS2 Foxy

Ubuntu20.04安装ROS2 Foxy 实操安装 安装ROS2的教程在网上很多&#xff0c;但是我操作之后都有问题&#xff0c;大部分的问题是在 sudo apt update 时访问packages.ros.org无法成功&#xff0c;主要的原因是没有外网&#xff0c;而自己整一个外网代理又非常麻烦&#xff0c;所…

读书之深入理解ffmpeg_简单笔记3(初步)

通读完只能对书中内容有大概的了解&#xff0c;具体的细节还得一一实践攻克。 10: libavformat接口使用 媒体流&#xff0c;文件等封装&#xff0c;解封装&#xff0c;转封装 视频截取&#xff0c;AVFormatContext,AVPacket等介绍 11&#xff1a;libavcodec接口使用 视频&…

Android开发中“真正”的仓库模式

原文地址&#xff1a;https://proandroiddev.com/the-real-repository-pattern-in-android-efba8662b754原文发表日期&#xff1a;2019.9.5作者&#xff1a;Denis Brandi翻译&#xff1a;tommwq翻译日期&#xff1a;2024.1.3 Figure 1: 仓库模式 多年来我见过很多仓库模式的实…

pytest安装失败,报错Could not find a version that satisfies the requirement pytest

问题 安装pytest失败&#xff0c;尝试使用的命令有 pip install pytest pip3 install pytest pip install -U pytest pip install pytest -i https://pypi.tuna.tsinghua.edu.cn/simple但是都会报同样的错&#xff1a; 解决方案 发现可能是挂了梯子的原因&#xff0c;关掉…

代码随想录算法训练营Day20|654.最大二叉树、617.合并二叉树、700.二叉搜索树中的搜索、98.验证二叉搜索树

目录 654.最大二叉树 前言 递归法 617.合并二叉树 前言 递归法 700.二叉搜索树中的搜索 前言 递归法 递归法 98.验证二叉搜索树 前言 递归法 迭代法 总结 654.最大二叉树 题目链接 文章链接 前言 本题延续昨天最后一题&#xff0c;依然是一道构造二叉树的题目…