目录

1.用户模型的创建

2.Marshmallow模块

3.MarshMallow基本构造器:Schema

  1.基于Schema完成数据序列化转换

  2.基于Schema完成数据反序列化转换

  3.反序列化阶段对数据进行校验

1.用户模型的创建

我们当前开发的项目属于社交类型项目,所以关于用户的信息和功能直接贯穿了整个项目。所以此处实现用户模块功能,我们先把用户基本信息构建起来,并通过基本信息实现用户注册登录相关功能,后面遇到业务再继续扩展。

1.创建用户蓝图/注册用户蓝图/添加总路由

cd application/apps
python ../../manage.py blue -n users

application/settings/dev.py

# 注册蓝图
INSTALLED_APPS = [
"application.apps.home",
"application.apps.users",
]

application/urls.py

from application.utils import include
urlpatterns = [
include("","home.urls"),
include("/users","users.urls"), # ***
]

2.用户相关模型

1.公共模型:BaseModel

application/model/utils.py

from application import db
from datetime import datetime
class BaseModel(db.Model):
"""公共模型"""
__abstract__ = True # 抽象模型
id = db.Column(db.Integer, primary_key=True, comment="主键ID")
name = db.Column(db.String(255), default="", comment="名称/标题")
is_deleted = db.Column(db.Boolean, default=False, comment="逻辑删除")
orders = db.Column(db.Integer, default=0, comment="排序")
status = db.Column(db.Boolean, default=True, comment="状态(是否显示,是否激活)")
created_time = db.Column(db.DateTime, default=datetime.now, comment="创建时间")
updated_time = db.Column(db.DateTime, default=datetime.now, onupdate=datetime.now, comment="更新时间") def __repr__(self):
return "<%s: %s>" % (self.__class__.__name__, self.name)

2.用户模型:User/UserProfile

application/apps/users/models.py

from application.utils.models import BaseModel,db
from werkzeug.security import generate_password_hash, check_password_hash class User(BaseModel):
"""用户基本信息表"""
__tablename__ = "mf_user"
name = db.Column(db.String(255), index=True, comment="用户账户")
nickname = db.Column(db.String(255), comment="用户昵称")
_password = db.Column(db.String(255), comment="登录密码")
age = db.Column(db.SmallInteger, comment="年龄")
money = db.Column(db.Numeric(7,2), comment="账户余额")
ip_address = db.Column(db.String(255), default="", index=True, comment="登录IP")
intro = db.Column(db.String(500), default="", comment="个性签名")
avatar = db.Column(db.String(255), default="", comment="头像url地址")
sex = db.Column(db.SmallInteger, default=0, comment="性别" ) # 0表示未设置,保密, 1表示男,2表示女
email = db.Column(db.String(32), index=True, default="", nullable=False, comment="邮箱地址")
mobile = db.Column(db.String(32), index=True, nullable=False, comment="手机号码")
unique_id = db.Column(db.String(255), index=True, default="", comment="客户端唯一标记符")
province = db.Column(db.String(255), default="", comment="省份")
city = db.Column(db.String(255), default="", comment="城市")
area = db.Column(db.String(255), default="", comment="地区")
info = db.relationship('UserProfile', backref='user', uselist=False) @property
def password(self):
return self._password @password.setter
def password(self, rawpwd):
"""密码加密"""
self._password = generate_password_hash(rawpwd) def check_password(self, rawpwd):
"""验证密码"""
return check_password_hash(self.password, rawpwd) class UserProfile(BaseModel):
"""用户详情信息表"""
__tablename__ = "mf_user_profile"
user_id = db.Column(db.Integer,db.ForeignKey('mf_user.id'), comment="用户ID")
education = db.Column(db.Integer, comment="学历教育")
middle_school = db.Column(db.String(255), default="", comment="初中/中专")
high_school = db.Column(db.String(255), default="", comment="高中/高职")
college_school = db.Column(db.String(255), default="", comment="大学/大专")
profession_cate = db.Column(db.String(255), default="", comment="职业类型")
profession_info = db.Column(db.String(255), default="", comment="职业名称")
position = db.Column(db.SmallInteger, default=0, comment="职位/职称")
emotion_status = db.Column(db.SmallInteger, default=0, comment="情感状态")
birthday =db.Column(db.DateTime, default="", comment="生日")
hometown_province = db.Column(db.String(255), default="", comment="家乡省份")
hometown_city = db.Column(db.String(255), default="", comment="家乡城市")
hometown_area = db.Column(db.String(255), default="", comment="家乡地区")
hometown_address = db.Column(db.String(255), default="", comment="家乡地址")
living_province = db.Column(db.String(255), default="", comment="现居住省份")
living_city = db.Column(db.String(255), default="", comment="现居住城市")
living_area = db.Column(db.String(255), default="", comment="现居住地区")
living_address = db.Column(db.String(255), default="", comment="现居住地址")

执行数据库迁移命令

cd ../..  # 切换工作目录会到项目根目录,manage.py所在目录下
python manage.py db init
python manage.py db migrate -m "users table"
python manage.py db upgrade

3.注册功能的实现:手机号码唯一性验证接口

在开发中,针对客户端提交的数据进行验证或提供模型数据转换格式成字典给客户端。可以使用Marshmallow模块来进行。

下面我们来了解一下Marshmallow模块.

2.Marshmallow模块

1.Marshmallow介绍

官方文档:https://marshmallow.readthedocs.io/en/latest/

Marshmallow,中文译作:棉花糖。是一个轻量级的数据格式转换的模块,也叫序列化和反序列化模块,常用于将复杂的orm模型对象与python原生数据类型之间相互转换。marshmallow提供了丰富的api功能。如下:

  1. Serializing

    序列化[可以把数据对象转化为可存储或可传输的数据类型,例如:objects/object->list/dict,dict/list->string]

  2. Deserializing

    反序列化器[把可存储或可传输的数据类型转换成数据对象,例如:list/dict->objects/object,string->dict/list]

  3. Validation

    数据校验,可以在反序列化阶段,针对要转换数据的内容进行类型验证或自定义验证。

Marshmallow本身是一个单独的库,基于我们当前项目使用框架是flask并且数据库ORM框架使用SQLAlchemy,所以我们可以通过安装flask-sqlalchemy和marshmallow-sqlalchemy集成到项目就可以了。

2.基本安装和配置

1.模块安装

pip install -U marshmallow-sqlalchemy
pip install -U flask-sqlalchemy
pip install -U flask-marshmallow

2.模块初始化

import os

from flask_marshmallow import Marshmallow
...
# 数据转换器的对象创建
ma = Marshmallow() def init_app(config_path):
...
# 数据转换器的初始化
ma.init_app(app)

3.创建一个marsh蓝图模块

为了方便学习和使用Marshllow, 我们单独创建一个蓝图来验证这个模块的基本使用.

cd application/apps
python ../../manage.py blue -n marsh
    INSTALLED_APPS = [
"application.apps.home",
"application.apps.users",
"application.apps.marsh",
]
from application.utils import include
urlpatterns = [
include("","home.urls"),
include("/users","users.urls"),
include("/marsh","marsh.urls"),
]

3.MarshMallow基本构造器:Schema

marshmallow转换数据格式主要通过构造器类来完成,而Schema类提供了数据转换的基本功能:序列化,验证和反序列化。所以在使用marshmallow的过程中所有的构造器类必须直接或间接继承于Schema基类

1.基于Schema完成数据序列化转换

1.序列化单个数据对象

application/apps/marsh/urls.py

from . import views
from application.utils import path
urlpatterns = [
path("", views.index),
]

application/apps/marsh/views.py

from marshmallow import Schema,fields
from application.apps.users.models import User,UserProfile
class UserSchema(Schema):
name = fields.String()
age = fields.Integer()
email = fields.Email()
money = fields.Number()
class Meta:
fields = ["name","age","money","email","info"]
ordered = True # 转换成有序字典 def index():
"""序列化"""
"""单个模型数据的序列化处理"""
user1 = User(name="xiaoming", password="123456", age=16, email="333@qq.com", money=31.50) data1 = UserSchema().dump(user1) # 将模型类对象序列化为字典dict格式 data2 = UserSchema().dumps(user1) # 把模型对象转换成json字符串格式
return "ok"

2.序列化多个数据对象

在前面进行的序列化操作属于序列化单个数据对象, MarshMallow中也可以进行多个数据对象的序列化.

application/apps/marsh/views.py

from marshmallow import Schema,fields
from application.apps.users.models import User,UserProfile class UserSchema(Schema):
name = fields.String()
age = fields.Integer()
email = fields.Email()
money = fields.Number()
class Meta:
fields = ["name","age","money","email","info"]
ordered = True # 转换成有序字典 def index():
"""序列化"""
"""多个模型数据的序列化"""
user1 = User(name="xiaoming", password="123456", age=15, email="333@qq.com", money=31.50)
user2 = User(name="xiaohong", password="123456", age=16, email="333@qq.com", money=31.50)
user3 = User(name="xiaopang", password="123456", age=17, email="333@qq.com", money=31.50)
data_list = [user1,user2,user3]
data1 = UserSchema(many=True).dumps(data_list) # 注意:序列化多个数据对象要加many=True
return "ok"

3.构造器嵌套使用

application/apps/marsh/views.py

from marshmallow import Schema,fields
from application.apps.users.models import User,UserProfile
class UserProfileSchema(Schema):
education = fields.Integer()
middle_school = fields.String() class UserSchema(Schema):
name = fields.String()
age = fields.Integer()
email = fields.Email()
money = fields.Number() # only的含义是外层序列化器要内层序列化器的哪些字段
info = fields.Nested(UserProfileSchema,only=["middle_school"])
class Meta:
fields = ["name","age","money","email","info"]
ordered = True # 转换成有序字典 def index():
"""序列化"""
"""序列化嵌套使用"""
user1 = User(name="xiaoming", password="123456", age=15, email="333@qq.com", money=31.50)
user1.info = UserProfile(
education=3,
middle_school="北京师范学院附属中学白沙路分校"
)
data = UserSchema().dump(user1)
data = UserSchema().dumps(user1)
print(data)
return "ok"

2.基于Schema完成数据反序列化转换

1.反序列化时设置missing参数

from marshmallow import Schema, fields, validate, ValidationError,post_load
class UserSchema2(Schema):
name = fields.String()
sex = fields.String()
age = fields.Integer(missing=18) # 反序列化数据时,如果数据没有给age字段赋值,则age默认值为18
email = fields.Email()
mobile = fields.String() @post_load
def post_load(self, data, **kwargs):
return User(**data) def index():
user_data = {"mobile":"1331345635","name": "xiaoming", "email": "xiaoming@qq.com","sex":"abc"}
us2 = UserSchema2()
result = us2.load(user_data) # 将字典转化为模型类对象
print(type(result),result) # <class 'application.apps.users.models.User'> <User: xiaoming>
return "ok"

将user_data数据反序列化后再序列化,可以看到结果多了age:18这一项,这就是因为在schema中的age字段中设置了missing=18

2.反序列化转换/忽略部分数据

from marshmallow import Schema, fields, validate, ValidationError,post_load
class UserSchema2(Schema):
name = fields.String()
sex = fields.String()
age = fields.Integer(missing=18)
email = fields.Email() # 设置反序列化时必须要有mobile字段
mobile = fields.String(required=True) @post_load
def post_load(self, data, **kwargs):
return User(**data) def index():
user_data = {"name": "xiaoming","sex":"abc"}
us2 = UserSchema2() # 设置反序列化时可以忽略部分数据
result = us2.load(user_data,partial=True) print(result) # ==> <User xiaoming>
return "ok"

3.设置字段只在序列化或反序列化阶段才启用

from marshmallow import Schema, fields, validate, ValidationError,post_load
class UserSchema2(Schema):
name = fields.String()
sex = fields.Integer()
age = fields.Integer(missing=18)
email = fields.Email()
mobile = fields.String()
password = fields.String(load_only=True) # 设置当前字段为只写字段,只会在反序列化阶段启用 @post_load
def post_load(self, data, **kwargs):
return User(**data) def index():
user_data = {"name": "xiaoming","password":"123456","sex":1}
us2 = UserSchema2()
# 反序列化
result = us2.load(user_data)
print(result) # ==> <User xiaoming>
# 序列化
us3 = UserSchema2(only=["sex","name","age"]) # 限制处理的字段,也就是序列化出来只有这三个字段
result2 = us3.dump(result)
print(result2)
return "ok"
'''
class UserSchema(Schema):
name = fields.Str()
# password is
password = fields.Str(load_only=True) # 相当于只写字段 "write-only"
created_time = fields.DateTime(dump_only=True) # 相当于只读字段 "read-only"
'''

4.反序列化阶段的钩子方法

post_dump([fn,pass_many,pass_original]) 注册序列化对象后调用的方法,它会在对象序列化后被调用。

post_load([fn,pass_many,pass_original]) 注册反序列化对象后要调用的方法,它会在验证数据之后被调用。

pre_dump([fn,pass_many]) 注册序列化对象之前调用的方法,它会在序列化对象之前被调用。

pre_load([fn,pass_many]) 在反序列化对象之前,注册要调用的方法,它会在验证数据之前调用。

from marshmallow import Schema, fields, validate, ValidationError,post_load,post_dump
class UserSchema2(Schema):
name = fields.String()
sex = fields.Integer(validate=validate.OneOf([0,1,2]))
age = fields.Integer(missing=18)
email = fields.Email()
mobile = fields.String()
password = fields.String(load_only=True) # 设置当前字段为只写字段,只会在反序列化阶段启用 @post_load
def post_load(self, data, **kwargs):
return User(**data) @post_dump
def post_dump(self,data, **kwargs):
data["mobile"] = data["mobile"][:3] +"*****"+ data["mobile"][-3:]
return data def index():
user_data = {"name": "xiaoming","password":"123456","sex":1,"mobile":"133123454656"}
us2 = UserSchema2()

# 反序列化
result = us2.load(user_data)
print(result) # ==> <User xiaoming>

# 序列化
us3 = UserSchema2(only=["sex","name","age","mobile"]) # 限制处理的字段
result2 = us3.dump(result)
print(result2)
return "ok"

Tip:schema常用属性数据类型

类型 描述
fields.Dict(keys, type]] = None, values, …) 字典类型,常用于接收json类型数据
fields.List(cls_or_instance, type], **kwargs) 列表类型,常用于接收数组数据
fields.Tuple(tuple_fields, *args, **kwargs) 元组类型
fields.String(*, default, missing, data_key, …) 字符串类型
fields.UUID(*, default, missing, data_key, …) UUID格式类型的字符串
fields.Number(*, as_string, **kwargs) 数值基本类型
fields.Integer(*, strict, **kwargs) 整型
fields.Decimal(places, rounding, *, allow_nan, …) 数值型
fields.Boolean(*, truthy, falsy, **kwargs) 布尔型
fields.Float(*, allow_nan, as_string, **kwargs) 浮点数类型
fields.DateTime(format, **kwargs) 日期时间类型
fields.Time(format, **kwargs) 时间类型
fields.Date(format, **kwargs) 日期类型
fields.Url(*, relative, schemes, Set[str]]] = None, …) url网址字符串类型
fields.Email(*args, **kwargs) 邮箱字符串类型
fields.IP(*args[, exploded]) IP地址字符串类型
fields.IPv4(*args[, exploded]) IPv4地址字符串类型
fields.IPv6(*args[, exploded]) IPv6地址字符串类型
fields.Method(serialize, deserialize, **kwargs) 基于Schema类方法返回值的字段
fields.Function(serialize, Any], Callable[[Any, …) 基于函数返回值得字段
fields.Nested(nested, type, str, Callable[[], …) 外键类型

Tip:schema数据类型的常用属性

属性名 描述
default 序列化阶段中设置字段的默认值
missing 反序列化阶段中设置字段的默认值
validate 反序列化阶段调用的内置数据验证器或者内置验证集合
required 设置当前字段的必填字段
allow_none 是否允许为空
load_only 是否在反序列化阶段才使用到当前字段
dump_omly 是否在序列化阶段才使用到当前字段
error_messages 字典类型,可以用来替代默认的字段异常提示语,格式:<br>error_messages={“required”: “用户名为必填项。”}

3.反序列化阶段对数据进行校验

1.基于内置器对数据进行校验

内置验证器 描述
validate.Email(*, error) 邮箱验证
validate.Equal(comparable, *, error) 判断值是否相等
validate.Length(min, max, *, equal, error) 值长度/大小验证
validate.OneOf(choices, labels, *, error) 选项验证
validate.Range([min, max]) 范围验证
validate.Regexp(regex, bytes, Pattern][, flags]) 正则验证
validate.URL(*, relative, schemes, Set[str]]] = None, …) 验证是否为URL

Tip:Schema常用属性数据类型

from marshmallow import Schema, fields, validate, ValidationError,post_load
class UserSchema3(Schema):
name = fields.String(required=True)
sex = fields.String(required=True,error_messages={"required":"对不起,permission必须填写"})
age = fields.Integer(missing=18,validate=validate.Range(min=18,max=40,error="年龄必须在18-40之间!")) # 限制数值范围
email = fields.Email(error_messages={"invalid":"对不起,必须填写邮箱格式!"})
mobile = fields.String(required=True, validate=validate.Regexp("^1[3-9]\d{9}$",error="手机号码格式不正确"),error_messages={"Regexp":"手机格式不正确"}) @post_load
def make_user_obj(self, data, **kwargs):
return User(**data) def index3():
user_data = {"mobile":"1331345635","name": "xiaoming","age":40, "email": "xiaoming@qq.com","sex":"abc"}
us2 = UserSchema3()
result = us2.load(user_data)
result2 = us2.dumps(result)
print(result)
print(result2)
return "ok"

2.自定义验证方法

局部钩子和全局钩子,比如局部钩子对单个字段(用户名)的判断,以及全局钩子对密码,确认密码多个字段的判断

from marshmallow import Schema, fields, validate,validates, ValidationError,post_load,validates_schema

class UserSchema4(Schema):
name = fields.String(required=True)
sex = fields.String(required=True,error_messages={"required":"对不起,permission必须填写"})
age = fields.Integer(missing=18,validate=validate.Range(min=18,max=40,error="年龄必须在18-40之间!")) # 限制数值范围
email = fields.Email(error_messages={"invalid":"对不起,必须填写邮箱格式!"})
mobile = fields.String(required=True, validate=validate.Regexp("^1[3-9]\d{9}$",error="手机号码格式不正确"),error_messages={"Regexp":"手机格式不正确"})
password = fields.String(required=True, load_only=True)
password2 = fields.String(required=True, allow_none=True) @post_load
def make_user_obj(self, data, **kwargs):
return User(**data) # 局部钩子 ***
@validates("name")
def validate_name(self,data,**kwargs):
print("name=%s" % data)
if data == "root":
raise ValidationError({"对不起,root用户是超级用户!您没有权限注册!"}) # 必须有返回值
return data # 全局钩子 ***
@validates_schema
def validate(self,data,**kwargs):
print(data)
if data["password"] != data["password2"]:
raise ValidationError("密码和确认密码必须一样!") data.pop("password2")
return data def index():
user_data = {"password":"12345","password2":"123456","mobile":"13313345635","name": "root1","age":40, "email": "xiaoming@qq.com","sex":"abc"}
us2 = UserSchema4()
result = us2.load(user_data)
print(result)
return "ok"

类型
描述
fields.Dict(keys, type]] = None, values, …)
字典类型,常用于接收json类型数据
fields.List(cls_or_instance, type], **kwargs)
列表类型,常用于接收数组数据
fields.Tuple(tuple_fields, *args, **kwargs)
元组类型
fields.String(*, default, missing, data_key, …)
字符串类型
fields.UUID(*, default, missing, data_key, …)
UUID格式类型的字符串
fields.Number(*, as_string, **kwargs)
数值基本类型
fields.Integer(*, strict, **kwargs)
整型
fields.Decimal(places, rounding, *, allow_nan, …)
数值型
fields.Boolean(*, truthy, falsy, **kwargs)
布尔型
fields.Float(*, allow_nan, as_string, **kwargs)
浮点数类型
fields.DateTime(format, **kwargs)
日期时间类型
fields.Time(format, **kwargs)
时间类型
fields.Date(format, **kwargs)
日期类型
fields.Url(*, relative, schemes, Set[str]]] = None, …)
url网址字符串类型
fields.Email(*args, **kwargs)
邮箱字符串类型
fields.IP(*args[, exploded])
IP地址字符串类型
fields.IPv4(*args[, exploded])
IPv4地址字符串类型
fields.IPv6(*args[, exploded])
IPv6地址字符串类型
fields.Method(serialize, deserialize, **kwargs)
基于Schema类方法返回值的字段
fields.Function(serialize, Any], Callable[[Any, …)
基于函数返回值得字段
fields.Nested(nested, type, str, Callable[[], …)
外键类型

day100:MoFang:用户模型类的创建&Marshmallow模块&使用基本构造器Schema完成数据的序列化转换和反序列化转换的更多相关文章

  1. Django商城项目笔记No.3用户部分-用户模型类

    Django商城项目笔记No.3用户部分-用户模型类 Django提供了认证系统,文档资料https://yiyibooks.cn/xx/Django_1.11.6/topics/auth/index ...

  2. 【Python-Django定义用户模型类】Python-Django定义用户模型类详解!!!

    定义用户模型类 1. Django默认用户认证系统 Django自带用户认证系统 它处理用户账号.组.权限以及基于cookie的用户会话. Django认证系统位置 django.contrib.au ...

  3. Django(三) 模型:ORM框架、定义模型类并创建一个对应的数据库、配置Mysql数据库

    一.模型概述 https://docs.djangoproject.com/zh-hans/3.0/intro/tutorial02/ https://www.runoob.com/django/dj ...

  4. django之模型类在视图中的应用

    一:模型类直接从把前端表单传入的值,进行存储. @csrf_exempt def regist(request): if request.method == 'POST': form = UserFo ...

  5. Django 入门案例开发(下)——创建项目应用及模型类

    前面两章是在已经开发好的项目上用来描述环境和业务,这一章创建一个全新的项目来用作开发,你可以跟着我的步骤进行开发,如果有不理解的地方可以给我留言. 今天的任务是创建好项目和用户(users)应用及让它 ...

  6. Django 入门项目案例开发(下)——创建项目应用及模型类

    关注微信公众号:FocusBI 查看更多文章:加QQ群:808774277 获取学习资料和一起探讨问题. 前面两章是在已经开发好的项目上用来描述环境和业务,这一章创建一个全新的项目来用作开发,你可以跟 ...

  7. Ruby on Rails Tutorial 第六章 用户模型

    1.用户模型(1)数据库迁移Rails默认使用关系数据库存储数据,数据库中的表有数据行组成,每一行都有相应的列,对应数据属性.把列名命名为相应的名字后,ActiveRecord会自动把他们识别为用户对 ...

  8. 5 项目---自定义用户模型以及轮播图图片url返回格式

    创建自定义的用户模型类  1. 用命令创建users 应用 2. 将users 注册到settings.py INSTALLED_APPS = [ 'django.contrib.admin', 'd ...

  9. Python实现一个ORM模型类

    ORM是三个单词首字母组合而成,包含了Object(对象-类),Relations(关系),Mapping(映射).解释过字面意思,但ORM的概念仍然模糊.私以为要理解一个事物,最好的法子是搞明白它出 ...

随机推荐

  1. 浅谈 Tarjan 算法

    目录 简述 作用 Tarjan 算法 原理 出场人物 图示 代码实现 例题 例题一 例题二 例题三 例题四 例题五 总结 简述 对于初学 Tarjan 的你来说,肯定和我一开始学 Tarjan 一样无 ...

  2. 简单操作elasticsearch(es版本7.6)

    简单操作elasticsearch(es版本7.6) es 官方文档 https://www.elastic.co/guide/index.html 简单操作elasticsearch主要是指管理索引 ...

  3. python菜鸟教程学习1:背景性学习

    https://www.runoob.com/python3/python3-intro.html 优点 简单 -- Python 是一种代表简单主义思想的语言.阅读一个良好的 Python 程序就感 ...

  4. S5830 android 2.3.4和2.3.7

    12年元旦买的手机S5830,原机自带2.3.4的系统. 看到人家的机子2.3.6的效果稍微绚一点,动了想刷机的念头. 前两天刷了2.3.7,效果还满意,用的还舒服,感觉就是有些费电, 本来就对智能手 ...

  5. [转自王垠]完全用GNU/Linux工作,摈弃Windows低效率的工作方式

    ZT (a qinghua student's article) 我已经半年没有使用 Windows 的方式工作了.Linux 高效的完成了我所有的工作. GNU/Linux 不是每个人都想用的.如果 ...

  6. 关于“Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.”

    Consider the following: If you want an embedded database (H2, HSQL or Derby), please put it on the c ...

  7. 利用日志文件getshell

    一.包含日志文件漏洞利用概述           当我们没有上传点,并且也没有url_allow_include功能时,我们就可以考虑包含服务器的日志文件.        利用思路也比较简单,当我们访 ...

  8. fork-vfork -exit&_exit

    昨天帮人查bug,发现了一个vfork fork exit  _exit不分导致的问题. 使用vfork 后调用exit导致的问题. 主要需要弄清楚他们之间的区别: 1.  fork  ():子进程拷 ...

  9. PyCharm离线安装PyQt5_tools(QtDesigner)

    目录 下载所需的whl包 安装whl 配置PyCharm 测试 下载所需的whl包 打开链接 PyPI,依此搜索 python_dotenv,PyQt5_sip,PyQt5,pyqt5_tools:基 ...

  10. C#委托的详细总结

    1.什么是委托 委托是C#中一种类型,它的作用相当于C语言中的函数指针,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用if- ...