bzsy 记录白皮书
# django 查询
# Q
Django 中 Q 查询及 Q()对象 - 听风。 - 博客园 (opens new window)
Django: 使用 Q 对象构建复杂的查询语句 - Huang Huang 的博客 (opens new window)
# 数据库迁移
多数据库 | Django 文档 | Django (opens new window)
Switch to a new Database in Django - Python Fusion (opens new window)
django 配置多个数据库,并为对应的 app 指定使用的数据库 (opens new window)
django 配置连接多个数据库,自定义表名称 - momingliu11 - 博客园 (opens new window)
Django 框架之 同时使用多个数据库 - 简书 (opens new window)
# Postman 登录
# 生成 Token
django 使用 jwt 进行身份验证 - 简书 (opens new window)
Authorization:JWT eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjo1MTUsInVzZXJuYW1lIjoiXHU5ZWM0XHU1MWUxIiwiZXhwIjoxNjE5NDA2MzgzLCJlbWFpbCI6IiJ9.dzcffx6uGRIfXTM5PXmakezu2NiZ4020ippv09VeK80
# 认证带 Token
# xadmin 与后端对应
自定用户管理对应apps/user/models.py
# 用户
系统所有用户
- admin/超级管理员
- 系统管理员/每一个系统唯一
- 普通用户/普通管理员
# 功能权限对应 URL
只有配置之后,用户点击才能跳过去,否则是白屏(应该为 403)
# 权限
每个权限对应的 url
# 组
用户组
# 用户权限
用户对应的权限(系统管理员)
# 组权限
组对应的权限
# 用户组
用户所属组
# 框架相关
# 五种 ModelMixin 类详解
- 返回所有数据列表 ListModelMixin
- 创建数据类 CreateModelMixin
- 传入参数,返回某个数据对象 RetrieveModelMixin
- 传入参数,更新数据对象 UpdateModelMixin
- 传入参数,删除某个数据对象 DestroyModelMixin
# 如何使用 Django 通用视图的 get_queryset, get_context_data 和 get_object 等方法
- get_queryset()方法,正如其名,该方法可以返回一个量身定制的对象列表。
- get_context_data,可以用于给模板传递模型以外的内容或参数,非常有用。
- get_object(),比如你希望一个用户只能查看或编辑自己发表的文章对象。当用户查看别人的对象时,返回 http 404 错误。这时候你可以通过更具体的 get_object()方法来返回一个更具体的对象。
如何使用 Django 通用视图的 get_queryset, get_context_data 和 get_object 等方法_大江狗-CSDN 博客 (opens new window)
class ShopModelSeralizer(serializers.ModelSerializer):
# 注意字段类型必须和model中相同
license = serializers.CharField()
shop_name = serializers.CharField()
shop_address = serializers.CharField()
class Meta:
model = ShopInfo
fields = ('license', 'shop_name', 'shop_address')
class ShopSeralizer(serializers.Serializer):
license = serializers.CharField(max_length=15, allow_null=False, required=True)
shop_name = serializers.CharField(max_length=100, allow_null=False, required=True)
shop_address = serializers.CharField(max_length=250, allow_null=False, required=True)
# views.py
class ShopView(mixins.ListModelMixin, viewsets.GenericViewSet):
pagination_class = AllPagination
serializer_class = ShopSeralizer
def list(self, request, *args, **kwargs):
objects = ShopInfo.objects.all()
serializer = ShopSeralizer(data=objects)
serializer.is_valid(raise_exception=True)
return Response(serializer.data)
class ShopModelView(mixins.ListModelMixin, viewsets.GenericViewSet):
def list(self, request, *args, **kwargs):
objects = ShopInfo.objects.all()
serializer = ShopModelSeralizer(objects, many=True)
return Response(serializer.data)
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
The data key is not populated until you call is_valid(). (This is a data-sanitation safety feature that stops you accessing input until you're sure it's safe.
Add the call to is_valid() and you should see your data.
Since you're deserializing though you want to access the object attribute to return you Keyboard instance.
python - Django Rest Framework serializer losing data - Stack Overflow (opens new window)
# Router 之base_name
base_name - 用于创建的 URL 名称的基本名称。如果不设置该参数,将根据视图集的 queryset 属性(如果有)来自动生成基本名称。注意,如果视图集不包括 queryset 属性,那么在注册视图集时必须设置 base_name。
只有在 viewset 中没有定义 queryset 时,Django rest 框架才需要这个base_name
。从 queryset DRF 可以读取model._meta.object_name.lower()
。(rest_framework.routers.SimpleRouter.get_default_base_name
)视图集注册表基于 refix, viewset 和 base_name(模型的)构建。
router.register(r'person/food', views.PersonViewSet, 'Person')
The default router uses the queryset defined in the serializer to determine the basename. The basename designates the start of the urls generated by the router. If the queryset is not set as a ViewSet attribute, the router throws up its hands in protest without trying to find queryset in functions. Specifying 'Person' means the internal view_name's will start with 'Person', but the url's are still specified by the first argument.
默认路由器使用序列化程序中定义的查询集来确定 basename。basename 指定路由器生成的 URL 的开头。如果没有为 ViewSet 设置 queryset 属性,则路由器会抛出异常,而不会尝试在函数中查找 queryset。 指定“ Person”表示内部 view_name 将以“Person”开头,但 url 仍由第一个参数指定。
# 存储过程
MySQL 存储过程 | 菜鸟教程 (opens new window)
# API 版本控制
Django API 版本控制 | njuCZ's blog (opens new window) 第 13 篇:DRF 框架之 API 版本管理 - 削微寒 - 博客园 (opens new window)
# 部署
# Nginx
- 启动
/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
- 重启
/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf -s reload
# uWsigi
# 启动
/usr/local/python3/bin/uwsgi -d --ini /root/xxx/mysite_uwsgi.ini
# 重启
/usr/local/python3/bin/uwsgi --reload /root/xxx/uwsgi/uwsgi.pid
# 关闭
/usr/local/python3/bin/uwsgi --stop /root/xxx/uwsgi/uwsgi.pid
# 查看服务状态
uwsgi --connect-and-read /root/xxx/uwsgi/uwsgi.status
2
3
4
5
6
7
8
如果觉得写全名称麻烦,可以使用uwsgi3
的别名去调用:
$uwsgi3 --version
2.0.17.1
$which uwsgi3
/usr/bin/uwsgi3
$ll /usr/bin/uwsgi3
lrwxrwxrwx 1 root root 28 Jan 3 2019 /usr/bin/uwsgi3 -> /usr/local/python3/bin/uwsgi
2
3
4
5
6
相关配置:uWSGI 配置文档翻译 - Ju6y - 博客园 (opens new window)
Django Nginx+uwsgi 安装配置 | 菜鸟教程 (opens new window)
如何用 uWSGI 托管 Django | Django 文档 | Django (opens new window)
How to Deploy old Django project using NGINX, Docker and UWSGI - Yasoob Khalid (opens new window)
python3 + Django + uwsgi + nginx 配置部署笔记 - SegmentFault 思否 (opens new window)
# 账号密码
# 管理员
admin
bzsy@2018!.
2
# 天津帐号
天津市、第一、第二、第三、东丽、西青、津南、北辰、塘沽、大港、武清、汉沽、宝坻、静海、蓟州、宁河
密码:bzsy1234
2
3
# 黄山
username:黄山烟草
password:hsyxzx123!
2
# 西安
帐号:西安 密码:Xayc@098
# 修改用户密码
更改用户密码---Django - 简书 (opens new window)
# 在线调试
- 改为 debug 模式
- 手动启动服务
/usr/op_virtual/op_project/bin/python manage.py runserver 0.0.0.0:9999
- 运行测试
curl -d 'username=admin' -d 'password=bzsy@2018!.' -H 'Accept: application/json; indent=4' http://127.0.0.1:9999/jwtlogin/
# get 带token 传参请求api
curl -H 'Authorization: JWT eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNjIxNTA1MzM1LCJlbWFpbCI6IjE0MUBxcS5jb20ifQ.GJ24wefi0qOmS83KH9xL2F1QAwLA1awjYUV5E9tRpiU' -X GET -d '{"product_id": "12011120", "company":"东丽", "target":"300", "f_type":"0" }' http://127.0.0.1:9999/market/api/strategy/?_t=1619691289
2
3
4
参阅:linux 下 curl get 方法传递参数 - MokeyChan - 博客园 (opens new window)
Django-filter,让过滤如此简单(2) - 知乎 (opens new window)
# 位置查坐标
# 序列化太耗时
Improve Serialization Performance in Django Rest Framework | Haki Benita (opens new window)
Web API performance: profiling Django REST framework (opens new window)
# 部署
# Nginx
# 安装
yum install nginx
# 查看运行状态
systemctl status nginx
# 启动nginx
systemctl start nginx
2
3
4
5
6
安全组开放 80 端口和 443 端口(HTTPS 可选),访问服务器公网 ip,默认 Nginx 位置/etc/nginx/nginx.conf
# 数据更新
商圈更新因为有两层循环,所以应该尽可能只更新需要的数据,而不是把所有的 shop 查出来去更新。
# 调查问卷
当题型是矩阵题的时候需要设置required=0
# 图片上传
可参考 sz_mobile 项目首页轮播头图
# 经纬度获取
#!/usr/bin/env python
# coding: utf-8
import pandas as pd
import numpy as np
import os
from sqlalchemy import create_engine
import requests
import json
import threading
import urllib
from queue import Queue
# 修改文件路径
shop_path = r'C:\Users\DELL\Desktop\2020.3.4-bj.csv'
biz_info_path = r'C:\Users\DELL\Desktop\乌鲁木齐\wulumuqishi_business_property.xlsx'
shop = pd.read_csv(shop_path)
shop = shop.rename(columns={'busi_addr':'shop_address'})
def get_latlng(queue,q_ret):
ret = list()
while not queue.empty():
data_dict = queue.get()
result = requests.get(data_dict.pop('url'))
data = json.loads(result.text)
if data.get('status') == '1' and data['geocodes']:
lng, lat = data['geocodes'][0]['location'].split(',')
data_dict['add_lng'], data_dict['add_lat'] = lng, lat
ret.append(data_dict)
else:
data_dict['add_lng'], data_dict['add_lat'] = None, None
ret.append(data_dict)
q_ret.put(ret)
return ret
# 修改城市名称
city='北京市'
data_tosql = shop.to_dict(orient='records')
url = "https://restapi.amap.com/v3/geocode/geo?address={address}&city={city}&key=262234d95584eb0b5cdeec3487a3baef"
detail_url = Queue(maxsize=10000)
q_ret = Queue()
for i in data_tosql:
url_ = url.format(address=urllib.parse.quote(i['shop_address']), city=city)
i['url'] = url_
detail_url.put(i)
threads = list()
for i in range(10):
thread_content = threading.Thread(target=get_latlng, args=(detail_url,q_ret))
thread_content.setDaemon(False)
thread_content.start()
thread_content.join()
threads.append(thread_content)
for thread in threads:
thread.join()
results = []
for _ in range(10):
results.extend(q_ret.get())
df = pd.DataFrame(results)
df.to_excel( r'C:\Users\DELL\Desktop\bj_shop_with_pos.xlsx',index=0)
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
71
72
73
参考meta项目的req.py文件
ret = get_lat_lng()
2
# 处理新户的流程
- 计算新户 biz_dist
shop.biz_dist = xxx
--> shop; - 从 excel 或者数据库(西安项目)读出来 all_shop;
- 从现有数据库(shop_info)获取旧户 old_shop;
- 判断旧户和新户数据没有重复 shop.license.isin(old_shop.license); 如果有(shop[shop.license.isin(old_shop.license)]),则需要排除再进行下一步;
- 将数据库中旧户信息读出来,和新户合并; s1 = pd.concat([old_shop,shop]).copy()
- 以现在数据为准进行合并; s = all_shop.merge(s1, how='left',on='license')
- 计算档位、区县信息,赋值省、市、license_status 信息; s['license_status']='有效' s['prevince'] = '天津市' s['city'] = '天津市'
- 更新到数据表;
# shop_info
engine.execute('truncate table shop_info'); s.to_sql('shop_info',engine, index=0, if_exists='append');
# shop_info_monthly
s['monthly'] = '202110' s.drop(columns=['company']).to_sql('shop_info_monthly',engine, index=0, if_exists='append')
# uwsgi 前缀
前后端部署在同一服务器上,使用同一个 nginx 端口,增加/api/前缀区分前后端,但后端开发时,接口均没有添加前缀/api/。可用以下方法解决
https://blog.csdn.net/weixin_38676276/article/details/120026667
{
# Django api use uwsgi
location /api/
{
# /api/hello ==> /hello
rewrite ^/api/(.*) /$1 break; #关键是这行做替换 留意最后面是 break;
include uwsgi_params;
uwsgi_pass 127.0.0.1:8001;
uwsgi_read_timeout 5;
}
# Django static
location /api/static/
{
alias /srv/Django/static/ ;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 数据库长时间不用连接超时
Python 长期连接数据库的最不佳实践:Lost connection to MySQL server during query – 土豆不好吃 (opens new window)
# pandas
# 填 NaN
dt.fillna(np.nan).replace([np.nan], [None])
# CSV 日期保存
dcp.to_csv(DT_XIAN_FP, index=0,date_format="%d/%m/%Y")