聊聊 PC 端自动化最佳方案:Pywinauto

1. 前言

上一篇文章,聊到 PC 端的一种自动化方案:WinAppDriver

有小伙伴后台留言,说「 pywinauto 」作为 WinAppDriver 的替代方案,也能完美完成 PC 端的自动化

2. 介绍

Pywinauto,完全由 Python 构建的一个模块,可以用于自动化 Windows 上的 GUI 应用程序

同时,它支持鼠标、键盘操作,在元素控件树较复杂的界面,可以辅助我们完成自动化操作

项目地址:https://github.com/pywinauto/pywinauto

支持的应用为下面 2 大类:

  • Win32 API  

    包含 MFC、VB6、VCL、simple WinForms controls and most of the old legacy apps

  • MS UI Automation

    包含 WinForms、WPF、Store apps、Qt5, browsers

其中

win32 API 的 backend 为「 win32

MS UI Automation 的 backend 为「 uia

3. 元素控件

和 WinAppDriver 类似,在编写自动化脚本之前,我们需要先获取元素控件的各类属性值

获取元素控件有 2 种方式:

  • 窗口内置方法

  • 检查工具

其中

窗口对象内置的 2 个方法都可以打印出当前页面的元素控件树

# 窗口对象中内置方法,打印窗体内所有元素控件
# 方式一:
窗体对象.print_control_identifiers()

# 方式二
窗体对象.dump_tree()

常用的检查工具也包含 2 种,分别是:Inspect.exe、Spy++

4. 实战一下

在实战之前,我们先安装依赖包 pywinauto

# 安装依赖
pip3 install pywinauto

接下来,我们还是以上篇文章中的例子来讲解完整的实现过程

4-1  打开微信客户端

首先,通过检查工具判断应用的 backend 属性值,PC 端微信的 backend 为「 uia 」

然后,实例化一个「 Application 」类

最后,使用该对象内置的函数创建一个应用对象

import pywinauto
from pywinauto.application import Application

# 获取应用对象
# 三种方式任选一种
# 方式一:应用进程pid(连接)
app = Application(backend='uia').connect(process=pid)

# 方式二:应用完整路径(连接)
app = Application(backend='uia').connect(path="D:Program Files (x86)TencentWeChatWeChat.exe")

# 方式三:打开应用(打开)
app = Application(backend='uia').start('D:Program Files (x86)TencentWeChatWeChat.exe')

需要指出的是,获取应用对象有上面 3 种方式,可以按需使用

4-2  获取窗体对象

通过检查工具获取窗体的属性列表,然后使用应用对象 + 窗体属性获取微信首页的窗体对象

聊聊 PC 端自动化最佳方案:Pywinauto

实现代码如下:

from pywinauto.win32functions import SetFocus

# 获取窗口对象
# 通过title及ClassName获取窗体对象
self.weixin_pc_window = self.app.window(title=u"微信", class_name="WeChatMainWndForPC")

self.weixin_pc_window.set_focus()

4-3  切换到聊天列

获取左侧聊天切换按钮,获取其坐标位置,模拟点击进入到聊天列表页面

from pywinauto import mouse

def __get_element_postion(self, element):
    """获取元素的中心点位置"""
    # 元素坐标
    element_position = element.rectangle()
    # 算出中心点位置
    center_position = (int((element_position.left + element_position.right) / 2),
                           int((element_position.top + element_position.bottom) / 2))
    return center_position

def start(self):
    # 1、获取左侧【聊天】切换元素
    chat_list_element = self.weixin_pc_window.child_window(title="聊天", control_type="Button")
    # 2、点击进入到聊天列表
    mouse.click(button='left',
                    coords=self.__get_element_postion(chat_list_element))

4-4  进入聊天页面,输入内容并发送

获取「 文件聊天助手 」元素,点击进入到聊天页面,找到输入框元素,使用内置方法输入内容,最后使用键盘模拟点击「 Enter 」键,发送消息

from pywinauto import mouse

# 3、点击【文件传输助手】进入到聊天页面
file_helper_element = self.weixin_pc_window.child_window(title="文件传输助手", control_type="ListItem")

mouse.click(button='left',
                    coords=self.__get_element_postion(file_helper_element))
# 4、获取输入框元素,模拟输入
        edit_element = self.weixin_pc_window.child_window(title=r"输入", control_type="Edit")

sleep(2)
# 输入内容
edit_element.type_keys("星安果")
# 使用键盘模拟回车,即:发送
send_keys('{ENTER}')

4-5  释放资源

完成操作后,可以调用应用对象的「 kill() 」函数关闭进程,释放掉资源

def teardown(self):
    """释放资源"""
    # 结束进程,释放资源
    self.app.kill()

5. 最后

上例中使用 pywinauto 完成了一个简单的发送消息的自动化步骤

实际项目中,结合鼠标、键盘可以实现很多复杂场景的自动化

pywinauto 和 WinAppDriver 都能很好的完成 PC 端的自动化,但是由于 WinAppDriver 支持 Appium,在脚本语法简洁性方面可能更有优势

 

– EOF –

转自:https://mp.weixin.qq.com/s/3qE1T2YeyoAqpqQdZYmkIA

强无敌,用 Python 复现基于北向资金的择时策略

大家好,我是帅东哥强无敌,用 Python 复现基于北向资金的择时策略

最近自己一直在学习理财相关的东西,所以后面一段时间,可能会多分享一些这方面的学习笔记

其实在学习之前,我一直在思考一个问题:为什么我们在市场上赚不了钱?可能基金还好点,只要行情不是特别差,你一直定投总会有多多少少有点收益的,但是其他市场就真不好说了。

观察了一下身边的朋友和同事,其实大多数人都是入门的。比如说有坚信价值投资的,拿着白马一拿就是好几年的;也有观察市场热点的,追涨杀跌玩的不亦乐乎。但是大家的收益都很一般,甚至亏钱的也不少。

所以,我在思考的时候就在想 价值投资和短线热点 这事。其实价值投资没有问题,但是拿的太久就是问题;短线热点也没有问题,但是没选对具体的个股基金就是问题。

并且,我自己是研究数据分析的,是不是可以在市场的基础上加一些数据分析导向的内容?或者是在数据的基础上,偏向于热点市场的板块?

目前来看,基于上面这个问题的思考,我是有一些小小的收获的。

但是我也还在学习中,今天的文章甚至后期的文章都只是一个阶段性的学习笔记,不敢说文章的方法适合于所有人。所以大家抄作业的时候也多多思考一下,毕竟方法是我的,但是钱是你的啊!


强无敌,用 Python 复现基于北向资金的择时策略

ok,说了些闲话,开始今天的正文。

今天的文章是对一个择时策略的复现,数据是基于每日大A北上资金进行的。这个策略很简单的一个应用:当市场处于持续低谷的时候,你可以加大你定投的比例;当市场开始火热一段时间了,你需要慢慢减少你定投的金额。

就像那句话:在别人贪婪的时候我恐惧,在别人空据的时候我贪婪。

以下是真正的正文:

在文章开始之前,先给大家普及一下北上资金的概念,懂的同学可以跳过去看下一节

北上资金?

在中国股市中有“南北”之称,一般“北”指的是沪深两市的股票,“南”指的是香港股票。因此,北上资金就是指从香港股票中流入大陆股市的资金,一般为香港资金以及国际资金。

从历史数据来看, 不管是长线短线,北上资金都比A股大部分投资者聪明。原因有很多,比如说:可能是外资的投资经验丰富信息渠道广,也有可能是内地部分游资通过北向资金通道进来,也就是换了一层马甲。

所以,在每天实盘的时候,大家可以关注北向资金的买入情况,偷懒一点的也可以跟着交易。但是但是但是,这里面有两个概念特别容易被大家混淆:净流入和净买入,其实它的公式很简单:

给大家解释下,外资每天买卖咱们A股都是有额度限制的,目前沪股通和深股通的额度都是每个交易日 520亿,而且是只要挂单就会占用额度,无论是否成交

所以,当日资金净流入会包含当日成交买入额和当日申报但未成交的买单金额,那么净流入金额一定会大于或等于净买入金额,这是两者最大的区别。

建议大家看北向资金的时候还是要看净买入金额,因为净流入金额只能代表北向资金的一个购买意愿,并不能代表真实交易。


常见的,一般 标准的 财经网站你应该会看到下面这种图:

强无敌,用 Python 复现基于北向资金的择时策略

强无敌,用 Python 复现基于北向资金的择时策略

但是很多时候你看到的都只是一个净流入的数据,并没有直接显示净买入的数据。

其实也不是说这个数据不对,只是说净买入数据会更准确些,更能反映当前北上资金的真实情况。这个数据最准确的就是在港交所了,而且是有盘中实时动态播报的,大家可以去了解一下。


强无敌,用 Python 复现基于北向资金的择时策略

说完基础知识,再来说今天的重点:基于北向资金的择时策略实现:

其实用一句话就可以解释所谓的择时选股策略:基于指标,对指数进行择时(即判断指数方向),如果方向向上,就进行选股

下图是华泰证券研究所的一篇报告,其中提到了一个基于北上资金的择时策略。正如文章开头所说,北上资金目前作为大A的风向标,具有一定的可参考性。

而报告中通过北上资金与沪深300的相关系数,也完美阐释了这一点:

强无敌,用 Python 复现基于北向资金的择时策略

该择时策略的具体内容是这样的:

强无敌,用 Python 复现基于北向资金的择时策略

策略理解起来很容易,但是怎么实现呢?

以下源码拿去即用(除了tushare需要安装,不过我想这个不用我教了吧),算是开源分享给大家。

1. 导入相应的库
# 导入相应的库
import tushare as ts
import datetime
import pandas as pd
import numpy as np
2. 通过接口 token 链接到 tushare
# 将 token 替换成你自己的就行
token = '替换成你自己的token'
pro = ts.pro_api(token)
3. 获取交易日的日期列表
# 获取所有交易日数据
trade_date = pro.trade_cal(start_date='20180101',end_date=datetime.datetime.today().strftime('%Y%m%d'))
date_list = list(trade_date[trade_date.is_open==1]['cal_date'].values)
4. 获取北上资金的日粒度数据

因为单次请求限制为300条,所以这一步可以分多次获取

# 单次请求限制为300条,分两次获取
df_data1 = pro.moneyflow_hsgt(start_date=date_list[0:300][0], end_date=date_list[0:300][-1])
df_data2 = pro.moneyflow_hsgt(start_date=date_list[300:600][0], end_date=date_list[300:600][-1])
df_data3 = pro.moneyflow_hsgt(start_date=date_list[600:][0], end_date=date_list[600:][-1])
# 合并数据
df_data = df_data1.append([df_data2, df_data3], ignore_index=True)
df_data = df_data.sort_values('trade_date',ascending=True).reset_index(drop=True)
# 重命名
df_data = df_data.rename(columns={'ggt_ss':'港股通-上海''ggt_sz':'港股通-深圳''hgt':'沪股通''sgt':'深股通''north_money':'北向资金''south_money':'南向资金'})

资金对应的单位是 百万,为了方便查看,这里需要进行单位的转换

# 单位换算:百万->亿
df_data['港股通-上海'] = df_data['港股通-上海']*0.01
df_data['港股通-深圳'] = df_data['港股通-深圳']*0.01
df_data['沪股通'] = df_data['沪股通']*0.01
df_data['深股通'] = df_data['深股通']*0.01
df_data['北向资金'] = df_data['北向资金']*0.01
df_data['南向资金'] = df_data['南向资金']*0.01

这里有一点需要注意,因为有个别日期北上资金是无法进行交易的。例如:6月30日-7月1日香港特别行政区纪念日、重阳节、圣诞节等均会有休市情况发生。

所以,有必要剔除掉这些北上资金休市的情况。

观察数据你会发现,如果根据 北上资金=0 这个条件去筛选,那恰好某一天的买入卖出刚好相等,这种情况也会被过滤掉,这明显是不合理的。

解决方法:根据 df_data[‘沪股通’].isna() 字段是否为空进行判断,代码如下:

# 剔除北上暂停交易的交易日
df_data2 = df_data.loc[~df_data['沪股通'].isna(), :].reset_index(drop=True)

数据处理完毕之后,对应的数据应该是这个样子的:

强无敌,用 Python 复现基于北向资金的择时策略

5. 核心策略实现

再来回顾一下策略的内容:

强无敌,用 Python 复现基于北向资金的择时策略

对了,图中的 252 表示大A一年中的交易日,你没看错,就这么多

而 1.5 倍标准差则是研报中规定的,至于为什么选这个数而不是其他 1倍、2倍呢?

研报中也有解释原因:其中一共选取了10组不同的上下限标注差,并且分别进行了回测,最终 上限+1.5 下限-1.5 的年化收益率最高,达到了 37.54%

ok,既然人家已经都做过了充分的回测,那我们就直接实现拿来用就好

核心代码如下:

"""遍历每一个交易日,对北上进行分析"""
signal = '无信号'
for index, row in df_data2.iterrows():
    if index<252:
        continue
    df_data_temp = df_data2.iloc[index-252:index]
    # 计算近 252 天的平均数和标准差
    average = df_data_temp['北向资金'].sum()/252
    std = df_data_temp['北向资金'].std()
    # 计算上下限
    up_line = float(format(average + std * 1.5'.4f'))
    down_line = float(format(average - std * 1.5'.4f'))

以上分别是计算出当天(从数据开始交易日的第252天起)以前 252 天的平均值、标准差、上限和下限

剩下的就是对结果进行判断和输出就ok,代码如下:

# 判断并输出
if row['北向资金'] >= up_line:
 signal = '看多'
 print('{0}:<{1}> 北上净买入:{2}亿元,看多线:{3}亿元, 看空线:{4}亿元'.format(row['trade_date'], signal, format(row['北向资金'], '.4f'), up_line, down_line))
elif row['北向资金'] <= down_line:
 signal = '看空'
 print('{0}:<{1}> 北上净买入:{2}亿元,看多线:{3}亿元, 看空线:{4}亿元'.format(row['trade_date'], signal, format(row['北向资金'], '.4f'), up_line, down_line))

if index == df_data2.shape[0]-1:
 print('n最新数据n{0}: <{1}> n北上净买入:{2}亿元,看多线:{3}亿元, 看空线:{4}亿元n'.format(row['trade_date'], signal, format(row['北向资金'], '.4f'), up_line, down_line))

截取了输出结果的今年的部分,如下图:

强无敌,用 Python 复现基于北向资金的择时策略

可以看到,截止到目前(8月30日收盘),策略给出的观点是看空,并且是从 7月26日 起就一直看空了,直到今天也是看空阶段。

去券商网站上看一下北上资金的历史数据,图是这样的:

强无敌,用 Python 复现基于北向资金的择时策略

从7月26号之后的(图中的红箭头)该策略给出的观点就是看空,但是你仔细看一下研报给的策略条件是,人家说的是:该日北向资金流入规模,而我们通过 tushare 获取到的是:北向资金的净买入金额

因为每日的净流入较净买入大很多,所以对应的 1.5倍标准差就需要相应的改动一下。

比如说,当你改成 上限+0.8 下限-0.8,它对应的策略是这样的:

强无敌,用 Python 复现基于北向资金的择时策略

当然了,这里的 0.8 其实是我自己乱改的,并没有经过回测验证,在这只是为了说明对应的数据不同,参数也要有所调整。

感兴趣的话大家可以去回测一下净买入金额对应的不同参数的收益结果,选一个最大的结果对应的参数,然后就可以开启轻松的定投模式了。

其实,我是有回测出最优参数的,但是担心你们用我的参数到时候亏钱了输不起,目前还是不公开出来了。

建议自己多试试,投资本就没有不劳而获的东西!或许你的参数收益会比我更优呢!

推荐阅读

1. pandas100个骚操作

2. 机器学习原创系列

3. 数据科学干货下载

最后给大家分享《10本数据挖掘电子书》,包括数据分析、统计学、数据挖掘、机器学习。
现在免费分享出来,有需要的读者可以下载学习,在下面的公众号「数据挖掘工程师」里回复关键字:数据挖掘,就行。

读书:《精通Django 3 Web开发》

manage.py:命令行工具,内置多种方式与项目进行交互。

asgi.py:用于启动异步通信服务

settings.py:项目的配置文件

urls.py:项目的路由设置,设置网站的具体网址内容

wsgi.py:全称为Python Web Server Gateway Interface,即Python服务器网关接口

创建应用XXX , pythonmanage.py startapp XXX

migrations:用于生成数据迁移文件,通过数据迁移文件可自动在数据库里生成相应的数据表。

apps.py:当前App的配置信息

admin.py:用于设置当前App的后台管理功能。

models.py:定义数据库的映射类,每个类可以关联一张数据表

tests.py:自动化测试的模块

views.py:视图文件,处理功能的业务逻辑

启动项目 python manage.py runserver 8001

内置的应用功能

admin:内置的后台管理系统。

auth:内置的用户认证系统。

contenttypes:记录项目中所有model元数据(Django的ORM框架)。sessions:Session会话功能,用于标识当前访问网站的用户身份,记录相关用户信息。

messages:消息提示功能。

staticfiles:查找静态资源路径。

中间件(Middleware)是一个用来处理Django请求(Request)和响应(Response)的框架级别的钩子,它是一个轻量、低级别的插件系统,用于在全局范围内改变Django的输入和输出。

配置属性MIDDLEWARE的数据格式为列表类型,每个中间件的设置顺序是固定的,如果随意变更中间件很容易导致程序异常

SecurityMiddleware:内置的安全机制,保护用户与网站的通信安全。

SessionMiddleware:会话Session功能。

LocaleMiddleware:国际化和本地化功能。

CommonMiddleware:处理请求信息,规范化请求内容。

CsrfViewMiddleware:开启CSRF防护功能。

AuthenticationMiddleware:开启内置的用户认证系统。

MessageMiddleware:开启内置的信息提示功能。

XFrameOptionsMiddleware:防止恶意程序单击劫持。

静态资源的配置分别由配置属性STATIC_URL、STATICFILES_DIRS和STATIC_ROOT完成

新增数据

get_or_create方法,若存在返回数据表已有的数据信息,否则数据新增

update_or_create方法,若存在,则进行更新操作,否则在数据表里新增数据

数据显示视图、数据操作视图和日期筛选视图。

数据显示视图

RedirectView用于实现HTTP重定向,默认情况下只定义GET请求的处理方法。TemplateView是视图类的基础视图,可将数据传递给HTML模板,默认情况下只定义GET请求的处理方法。ListView是在TemplateView的基础上将数据以列表显示,通常将某个数据表的数据以列表表示。DetailView是在TemplateView的基础上将数据详细显示,通常获取数据表的单条数据。

数据操作视图是对模型进行操作,如增、删、改

FormView视图类使用内置的表单功能,通过表单实现数据验证、响应输出等功能,用于显示表单数据。CreateView实现模型的数据新增功能,通过内置的表单功能实现数据新增。UpdateView实现模型的数据修改功能,通过内置的表单功能实现数据修改。DeleteView实现模型的数据删除功能,通过内置的表单功能实现数据删除。

日期筛选视图是根据模型里的某个日期字段进行数据筛选的,然后将符合结果的数据以一定的形式显示在网页上。

Django模板引擎的解析过程

使用CSRF防护功能,首先在配置文件settings.py中设置CSRF防护功能。

表单设有隐藏控件csrfmiddlewaretoken,隐藏控件是由模板语法{% csrf_token %}生成的

取消表单的CSRF防护,那么可以在模板文件上删除{% csrf_token %},并且在对应的视图函数中添加装饰器@csrf_exempt

取消整个网站的CSRF防护,那么可以在settings.py的MIDDLEWARE注释的CSRF中间件CsrfViewMiddleware

对某些请求设置CSRF防护,那么可以在模板文件上添加模板语法{%csrf_token %},然后在对应的视图函数中添加装饰器@csrf_protect实现

创建static文件夹 python manage.py collectstatic

如果将Django设为调试模式(DEBUG=True),那么项目运行时将读取项目的pstatic文件夹的静态资源。

如果将Django设为调试模式(DEBUG=True),那么项目运行时将读取项目的pstatic文件夹的静态资源。

Django数据导入导出神器django-import-export使用教程

顾名思义,django-import-export是一个用于处理导入和导出数据的库。它支持多种格式,包括xls、csv、json、yaml以及tablib支持的所有其他格式。它还可以轻松与Django管理后台集成,使用起来非常方便。

安装插件

使用PIP安装

pip install django-import-export

更新settings.py:

INSTALLED_APPS = (
    ...
    'import_export',
)

还有一个可选的配置,我通常这样添加:

IMPORT_EXPORT_USE_TRANSACTIONS = True

默认值为False。它确定库是否会在数据导入中使用数据库事务,以确保安全。

编写资源Resources

django-import-export库使用Resource的概念,它的类定义非常类似于Django处理模型表单和管理类的方式。

在文档中,作者建议将与资源相关的代码放在admin.py文件。但是,如果实现与Django admin没有关系,我通常更喜欢在app文件夹里创建一个名为resources.py。

models.py

from django.db import models
class Person(models.Model):    name = models.CharField(max_length=30)    email = models.EmailField(blank=True)    birth_date = models.DateField()    location = models.CharField(max_length=100, blank=True)

resources.py

from import_export import resourcesfrom .models import Person
class PersonResource(resources.ModelResource):    class Meta:        model = Person

这是最简单的定义。您可以将几个配置传递给元类,fieldsexclude

导出数据

导出数据到CSV

from .resources import PersonResource
person_resource = PersonResource()
dataset = person_resource.export()
dataset.csv
id,name,email,birth_date,location
1,John,john@doe.com,2016-08-11,Helsinki
2,Peter,peter@example.com,2016-08-11,Helsinki
3,Maria,maria@gmail.com,2016-08-11,Barcelona
4,Vitor,vitor@freitas.com,2016-08-11,Oulu
5,Erica,erica@gmail.com,2016-08-11,Oulu

导出数据到JSON

dataset.json
[
  {"id"1"name""John""email""john@doe.com""birth_date""2016-08-11""location""Helsinki"},
  {"id"2"name""Peter""email""peter@example.com""birth_date""2016-08-11""location""Helsinki"},
  {"id"3"name""Maria""email""maria@gmail.com""birth_date""2016-08-11""location""Barcelona"},
  {"id"4"name""Vitor""email""vitor@freitas.com""birth_date""2016-08-11""location""Oulu"},
  {"id"5"name""Erica""email""erica@gmail.com""birth_date""2016-08-11""location""Oulu"}
]

导出数据到YAML

dataset.yaml
- {birth_date'2016-08-11', email: john@doe.com, id: 1, location: Helsinki, name: John}
- {birth_date'2016-08-11', email: peter@example.com, id: 2, location: Helsinki, name: Peter}
- {birth_date'2016-08-11', email: maria@gmail.com, id: 3, location: Barcelona, name: Maria}
- {birth_date'2016-08-11', email: vitor@freitas.com, id: 4, location: Oulu, name: Vitor}
- {birth_date'2016-08-11', email: erica@gmail.com, id: 5, location: Oulu, name: Erica}

过滤数据

from .resources import PersonResource
from .models import Person
person_resource = PersonResource()
queryset = Person.objects.filter(location='Helsinki')
dataset = person_resource.export(queryset)
dataset.yaml
- {birth_date'2016-08-11', email: john@doe.com, id: 1, location: Helsinki, name: John}
- {birth_date'2016-08-11', email: peter@example.com, id: 2, location: Helsinki, name: Peter}

导出到CSV视图

from django.http import HttpResponsefrom .resources import PersonResource
def export(request):    person_resource = PersonResource()    dataset = person_resource.export()    response = HttpResponse(dataset.csv, content_type='text/csv')    response['Content-Disposition'] = 'attachment; filename="persons.csv"'    return response

导出到Excel视图

from django.http import HttpResponsefrom .resources import PersonResource
def export(request):    person_resource = PersonResource()    dataset = person_resource.export()    response = HttpResponse(dataset.xls, content_type='application/vnd.ms-excel')    response['Content-Disposition'] = 'attachment; filename="persons.xls"'    return response

导入数据

查看new_persons.csv的数据

name,email,birth_date,location,id
Jessica,jessica@jones.com,2016-08-11,New York,
Mikko,mikko@suomi.com,2016-08-11,Jyväskyla,

id必须存在,因为它是主键。但是它会生成,所以我们不需要指定值。

import.html

{% extends 'base.html' %}
{% block content %}
  <form method="post" enctype="multipart/form-data">
    {% csrf_token %}
    <input type="file" name="myfile">
    <button type="submit">Upload</button>
  </form>
{% endblock %}

views.py

from tablib import Datasetdef simple_upload(request):    if request.method == 'POST':        person_resource = PersonResource()        dataset = Dataset()        new_persons = request.FILES['myfile']        imported_data = dataset.load(new_persons.read())        result = person_resource.import_data(dataset, dry_run=True)  # Test the data impor        if not result.has_errors():            person_resource.import_data(dataset, dry_run=False)  # Actually import now     return render(request, 'core/simple_upload.html')

Django后台管理集成

在admin.py里使用ImportExportModelAdmin,而不是ModelAdmin

from import_export.admin import ImportExportModelAdmin
from django.contrib import admin

from .models import Person

@admin.register(Person)
class PersonAdmin(ImportExportModelAdmin):
   pass

添加之后刷新页面你就会看到导入和导出按钮。

Django数据导入导出神器django-import-export使用教程

在导入现有项目时,导入功能具有良好的差异性:

Django数据导入导出神器django-import-export使用教程

这是一个强大的Django库,你可以用它做更多的事情。比如只想有导出功能,可以使用ExportMixin。

from .models import Personfrom django.contrib import adminfrom import_export.admin import ExportMixin
class PersonAdmin(ExportMixin, admin.ModelAdmin):    resource_class = PersonResource
admin.site.register(Person, BookAdmin)

详细文档地址:https://django-import-export.readthedocs.io/en/latest/

文章来源:Django中文网 作者:夜之舞。

正确使用Python f-string格式化字符串的7个层级

f-string是Python 3.6推出的一种简单而不同的字符串格式技术,可以优雅地表达Python字符串。除非您仍在使用旧的 Python 版本,否则在格式化字符串时,f 字符串绝对应该是您的首选。因为它可以通过一个迷你语法满足您的所有要求,甚至运行字符串的表达式。本文将深入探讨这项技术从初级到深度的7个层次。在了解它们之后,您可能会成为字符串格式化大师。

正确使用Python f-string格式化字符串的7个层级

 

1. 轻松从变量显示值

使用 f 字符串只需要做两件事:

  • 在字符串前添加一个小写的f;
  • 使用f字符串中以{variable_name}插值变量.
name = 'Yang'title = 'full stack hacker'print(f'{name} is a {title}.')# Yang is a full stack hacker.

如上所示,在 f 字符串机制的帮助下,我们可以编写简单且更少的代码,以便在字符串中显示更多代码。它完美地呼应了 Python 的禅宗。

“简单总比复杂好。

2. 数字格式化

有时仅仅显示原始值可能无法满足我们的需求,但是直接修改原始变量通常不是个好主意,因为变量可能在其他地方使用。不用担心,Python f字符串还支持”格式规范迷你语言”,它使我们能够根据自己喜欢的方式在 f 字符串中格式化值,尤其是数字。

pi = 3.1415926print(f'Pi is approximately equal to {pi:.2f}')# Pi is approximately equal to 3.14
id = 1  # need to print a 3-digit numberprint(f"The id is {id:03d}")# The id is 001
N = 1000000000  # need to add separatorprint(f'His networth is ${N:,d}')# His networth is $1,000,000,000

以上示例仅显示了冰山一角。对于格式规格语法的完整列表,相应的官方文档是您最好的朋友。

3. 正确打印特殊字符

我们可以通过 f 字符串打印这些字符或其他特殊字符吗?比如{}是的,当然。但语法有点棘手。让我们来看看。

 

3.1 打印引号

正如我们所知,反斜线是常用的转义字符,用于调用对其以下字符的替代解释。对于 f 字符串,我们需要注意一条规则:在 f 字符串表达式的括号{}中不起作用

name = 'Yang'# Correct Way:print(f''{name}' is a full stack hacker.')# 'Yang' is a full stack hacker.
# 错误方式:print(f'{'name'} is a full stack hacker.')# SyntaxError: f-string expression part cannot include a backslash

3.2 打印双括号{}

用 f字符串打印{}的方法是不同的, 非常容易出bug。这次我们不能使用反斜线。

name = 'Yang'
# 1print(f'{name} is a full stack hacker.')# 'Yang' is a full stack hacker.
# 2print(f'{{name}} is a full stack hacker.')# {name} is a full stack hacker.
# 3print(f'{{{name}}} is a full stack hacker.')# {Yang} is a full stack hacker.
# 4print(f'{{{{name}}}} is a full stack hacker.')# {{name}} is a full stack hacker.
# 5print(f'{{{{{name}}}}} is a full stack hacker.')# {{Yang}} is a full stack hacker.

如上例所示,该变量是作为f-字符串的括号还是变量处理取决于其周围的括号数。如果您不知道这种奇怪的机制,则容易出现错误。

 

3.3 打印反斜线

打印反斜线很简单:只需使用双反斜线打印。但是不要将它们添加到 f 字符串表达式括号当中。

name = 'Yang'
print(f'\{name}\ is a full \stack hacker.')# Yang is a full stack hacker.
#错误的print(f'{\name\} is a full \stack hacker.')# SyntaxError: f-string expression part cannot include a backslash

4. 小心打印字典值

将字典的值应用到 f 字符串中也容易出现错误。我们必须使用不同的引号来描述字典键和 f 字符串,如下所示。如果f字符串用双引号表示,那么变量里的字典键必须用单引号。

Hacker = {'name': 'Yang'}
print(f"{Hacker['name']} is a hacker")# Yang is a hackerprint(f'{Hacker["name"]} is a hacker')# Yang is a hackerprint(f'{Hacker['name']} is a hacker')# 语法错误 SyntaxError: invalid syntaxprint(f"{Hacker["name"]} is a hacker")# 语法错误 SyntaxError: invalid syntax

如上所示,如果我们对键名和 f 字符串都使用相同的单引号或双引号, Python 会对我们的代码感到困惑, 从而报错。

 

5. 正确处理多行 F 字符串

为了使我们的代码更易读,有必要使用多行书写一长串字符。但如果是 f 字符串,不要忘记在每行之前添加f。

ame = 'Yang'
# 错误方式print(f"{name} is a hacker."      "{name} is also a top writer."      "{name} writes on Medium."      )# Yang is a hacker.{name} is also a top writer.{name} writes on Medium.
# 正确方式print(f"{name} is a hacker."      f"{name} is also a top writer."      f"{name} writes on Medium."      )# Yang is a hacker.Yang is also a top writer.Yang writes on Medium.

6. 像大师一样显示日期和时间

如果我们需要打印日期或时间,f 字符串将再次告诉我们它是多么方便:

from datetime import datetimetoday = datetime.today()print(f"Today is {today}")# Today is 2021-07-31 18:20:48.956829print(f"Today is {today:%B %d, %Y}")# Today is July 31, 2021print(f"Today is {today:%m-%d-%Y}")# Today is 07-31-2021

如上例所示,在 f 字符串的帮助下,我们可以使用我们任何喜欢的格式打印日期或时间。

7. 评估 F 字符串内的表达式

当我第一次知道 f 字符串时, 我简直不敢相信:我们可以在 f 字符串内运行 Python 表达式。如果是真的,还算是字符串吗?

 

我仔细阅读了 PEP 498,终于明白了:

F 字符串提供了一种将表达式嵌入字符串字面的方法。需要注意的是,f 字符串实际上是在运行时间评估的表达方式,而不是恒定的值。

因此,f 字符串与普通字符串不同,此功能赋予它更大的能力。例如,我们可以在它里面运行一个显示时间的功能。

from datetime import datetime
print(f"Today is {datetime.today()}")# Today is 2021-07-31 18:20:48.956829

结论

Python 中的 f-string是一个伟大的字符串格式化技术, 显示了 Python 是多么优雅。它非常强大,因为它不是一个普通的字符串,而是在运行时可以表达的字符串。对于一些特殊情况,它有特殊的规则,我们需要谨慎使用它。

 

原文:7 Levels of Using F-Strings in Python | by Yang Zhou

翻译:大江狗

转自:https://mp.weixin.qq.com/s/DMf-a2BwdXKSKAXBYEoDcw