Dust8 的博客

读书百遍其义自见

0%

问题:
启用了时区, 在原生sql中没有转换时区, 导致时间筛选不正确.

原因:
是数据库保存的是UTC的时间.

解决办法:

  1. 没有多时区用户, 直接不启用时区
  2. 启用时区, orm,表单会自动处理时区, 原生sql在执行前自己把时间转换为UTC时间
  3. 启用时区, 数据库连接配置DATABASES里面设置TIME_ZONE
  4. 启用时区, 原生sql里面使用AT TIME ZONE

因为已经有数据了, 而且不同数据库转换时间的方法不一致, 为了通用所以目前使用的是方法2

1
2
3
4
5
6
7
8
from django.utils import timezone
from django.utils.dateparse import parse_datetime

def utc_time(datetime_str):
naive = parse_datetime(datetime_str)
current_tz = timezone.get_current_timezone()
ut = naive.replace(tzinfo=current_tz).astimezone(timezone.utc)
return ut.strftime("%Y-%m-%d %H:%M:%S")

时区

当启用对时区的支持时,Django 在数据库中以 UTC 为单位存储日期时间信息,在内部使用具有时区的日期时间对象,并在模板和表单中将其转换为最终用户的时区。

aware 代表带有时区, naive 代表没有带时区.

表单的处理

在表单Field里面的clean方法把提交时间转换为带时区的时间, 同理渲染的时候还有to_current_timezone, 把数据库utc时间转换为当前时区时间.

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
# django/forms/utils.py
def from_current_timezone(value):
"""
When time zone support is enabled, convert naive datetimes
entered in the current time zone to aware datetimes.
"""
if settings.USE_TZ and value is not None and timezone.is_naive(value):
current_timezone = timezone.get_current_timezone()
try:
if not timezone._is_pytz_zone(
current_timezone
) and timezone._datetime_ambiguous_or_imaginary(value, current_timezone):
raise ValueError("Ambiguous or non-existent time.")
return timezone.make_aware(value, current_timezone)
except Exception as exc:
raise ValidationError(
_(
"%(datetime)s couldn’t be interpreted "
"in time zone %(current_timezone)s; it "
"may be ambiguous or it may not exist."
),
code="ambiguous_timezone",
params={"datetime": value, "current_timezone": current_timezone},
) from exc
return value

orm

orm 执行前也会把带有当前时区的转换为数据的时区. 每种数据库都实现了该方法.

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
# django/db/models/function/datetime.py
class Extract(TimezoneMixin, Transform):
...
def as_sql(self, compiler, connection):
sql, params = compiler.compile(self.lhs)
lhs_output_field = self.lhs.output_field
if isinstance(lhs_output_field, DateTimeField):
tzname = self.get_tzname()
sql, params = connection.ops.datetime_extract_sql(
self.lookup_name, sql, tuple(params), tzname
)



# django/db/backends/base/operations.py
def datetime_extract_sql(self, lookup_type, sql, params, tzname):
"""
Given a lookup_type of 'year', 'month', 'day', 'hour', 'minute', or
'second', return the SQL that extracts a value from the given
datetime field field_name.
"""
raise NotImplementedError(
"subclasses of BaseDatabaseOperations may require a datetime_extract_sql() "
"method"
)

参考链接

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
#!/bin/bash

# 一键安装Python

py_version=3.8.8
install_path=/usr/local

install_dependencies () {
# update the packages index
sudo apt-get update

# build dependencies
sudo apt-get build-dep python3 -y
sudo apt-get install pkg-config -y

# build all optional modules
# https://devguide.python.org/setup/#install-dependencies
sudo apt-get install -y build-essential gdb lcov pkg-config \
libbz2-dev libffi-dev libgdbm-dev libgdbm-compat-dev liblzma-dev \
libncurses5-dev libreadline6-dev libsqlite3-dev libssl-dev \
lzma lzma-dev tk-dev uuid-dev zlib1g-dev
}

install_python () {
# 国外源太慢, 可以用阿里源 https://registry.npmmirror.com/
# wget -c https://www.python.org/ftp/python/$py_version/Python-$py_version.tgz
wget -c https://registry.npmmirror.com/-/binary/python/$py_version/Python-$py_version.tgz

tar -xzf Python-$py_version.tgz -C /tmp

cd /tmp/Python-$py_version/

./configure --prefix=$install_path --enable-optimizations --with-ssl

make -j2

# 避免覆盖默认的python
sudo make altinstall
}

# http://c.biancheng.net/view/2991.html
read -p "请输入安装的python版本(例如: 3.8.8): " py_version
echo "python版本: $py_version"

install_dependencies;
install_python;

参考链接

在代码合作编写中, 可能编辑器不同, 个人写代码习惯不同, 会出现代码不美观, 严重的会导致合并代码困难. 所以需要把代码统一格式化.

editorconfig

它可以解决不同编辑器默认的格式不统一问题. 编辑器会读取该文件来设置默认文件格式.
这里可以参考 django 项目里面的设置

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
# .editorconfig
# https://editorconfig.org/

root = true

[*]
indent_style = space
indent_size = 4
insert_final_newline = true
trim_trailing_whitespace = true
end_of_line = lf
charset = utf-8

# Docstrings and comments use max_line_length = 79
[*.py]
max_line_length = 88

# Use 2 spaces for the HTML files
[*.html]
indent_size = 2

# The JSON files contain newlines inconsistently
[*.json]
indent_size = 2
insert_final_newline = ignore

[**/admin/js/vendor/**]
indent_style = ignore
indent_size = ignore

# Minified JavaScript files shouldn't be changed
[**.min.js]
indent_style = ignore
insert_final_newline = ignore

# Makefiles always use tabs for indentation
[Makefile]
indent_style = tab

# Batch files use tabs for indentation
[*.bat]
indent_style = tab

[docs/**.txt]
max_line_length = 79

[*.yml]
indent_size = 2

black 解决代码格式化问题

django 的代码现在也改用 black 格式化工具了.可以在 django 源码里面看到.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# .pre-commit-config.yaml
repos:
- repo: https://github.com/psf/black
rev: 22.3.0
hooks:
- id: black
exclude: \.py-tpl$
- repo: https://github.com/PyCQA/isort
rev: 5.10.1
hooks:
- id: isort

# setup.cfg
[isort]
profile = black
default_section = THIRDPARTY
known_first_party = django

vscode 编辑器使用 black

vscode中先打开python文件, 在右键单击就会出现格式化文档选项, 在点击格式化文档, 如果还没有安装格式化工具的, 就会出现选择哪个格式化工具, 这里我们选择 black. 安装好后在同样操作一遍, 就会自动格式化了.

命令行使用 black

因为可能文件太多,不可能一一用编辑打开来格式化.有一些命令行,非常有用.

1
2
3
4
5
# 检查格式化前后的不同
black . --check --diff

# 执行格式化
black .

isort 解决包引入格式化问题

但是默认的配置, isortblack 格式化 import 代码不一致, 导致有问题,所以需要配置 isort 来适应 black. 在前面的 .editorconfig 文件里面配置 profile = black 来统一格式.

1
2
3
4
# .editorconfig
[*.py]
max_line_length = 88
profile = black

vscode 编辑器使用 black

vscode中先打开python文件, 在右键单击就会出现Sort Imports选项, 在点击Sort Imports,就自动格式化了.

命令行使用 isort

isortblack一样有一些命令行,非常有用.

1
2
3
4
5
6
7
8
9
10
11
# isort 简单的介绍和使用
isort

# isort 详细的使用介绍
isort --help

# 检查当前目录,并列出有格式化前后不一致的地方
isort --check --diff .

# 执行格式项目
isort .

代码提交前检查

在代码提交前先检查一下 blackisort 是否全都统一格式化了. 如果有输出需要格式化的文件, 格式化后在提交.

1
2
black . --check
isort . --check

除了手动执行检查外, 还可以使用 pre-commit 工具来在提交前自动检查, 避免忘记检查. 如果检查不通过, 是提交不了的.

参考链接

dlib 是一个机器学习算法的工具库.想在python中使用它的追踪算法.由于在最新的pypidlib 已经没有上传已经编译好的 windows 版本, 最近的windows版本是 python3.6的.所以需要自己编译.

下载源码

https://github.com/davisking/dlib
打开 setup.py 文件可以看到使用方式

1
2
# 编译并安装
python setup.py install

编译需要 vs c++ , cmake 等依赖环境.本机还好, 如果在部署机上也安装依赖,就太麻烦了,所以可以编译成 whl 格式的安装包.

编译whl安装包

1
2
3
4
5
# 安装依赖
pip install twine wheel

# 编译. 这样在dist目录里面就可以看编译出的安装包
python setup.py bdist_wheel

有些cpu太老(如奔腾cpu)不支持avx指令, 编译的时候就需要指定参数

1
2
# 编译, 不使用avx指令, 并清除之前的编译文件
python setup.py bdist_wheel --no USE_AVX_INSTRUCTIONS --clean

备注

  • whl 安装包的命名是有规则的,不能乱命名.不然安装不了,报错为ERROR: **.whl is not a supported wheel on this platform

参考链接

Dockerfile 里面需要安装软件,有时国外源太慢,导致安装不了.可以通过替换 apt 源来解决

替换源

阿里源: https://developer.aliyun.com/mirror/ubuntu

修改方法

通过命令直接替换字符

1
2
RUN sed -i s@/archive.ubuntu.com/@/mirrors.aliyun.com/@g /etc/apt/sources.list
RUN apt clean

通过替换源文件

1.在该文件夹中创建sources.list文件
2.在sources.list中添加国内镜像源
3.在dockerfile中添加命令,把sources.list映射到容器内

1
ADD sources.list /etc/apt