广东省内游之一,没有海

以下全部摘抄自网上,没有亲自去过

一. 乳源大峡谷, 深圳开车330KM

1. 长达15公里,谷深300多米,有“广东最美峡谷”的美誉。这个峡谷最大的特点便是奇美奇险。而且这里也特别适合徒步!
身临其境,你才能感受到它的特别。据网友评论说是一个超出你期待的景点!
2. 地址:韶关市乳源瑶族自治县西南68公里的大布镇
3. 自驾:途径京港澳高速、乐广高速,用时约5h
4. 推荐美食:鱼丸、鱼面、马鲛鱼饭、猪肠碌、海胆饭、泥焗鸡

乳源大峡谷

一.2分支 仙门奇峡,韶关市乳源瑶族自治县洛阳镇境内
风景独特,很多奇石异景,进入景区犹如进入仙境般的感觉,在这里可以零距离接大自然,是一个避暑胜地,旅游最佳目的地。
其中的情侣峡竹筏漂流,全长约3公里,峡谷两岸的悬崖峭壁千姿百态。山谷间有细流汇成的河,河面倒映着山,天然石门,让
你感叹大自然的鬼斧神工。

仙门奇峡

一.3分支 地址:韶关市曲江区枫湾镇 枫湾小桂林

风湾镇1
风湾镇2
风湾镇3
风湾镇4
风湾镇5
风湾镇6

二. 英西峰林 深圳开车280KM, 距离乳源90KM

1. 英西峰林地处英德西南部的九龙、黄花两镇间,既有喀斯特地貌的淡墨山水,又有小桥流水般的农家田园,特别
适合自驾、徒步或骑行。正确的游玩姿势当然是徒步,穿过一道道乡间小路,看看客家人的日常生活,满足你逃离城
市的心愿。如果走累了,就花十几块钱,乘坐竹筏顺溪水而下,既惬意,又能将两岸美景尽收眼底~
2. 地址:清远英德市西南60公里的九龙
3. 自驾:途经京港澳高速、许广高速等,用时约4.5h
4. 推荐美食:黄花鸡、九龙豆腐、英德红茶、英德东乡蒸肉   
5. 周边游玩推荐 :连南千年瑶寨,“广东十大最美古村落”之一(约两小时车程)
    地址:英德市区西南60多公里的九龙、明迳、岩背三镇一带
    自驾游路线:清连高速,走S348省道,一个多小时车程可到达九龙镇。

英西峰林

二.2 分支,洞天仙境
,清远市英德市九龙镇, 步行从洞口沿着栈道往山洞里面走,洞中豁然开朗,洞顶有两个通天大洞,每天中午
11点半左右,光线会透入洞里,映射到水面上,眼前出现山、水、石、钟乳、瀑布,景色迷人,宛如仙境。可以选择坐
小船进去回程走路出来。不上山顶的话,景点路程并不远,里面的码头是一片竹林,很悠闲很舒服,适合带老少前来游玩。

英德洞天仙境

三. 清泉湾, 开车200KM, 离英西峰林68KM

1.【推荐理由】度假区交通便利,离县城只有五公里的距离。区内的娱乐项目也很丰富,有山泉水城、竹林极速滑水漂流、度
  假酒店,还有集趣味、游乐、挑战于一体的“欢乐智勇向前冲”、大型水路拓展训练基地、特色餐厅、会议中心等项目和配套
  服务设施,是一个集观光度假、休闲疗养、商务会议、特色美食、运动健身、生态旅游为一体的大型生态旅游度假区。
2. 景区电话:0763-5838666
3. 小贴士:1、看点:漂流、泡温泉,休闲度假
4. 自驾线路:从深圳走广深高速,再到北二环高速,上广清高速到清远市后,过北江大桥右转,经先锋桥即可看到前往清泉湾的指示牌;
   预计3个半小时可到

清泉湾大门
清泉湾1
清泉湾2
清泉湾3
清泉湾4

四. 从化白水寨 深圳开车160KM,

1.【推荐理由】白水寨,因拥有中国内地落差最大的瀑布群而出名。景区内修建有一条长约6.6公里的木栈道,长度为全国之最。游人可
  沿着木栈道登山,一路前行,一边呼吸森林负氧离子,一边欣赏仙瀑美景。
2. 景区电话:020-82821188
3. 小贴士:1、交通:自驾车深圳——广州,走机场高速,接街北高速,在从化街口出口转105国道,再沿S355省道(往增城方向)前行,即
   可到达白水寨景区。车程约1小时,交通便捷,路况良好。
4. 美食:古法烧鸡、手打猪肉丸、榄角蒸水库鱼头

增城白水寨1
增城白水寨2
增城白水寨3
增城白水寨4
四.1 分支 不远是石门国家森林公园
不用下车就可买票进入(成年人30元,车辆进入公园10元,65岁以上老人免费)。
开车直接进入公园游览,上午先看了石门景区,在桃花源的景点有小面积的花圃,开车一路走下去,直到巍峨石门、玫瑰园等景点处。如果再往
三仙会堂和天堂顶均需徒步,而且时间较长,后未去。
上午11:30左右开车往石灶景区方向,印象最深的是天池花海,花的品种和面积确实不少。
下午,4点30左右,游览结束,开始往回返程。
体会: 1. 由于可以开车自驾进入景区,所以陪同老人前往,特别合适。
2. 这里也是一个徒步的好地方,有山有水有步道,尤其天堂顶还是有一定挑战性的。有机会约几个喜欢徒步的朋友再来走一走。
石门山森林公园
石门竹林
石门森林
石门花海

五. 雁山湖国际花园度假区 深圳开车410KM, 在梅州境内

【推荐理由】度假村依山伴水,环境十分优越。区内环境很好,有森林公园,是一个天然的大氧吧。度假村不仅环境好,设施
也建设的很完善。现在度假村, 内建成的有山庄别墅、酒店、滑草场、游泳池、童趣园、运动场、跑马场等,配套服务丰富。现已
建设有春晖园、夏晓园、秋实园三大景区,是休闲度假的最佳场所。
景区电话:0753-2839288
小贴士:自驾最近路线:深圳—梅观高速—机荷高速—惠盐高速—惠河高速—梅河高速—雁鸣湖。

雁山湖度假区1
雁山湖度假区2

六. 江门古劳水乡又称围墩水乡,已经有600多年历史,有“中国威尼斯”之称,是典型的湿地生态地貌

[门票】免费【地址】江门市鹤山市古劳镇双桥村委会仁和堡村
【交通】乘车:深圳坐汽车到鹤山,在鹤山坐汽车或者打车到古劳水乡。(建议自驾,导航到”古劳镇政府”,政府旁即为古劳水乡游客中心。深圳自驾过去差不多3h)
古劳镇1
古劳镇2
古劳镇3
古劳镇4
古劳镇5
古劳镇6
6.1分支 下川岛王府洲旅游度假区, 江门市台山市川岛镇,海边沙滩
下川岛1
下川岛2
下川岛3

七. 湖光岩 (深圳开车530KM)

湛江市麻章区湖光镇, 湖光岩真是绿色的海洋,从西门进入景区,初见玛珥湖,真被惊艳到了。湖面壮阔而平静,湖
水碧绿清澈,湖边绿树丛生。沿着湖一直走一圈大概需要3个小时

手机投屏电脑的软件之一,Scrcpy

2023年10月在debian12下重新用了一次,此时版本为2.1.1

  1. 到gihub上下载最新版安装如下:
1
2
3
4
5
6
7
8
9
10
11
$ sudo apt install ffmpeg libsdl2-2.0-0 adb wget \
gcc git pkg-config meson ninja-build libsdl2-dev \
libavcodec-dev libavdevice-dev libavformat-dev libavutil-dev \
libswresample-dev libusb-1.0-0 libusb-1.0-0-dev
$ git clone https://github.com/Genymobile/scrcpy
$ cd scrcpy
$ ./install_release.sh
# 安装成功,如果以后有新的版本,安装命令如下
$ cd scrcpy
$ git pull
$ ./install_release.sh
  1. 打开手机“允许USB调试”,用用USB线与电脑链接,手机会弹出是否充许电脑对手机进行调试,要在手机上点击允许。
  2. 有线连接
1
2
3
4
5
$ adb devices
List of devices attached
XZ9CRS8ED unauthorized
# 表示连上手机了
$ scrcpy # 就可以用了
  1. 无线连接
1
2
3
4
5
6
7
# 退出上一步的有线,并执行
$ adb shell ip a # 查看手机的IP地址,如果为192.168.8.666
$ adb tcpio 5555
# 提示“restarting in TCP mode port: 5555”
# 可以拔掉USB线了
$ adb connect 192.168.8.666:5555
$ scrcpy
  1. 快捷键,利于控制,MOD键,默认为左边的Alt键,可通过如下命令更改
1
2
3
4
5
# 要更改使用右 Ctrl 键,则执行
scrcpy --shortcut-mod=rctrl
使用左 Ctrl 键 + 左 Alt 键,或 Super 键
scrcpy --shortcut-mod=lctrl+lalt,lsupe
# 可选的按键有 lCtrl、rCtrl、lAlt、rAlt、lSuper`和 rSuper

MOD+f : 把scrcpy这个窗口在电脑上全屏
MOD+左箭头 : 向左旋转scrcpy窗口,注意手机的屏幕并没有旋转
MOD+右箭头 : 向右旋转scrcpy窗口,注意手机的屏幕并没有旋转
MOD+h 或 鼠标中键 :反回手机主屏幕
MOD+b 或 鼠标右键双击两次 : 返回
MOD+s : 切换手机中的App
MOD+m : 手机熄屏时,可以解锁屏幕
双击鼠标右键两次 : 手机熄屏时,可以解锁屏幕
MOD+o :关闭手机屏幕,但在电脑上还是显示。这里人为开手机屏幕也得了。得用下个快捷键打开。这一点非常好,手机省电了
MOD+Shift+o : 打开手机屏幕。
MOD+r : 旋转手机屏幕,按一次横屏,再按一次坚屏
如果把MOD换成 Ctrl键,测Ctrl+c Ctrl+x Ctrl+v也可以用了
Ctrl+Shift+V 把手机上的剪贴本放到电脑上

以下为2022年连接时的记录

两年前Scrcpy还不成熟时,试用过一下,不好用。就没有用了,现在的版本好了很多,也稳定了好多。趁电脑安装ubuntu20.04最新版时,又试用了一下。相当不错,链接两个小时,没有一次掉线。又怕忘记如何链接的,就做个笔记。
一 安装
1
2
$ sudo snap install scrcpy # 用apt install scrcpy也可以,但是采用snap安装,可以安装比较新的版本
$ sudo apt install android-tools-adb
二 手机与电脑先物理连接

打开手机“允许USB调试”,用用USB线与电脑链接

三 配置
1
$ lsusb  # 查看链接到USB接品的设备

USB device
可以看到,我的手机的ID号是:18d1:4ee2

1
2
3
4
5
6
7
8
$ mkdir ~/.android
$ eho 0x18d1 > ~/.android/adb_usb.ini
$ cd /etc/udev/rules.d
$ vim android.rules
# 写入
SUBSYTEM=="usb", SYSFS{idVendor}=="04e8", MODE="0666"
# 保存退出
$ sudo chmod 777 android.rules
四 启动服务
1
2
3
$ sudo service udev restart
$ adb start-server
$ adb devices

终端会显示
说明己经连接上了手机。则可以启动scrcpy了。

1
$ scrcpy

可以链接了。

五 无线链接

首先 手机与电脑要保持在一个局域网内,先用USB线连接手机

1
$ adb tcpip 5555 #设端口为5555

把线拔掉

1
2
3
4
$ adb connect 192.168.8.218:5555 # 192.168.8.218是手机的IP地址
$ scrcpy
$ scrcpy --turn-screen-off # 连接时,可关掉手机屏幕
$ scrcpy --bit-rate 2M --max-size 800 # 降低无线链接的速率(2M),与屏幕分辨率(800),以保持无线链接不卡线

修改Anlinux的shell,以安装ubuntu的新版本

多年前采用anlinux的app,来在termux上安装linux,后面有大神写出了proot-distro的东东来安装linux非常方便,还能通过修改/etc/proot-distro/目录下的文件,选择各种版本的linux,于是果断放弃了anlinux转用proot-distoo。然而proot-distro的作者却自己封装了linux的rootfs文件,没有辣么方便了,又从proot-distro更新到2.9.3后,竟然连我以前装的linux版本都启动不了了。于是想起了以前的anlinux的app,拿它与proot-distro的shell比较过,觉得它更简单,于是修改之,自己安装Canonical官方发布的arm版 ubuntu21.04,例子如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#!/data/data/com.termux/files/usr/bin/bash
folder=ubuntu-hirsute
if [ -d "$folder" ]; then
first=1
echo "skipping downloading"
fi
# 下载Canonical官方发布的 ubutnu21.04 的 rootfs
wget "https://partner-images.canonical.com/core/hirsute/current/ubuntu-hirsute-core-cloudimg-arm64-root.tar.gz"
tarball="ubuntu-hirsute-core-cloudimg-arm64-root.tar.gz"
cur=`pwd`
mkdir -p "$folder"
cd "$folder"
echo "Decompressing Rootfs, please be patient."
proot --link2symlink tar -zxvf ${cur}/${tarball}||:
cd "$cur"

mkdir -p ubuntu-binds
bin=start-hirsute.sh
echo "writing launch script"
cat > $bin <<- EOM
#!/bin/bash
cd \$(dirname \$0)
## unset LD_PRELOAD in case termux-exec is installed
unset LD_PRELOAD
command="proot"
command+=" --link2symlink"
command+=" -0"
command+=" -r $folder"
if [ -n "\$(ls -A ubuntu-binds)" ]; then
for f in ubuntu-binds/* ;do
. \$f
done
fi
command+=" -b /dev"
command+=" -b /proc"
command+=" -b ubuntu-hirsute/root:/dev/shm"
## uncomment the following line to have access to the home directory of termux
#command+=" -b /data/data/com.termux/files/home:/root"
## uncomment the following line to mount /sdcard directly to /
command+=" -b /sdcard"
command+=" -b /storage"
command+=" -w /root"
command+=" /usr/bin/env -i"
command+=" HOME=/root"
command+=" PATH=/usr/local/sbin:/usr/local/bin:/bin:/usr/bin:/sbin:/usr/sbin:/usr/games:/usr/local/games"
command+=" TERM=\$TERM"
command+=" LANG=C.UTF-8"
command+=" /bin/bash --login"
com="\$@"
if [ -z "\$1" ];then
exec \$command
else
\$command -c "\$com"
fi
EOM

echo "fixing shebang of $bin"
termux-fix-shebang $bin
echo "making $bin executable"
chmod +x $bin
echo "removing image for some space"
rm $tarball
echo "You can now launch Ubuntu with the ./${bin} script"
安装完成后,执行 ./start-hirsute.sh 进入ubuntu21.04,发现不能apt updated,后来发现是没有dns解析,于是
1
2
3
4
5
6
cd /etc
vim resolv.conf
添加
nameserver 114.114.114.114
nameserver 8.8.8.8
保存后退出
进入linux后,出现以下错误
1
2
3
4
goups: cannot find name for group ID 3003
groups: cannot find name for group ID 9997
goups: cannot find name for group ID 20xxx
groups: cannot find name for group ID 50xxx

这是由于termux安装ubuntu后没有给原本Android的系统用户组赋予名称导致的。由于每次在不同设备上安装termux.apk分配的u0_id (whoamis查到是u0_axxx)中的id值是不同的,这个需要每次改一下
解决方法:
1.用startubuntu进入系统su
2.执行以下命令

1
2
3
4
$ addgroup --system --gid 3003 inet
$ addgroup --system --gid 9997 sdcard_rw
$ addgroup --system --gid 50xxx all_axxx
$ reset

streamlit学习笔记五-----暂称全局变量吧

在编写一个streamlit代码时,发现有一个变量会在几个函数中使用,可是可这个变量如果定义在外的话,每个函数调用改变它后,虽的函数再调用,这个变量并不是上次改过的值,值还是初始化时赋的值。比如 代码一
1
2
3
4
5
6
7
8
9
10
11
12
import streamlit as st

st.title('代码一例子')
count = 0

increment = st.button('增加')
if increment:
count += 1

st.write('Count = ', count)

# 这个代码执行后,不管你咋按那个按钮,count都是1。
肿么才能避免呢? 采用 st.session_state,streamlit把它叫做 ”会话状态“
1
2
3
4
5
6
7
8
9
10
import streamlit as st

# 检查 'key' 是否存在于 session_state 中
# 如果不存在,则初始化之
if 'key' not in st.session_state:
st.session_state['key'] = 'value'

# 另一种语法
if 'key' not in st.session_state:
st.session_state.key = 'value'

一. 采用 “会话状态”,那么代码一可以改为代码二

1
2
3
4
5
6
7
8
9
10
11
12
import streamlit as st

st.title('代码一改为代码二')
# 检查 'count' 是否在 session_state中
if 'count' not in st.session_state:
st.session_state.count = 0

increment = st.button('增加')
if increment:
st.session_state.count += 1

st.write('Count = ', st.session_state.count)

二. 使用 “会话状态” 与 “回调函数” 来修改代码一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import streamlit as st

st.title('采用回调来更改代码一')
# 检查 'count' 是否在 session_state中
if 'count' not in st.session_state:
st.session_state.count = 0

# 定义函数,一会儿就要回调它
def increment_counter():
st.session_state.count += 1

# 在 st.button里回调函数 increment_counter()
st.button('Increment', on_click=increment_counter)

st.write('Count = ', st.session_state.count)

三. 以上的回调函数是木有参数的,那么如果有参数呢?

1. 使用 args 小部件来传递参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import streamlit as st

st.title('回调函数有参数')
if 'count' not in st.session_state:
st.session_state.count = 0

increment_value = st.number_input('输入一个数值', value=0, step=1)

# 函数有参数
def increment_counter(increment_value):
st.session_state.count += increment_value
# 采用 args 把参数导入
increment = st.button('Increment', on_click=increment_counter,
args=(increment_value, ))

st.write('Count = ', st.session_state.count)
2. 使用 kwargs 传递命名参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import streamlit as st

st.title('回调参数用 kwargs 传递参数')
if 'count' not in st.session_state:
st.session_state.count = 0

def increment_counter(increment_value=0):
st.session_state.count += increment_value

def decrement_counter(decrement_value=0):
st.session_state.count -= decrement_value

st.button('Increment', on_click=increment_counter,
kwargs=dict(increment_value=5))

st.button('Decrement', on_click=decrement_counter,
kwargs=dict(decrement_value=1))

st.write('Count = ', st.session_state.count)

四. 会话状态(全局变量)与 小部件中的值关联,采用 “key” 参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import streamlit as st

if "celsius" not in st.session_state:
# set the initial default value of the slider widget
st.session_state.celsius = 50.0

st.slider(
"Temperature in Celsius",
min_value=-100.0,
max_value=100.0,
key="celsius" # 采用 key 把slider小部件中的值与全局变量celsius关联
)

# This will get the value of the slider widget
st.write(st.session_state.celsius)

flask全局变量三,视图间的参数传递

在”flask全局变量一“,时,我讲了采用session[“变量名”],来定义全局变量,实现在视图间传递变量。现在用用另一名方法,用上下文的方法,采用g变量,来定义全局变量。比方法一要简单
有几个上下文装饰器
装饰器名 方式
@app.before_request 函数会在请求处理之前被调用
@app.after_request 函数会在请求处理完成后才被调用
@app.teardown_request 函数会在请求处理完成后才被调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from flask import Flask
from flask import g, request

app=Flask(__name__)

@app.before_request
def span_num_init():
g.start_num = 0 # 定义g变量
g.span_mum = 5 # 定义g变量

@app.route("/fun1")
def fun1():
g.start_num=9
g.span_num=16

@app.route("/fun2")
def fun2():
print("start_num=",g.start_num) # 此处start_num又变为0
print("span_num=",g.span_num]) # 此处start_num又变为5

flask全局变量二,自定义上下文参数

如果我要在模板中一个多选菜单的项目是个变量。那么要每个视图函数读一次变量,再发送到模版中去。比如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
def get_option_item():
item = ["项目1""项目2""项目3""项目4""项目5""项目6""项目7",]
return item
#视图1
@app.route(/index1)
def index1():
item=get_option_item()
return render_template("index1.html", item=itme)
....
#视图n
@app.route(/index_n)
def index_n():
item=get_option_item()
return render_template("indexn.html", item=itme)

在模板中

1
2
3
4
5
<select>
{% for select_i in item %}
<option> select_i </option>
{% endfor %}
</select>
每个视图要读一次很烦,那么采用上下文变量的方式就很好的解决了这个问题。修改一下python代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# current_app对象是一个定义在应用上下文中的代理
from flask import current_app
app=Flask(__name__)

# 函数用@app.context_processor装饰器修饰,它是一个上下文处理器,它的作用是在模板被渲染前运行其所修饰的函数,并将函数返回的字典导入到模板上下文环境中,与模板上下文合并。
@app.context_processor
def get_option_item():
item = ["项目1""项目2""项目3""项目4""项目5""项目6""项目7",]
return dict(item=item) #注意是字典
# 视图函数不用再调用了
#视图n
@app.route(/index_n)
def index_n():
# item=get_option_item()
return render_template("indexn.html")
模板不用改变,直接就可用了。

streamlit学习笔记五-----多个小部件分组

默认情况下,每次用户与您的streamlit应用(表单)交互时,Streamlit 都会重新运行您的脚本。然而,有时在实际重新运行脚本之前等待一组相关的小部件(表单项)被填充完后,再执行更好,这里st.form()诞生了。

格式

st.form(key: str, clear_on_submit: bool = False)
key: 字符串,表示这个表单的标识
clear_on_submit:布而值,如果为 True,则在用户按下提交按钮后,表单内的所有小部件都将重置为其默认值。

一 with用法
1
2
3
4
5
6
7
8
9
10
11
12
with st.form("my_form"):
st.write("Inside the form")
slider_val = st.slider("Form slider")
checkbox_val = st.checkbox("Form checkbox")

# 每一个form必须有一个 submit 按钮.
submitted = st.form_submit_button("Submit")
if submitted:
st.write("slider", slider_val, "checkbox", checkbox_val)

st.write("己通退了表单j")

二 指名用法
1
2
3
4
5
6
7
8

form23 = st.form("my_form")
form23.slider("Inside the form")
st.slider("在此表单外面了")

# 增加一个submit按钮到此表单:
form23.form_submit_button("Submit")

flask 的form学习之三,一个小form

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class MockCreate(Form):
user_email = StringField("email address",[validators.Email()])
api = StringField("api",[Required()])
submit = SubmitField("Submit")
code = IntegerField("code example: 200",[Required()])
alias = StringField("alias for api")
data = TextAreaField("json format",[Required()])


@app.route("/mockservice",methods=['GET','POST'])
def MockController():
form = MockCreate()
code = form['code']
api = form['api']
return render_template("testf.html",api=api,data=code)

flask 的form学习之二,Flask-WTF

使用 Flask-WTF的好处是直接在python中定义表单中的字段,比较直观

1
$ pip install flask-WTF

一. WTForms支持的全部HTML标准字段

字段对象 说明 相当于html的语句
StringField 文本字段
TextAreaField 多行文本字段
PasswordField 密码字段
HiddenField 隐藏文件字段
DateField 文本字段,值为datetime.date文本格式
DateTimeField 文本字段,值为datetime.datetime文本格式
IntegerField 文本字段,值为整数
DecimalField 文本字段,值为decimal.Decimal数
FloatField 文本字段,值为浮点数
BooleanField 复选框,值为True或False <input type=”radio”
RadioField 一组单选框
SelectField 下接列表
SelecMultipleField 可选择多个值的下接列表
FileField 文件上传
SubmitField 表单提交按钮
FormField 把表单做为字段嵌入另一个表单
FieldList 一组指定类型的字段

二 python代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
from flask import Flask
from flask import render_template
from flask_wtf import FlaskForm
from wtforms.fields import (StringField, PasswordField, DateField, BooleanField,
SelectField, SelectMultipleField, TextAreaField,
RadioField, IntegerField, DecimalField, SubmitField)
from wtforms.validators import DataRequired, InputRequired, Length, Email, EqualTo, NumberRange


app = Flask(__name__)
app.secret_key = 'asdfs'


class WtfForm(FlaskForm):
# StringField 文本输入框,必填,用户名长度为4到25之间,占位符
username = StringField('用户名:', validators=[Length(min=4, max=25)], render_kw={'placeholder': '请输入用户名'})

# Email格式
email = StringField('邮箱地址:', validators=[Email()], render_kw={'placeholder': '请输入邮箱地址'})

# PasswordField,密码输入框,必填
password = PasswordField('密码:', validators=[DataRequired()], render_kw={'placeholder': '请输入密码'})

# 确认密码,必须和密码一致
password2 = PasswordField('确认密码:', validators=[InputRequired(), EqualTo('password', '两次密码要一致')])

# IntegerField,文本输入框,必须输入整型数值,范围在16到70之间
age = IntegerField('年龄:', validators=[NumberRange(min=16, max=70)])

# DecimalField,文本输入框,必须输入数值,显示时保留一位小数
height = DecimalField('身高(cm):', places=1)

# DateField,文本输入框,必须输入是"年-月-日"格式的日期
birthday = DateField('出生日期:', format='%Y-%m-%d')

# RadioField,单选框,choices里的内容会在ul标签里,里面每个项是(值,显示名)对
gender = RadioField('性别:', choices=[('0', '男'), ('1', '女')], validators=[DataRequired()])

# SelectField,下拉单选框,choices里的内容会在Option里,里面每个项是(值,显示名)对
job = SelectField('职业:', choices=[
('teacher', '教师'),
('doctor', '医生'),
('engineer', '工程师'),
('lawyer', '律师')
])

# Select类型,多选框,choices里的内容会在Option里,里面每个项是(值,显示名)对
hobby = SelectMultipleField('爱好:', choices=[
('0', '吃饭'),
('1', '睡觉'),
('2', '敲代码')
])

# TextAreaField,段落输入框
description = TextAreaField('自我介绍:', validators=[InputRequired()], render_kw={'placeholder': '例:小明,18岁,未婚找女友'})

# BooleanField,Checkbox类型,加上default='checked'即默认是选上的
accept_terms = BooleanField('是否接受上述条款', default='checked', validators=[DataRequired()])

# SubmitField,Submit按钮
submit = SubmitField('提交')


@app.route('/', methods=['POST', 'GET'])
def index():
form = WtfForm()
return render_template('wtf.html', form=form)

if __name__ == "__main__":
app.run(debug=True)

三. html代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="">
{{ form.csrf_token }}
{{ form.username.label }}{{ form.username }}
<br>
{{ form.email.label }}{{ form.email }}
<br>
{{ form.password.label }}{{ form.password }}
<br>
{{ form.password2.label }}{{ form.password2 }}
<br>
{{ form.age.label }}{{ form.age }}
<br>
{{ form.height.label }}{{ form.height }}
<br>
{{ form.birthday.label }}{{ form.birthday }}
<hr>
{{ form.gender.label }}{{ form.gender }}
<br>
{{ form.job.label }}{{ form.job }}
<br>
{{ form.hobby.label }}{{ form.hobby }}
<br>
{{ form.description.label }}{{ form.description }}
<br>
{{ form.accept_terms.label }}{{ form.accept_terms }}
<br>
{{ form.submit }}
<br>

</form>
</body>
</html>

flask全局变量一,视图间的参数传递

提出的问题:

flask视图间如何传递变量呢?开始我用的全局变量,如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from flask import Flask,request,render_template

app=Flask(__name__)

app.secret_key = '就得是要一个key' # 必须有
app.config['SESSION_TYPE'] = 'filesystem' # 必须有

start_num=0
span_num=5

@app.route("/fun1")
def fun1():
start_num=9
span_num=16

@app.route("/fun2")
def fun2():
print("start_num=",start_num) #此处start_num又变为0
print("span_num=",span_num]) #此处start_num又变为5

在执行视图fun2时, session[“start_num”]与session[“span_num”]的值又变为初始值了。
咋整呢?

网上找到一种办法是 session法。修改代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from flask import Flask,request,render_template
from flask import session

app=Flask(__name__)

app.secret_key = '我的key'
app.config['SESSION_TYPE'] = 'filesystem'

session["start_num"]=0
session["span_num"]=5

@app.route("/fun1")
def fun1():
session["start_num"]=9
session["span_num"]=16

@app.route("/fun2")
def fun2():
print("session["start_num"]",session["start_num"]) #此处session["start_num"]又变为9
print("session["span_num"]",session["span_num"]) #此处session["start_num"]又变为16
还有一种办法就是把两个临时值传到数据库,或保存为json数据,存入文件中,程序不难,但是如果参数频繁改变的话,要反复读写文件就不好玩了。