├── README.md
├── apis
├── __pycache__
│ ├── __init__.cpython-36.pyc
│ ├── base.cpython-36.pyc
│ ├── enum.cpython-36.pyc
│ ├── setting.cpython-36.pyc
│ └── urls.cpython-36.pyc
└── api_v1
│ ├── __pycache__
│ ├── __init__.cpython-36.pyc
│ ├── base.cpython-36.pyc
│ ├── enum.cpython-36.pyc
│ ├── setting.cpython-36.pyc
│ └── urls.cpython-36.pyc
│ ├── base.py
│ ├── enum.py
│ ├── setting.py
│ ├── urls.py
│ └── user
│ ├── __pycache__
│ ├── __init__.cpython-36.pyc
│ ├── json_models.cpython-36.pyc
│ ├── param_models.cpython-36.pyc
│ ├── serializers.cpython-36.pyc
│ └── views.cpython-36.pyc
│ ├── serializers.py
│ └── views.py
├── apps
├── __pycache__
│ └── __init__.cpython-36.pyc
└── user
│ ├── __init__.py
│ ├── __pycache__
│ ├── __init__.cpython-36.pyc
│ ├── admin.cpython-36.pyc
│ ├── apps.cpython-36.pyc
│ ├── models.cpython-36.pyc
│ ├── urls.cpython-36.pyc
│ └── views.cpython-36.pyc
│ ├── admin.py
│ ├── apps.py
│ ├── migrations
│ ├── 0001_initial.py
│ └── __pycache__
│ │ ├── 0001_initial.cpython-36.pyc
│ │ └── __init__.cpython-36.pyc
│ ├── models.py
│ ├── tests.py
│ ├── urls.py
│ └── views.py
├── attendances.xml
├── attendances
├── __pycache__
│ ├── __init__.cpython-36.pyc
│ ├── settings.cpython-36.pyc
│ ├── urls.cpython-36.pyc
│ ├── view.cpython-36.pyc
│ └── wsgi.cpython-36.pyc
├── settings.py
├── urls.py
└── wsgi.py
├── manage.py
├── requirements.txt
└── test.py
/README.md:
--------------------------------------------------------------------------------
1 | # Python3 开发以及部署 RESTful API项目(Python3 + Django2.0 + Django REST FrameWork + Centos7 + uWsgi + Nginx)
2 | 文档分为两个部分,分别从开发和部署两个方面先介绍项目流程,然后会说明项目中最常遇到的问题以及解决方案。如果项目中有什么处理不正确的地方,也希望大家给予指正、交流。
3 |
4 | 1. 开发环境采用Python3.6.3版本,项目采用Django2.0,Django REST FrameWork3.7.7去搭建。
5 |
6 | 2. 部署的时候,系统版本为Centos7,uWsgi版本使用本文发布时最新的2.0.15,Nginx版本1.13.7
7 |
8 | ## 第一部分 开发流程以及问题说明
9 | 由于项目本身基于 Token 的身份验证,另外有些接口不只是处理一个表里的数据,直接通过ORM不太好映射,所以并没有完全按照Django REST FrameWork进行开发,并且只采用GET和POST方法。
10 |
11 | ### 一、开发步骤
12 | 首先搭建开发环境并且创建一个新的项目。
13 | #### 1. 安装Python3:如果使用的是 Mac OS X ,系统可能已经预装了 Python 。我们可以通过homebrew安装Python3。
14 | ``` shell
15 | $ brew install python3
16 | ```
17 | 安装了Python3之后,会有pip3,使用pip install XXX 新安装的库会放在这个目录下面python2.7/site-packages使用pip3 install XXX 新安装的库会放在这个目录下面python3.6/site-packages如果使用python3执行程序,那么就不能import python2.7/site-packages中的库
18 | #### 2. 安装Django和Django REST FrameWork:可以下载django最新版本,若想指定版本,请在命令后面加上版本号。
19 | ``` shell {.line-numbers}
20 | $ pip3 install django
21 | $ pip3 install djangorestframework
22 | ```
23 | ``` shell {.line-numbers}
24 | $ pip3 install django==版本号
25 | $ pip3 install djangorestframework==版本号
26 | ```
27 | #### 3. 创建一个新的项目。
28 | ``` shell {.line-numbers}
29 | $ cd ~
30 | $ django-admin.py startproject attendances
31 | $ cd attendances
32 | $ python manage.py startapp user apps/user
33 | ```
34 | #### 4. 将新user应用和rest_framework应用添加到配置文件attendances/settings.py文件的INSTALLED_APPS。
35 | ``` python {.line-numbers}
36 | INSTALLED_APPS = (
37 | ...
38 | 'rest_framework',
39 | 'apps.user',
40 | )
41 | ```
42 | #### 5. 写接口代码前的一点准备。
43 | 做完以上步骤,我们就把项目开发需要的环境搭建完成了,接下来就可以在我们的项目中添加接口了。
44 |
45 | 另外还有一点要说明的是,为了给我们的api增加版本控制,我们的文件目录和路由是这样处理的,这样我们就可以通过添加新的版本文件并且修改配置,同时运行多个版本的接口:
46 |
47 | **文件目录结构**
48 |
49 | - > apis
50 | -
51 |
52 | - > api_v1
53 | -
54 |
55 | - > user
56 | - > base
57 | - > enum
58 | - > setting
59 | - > urls
60 |
61 |
62 |
63 |
64 | - > apps
65 | - > attendances
66 | -
67 |
68 | - > setting
69 | - > urls
70 | - > wsgi
71 |
72 |
73 | - > static
74 | - > attendances.xml
75 | - > manage.py
76 | - > requirements.txt
77 | - > test.py
78 |
79 |
80 | **路由**
81 | ``` python {.line-numbers}
82 | # 项目路由
83 | urlpatterns = [
84 | url('admin/', admin.site.urls),
85 | url(r'^api/v1/', include('apis.api_v1.urls', namespace='api-v1')),
86 | ]
87 | ```
88 | ``` python {.line-numbers}
89 | # apis下面的路由
90 | from apis.api_v1.user import views as api_user
91 |
92 | urlpatterns = [
93 | # user
94 | url(r'^user/$', api_user.user, name='user'),
95 | ]
96 |
97 | app_name = 'api-v1'
98 | ```
99 | **调用地址:** https://{Domain}/api/v1/user
100 |
101 | **请求方法:** GET-获取用户信息 POST-修改用户信息
102 |
103 | > 文件说明:apis存放的是api接口文件,app存放的是应用或者可以说是模块,attendances是项目文件存放一些项目配置,static静态文件,attendances.xml是uWsgi的配置文件,requirements.txt是一些项目相关的依赖,test.py是为了测试uWsgi是否配置成功的文件。
104 | #### 6. 创建一个可以使用的模型以及Serializer类、Django视图。
105 | **在apps/user/models.py创建User模型**
106 | ``` python {.line-numbers}
107 | """
108 | 用户模块
109 | """
110 | from django.db import models, transaction
111 |
112 | class User(models.Model):
113 | """
114 | 用户信息表
115 | """
116 | user_id = models.AutoField(primary_key=True, verbose_name='用户id')
117 | user_guid = models.CharField(max_length=150, verbose_name='用户guid')
118 | user_name = models.CharField(
119 | max_length=100, blank=True, null=True, verbose_name='用户名')
120 | real_name = models.CharField(
121 | max_length=50, blank=True, null=True, verbose_name='真实姓名')
122 | avatar = models.CharField(
123 | max_length=250, blank=True, null=True, verbose_name='头像')
124 | mobile = models.CharField(
125 | max_length=50, blank=True, null=True, verbose_name='手机')
126 | balance = models.DecimalField(
127 | max_digits=8, decimal_places=2, blank=True, null=True, verbose_name='账户余额')
128 | available_balance = models.DecimalField(
129 | max_digits=8, decimal_places=2, blank=True, null=True, verbose_name='可用金额')
130 | frozen_balance = models.DecimalField(
131 | max_digits=8, decimal_places=2, blank=True, null=True, verbose_name='冻结金额')
132 | all_balance = models.DecimalField(
133 | max_digits=8, decimal_places=2, blank=True, null=True, verbose_name='累计金额')
134 | wx_open_id = models.CharField(max_length=150, verbose_name='微信OpenID')
135 | wx_union_id = models.CharField(
136 | max_length=150, blank=True, null=True, verbose_name='微信UnionID')
137 | create_date = models.FloatField(blank=True, null=True, verbose_name='创建时间')
138 | last_login_date = models.FloatField(
139 | blank=True, null=True, verbose_name='最后登录时间')
140 | ip_address = models.CharField(
141 | max_length=50, blank=True, null=True, verbose_name='IP地址')
142 | gender = models.IntegerField(blank=True, null=True, verbose_name='性别')
143 | province = models.CharField(
144 | max_length=50, blank=True, null=True, verbose_name='省份')
145 | city = models.CharField(
146 | max_length=50, blank=True, null=True, verbose_name='城市')
147 | session_key = models.CharField(
148 | max_length=150, blank=True, null=True, verbose_name='会话秘钥')
149 | is_notify = models.IntegerField(blank=True, null=True, verbose_name='是否开启打卡通知')
150 |
151 | @classmethod
152 | def update_user_balance(cls, user_id, amount):
153 | # 手动让select for update和update语句发生在一个完整的事务里面
154 | with transaction.atomic():
155 | user = (
156 | cls.objects
157 | .select_for_update()
158 | .get(user_id=user_id)
159 | )
160 | user.available_balance += amount
161 | user.balance = user.available_balance + user.frozen_balance
162 | if amount > 0:
163 | user.all_balance += amount
164 | user.save()
165 | return user
166 |
167 | class Meta:
168 | managed = False
169 | db_table = 'user'
170 | ordering = ['-create_date']
171 | verbose_name = '用户'
172 | verbose_name_plural = '用户'
173 | ```
174 | **在apis/api_v1/user/serializers.py创建Serializer类**
175 | ``` python {.line-numbers}
176 | """
177 | 用户模块
178 | """
179 | from rest_framework import serializers
180 | from apps.user.models import User
181 | from apis.api_v1.enum import ErrorCode
182 | from apis.api_v1.base import BaseApi
183 |
184 |
185 | class GetUserSerializer(serializers.Serializer):
186 | """
187 | 获取用户信息
188 | """
189 | token = serializers.CharField(max_length=150)
190 | user_id = serializers.IntegerField()
191 |
192 | def get_user(self, validated_data):
193 | result = dict()
194 | base_api = BaseApi()
195 | # 获取用户
196 | try:
197 | user = User.objects.get(user_id=validated_data["user_id"])
198 | except User.DoesNotExist:
199 | result["error_code"] = ErrorCode.用户不存在.value
200 | result["error"] = "用户不存在"
201 | return result
202 | # 认证
203 | if not base_api.authenticate_user(validated_data["token"], user.user_guid):
204 | result["error_code"] = ErrorCode.认证错误.value
205 | result["error"] = "认证错误"
206 | return result
207 | result["nick_name"] = user.user_name
208 | result["avatar"] = user.avatar
209 | result["error_code"] = ErrorCode.正确.value
210 | result["error"] = ""
211 | return result
212 |
213 | ```
214 | **在apis/api_v1/user/view.py创建视图**
215 | ``` python {.line-numbers}
216 | """
217 | 用户模块
218 | """
219 | import json
220 | from rest_framework.decorators import api_view
221 | from rest_framework.response import Response
222 | from rest_framework import status
223 | from apis.api_v1.user.serializers import *
224 | from apis.api_v1.enum import ErrorCode
225 |
226 |
227 | @api_view(['GET', 'POST'])
228 | def user(request):
229 | """
230 | GET:获取用户信息
231 | POST:更新用户信息
232 | """
233 | if request.method == 'GET':
234 | param = dict()
235 | param["token"] = request.GET.get("token", None)
236 | param["user_id"] = request.GET.get("user_id", 0)
237 | serializer = GetUserSerializer(data=param)
238 | if serializer.is_valid():
239 | result = serializer.get_user(serializer.validated_data)
240 | return Response(result, status=status.HTTP_201_CREATED)
241 | return Response(dict(error_code=ErrorCode.参数错误.value, error=json.dumps(serializer.errors, ensure_ascii=False)), status=status.HTTP_400_BAD_REQUEST)
242 | # elif request.method == 'POST':
243 | # serializer = PostUserSerializer(data=request.data)
244 | # if serializer.is_valid():
245 | # result = serializer.update_user(serializer.validated_data)
246 | # return Response(result, status=status.HTTP_201_CREATED)
247 | # return Response(dict(error_code=ErrorCode.参数错误.value, error=json.dumps(serializer.errors, ensure_ascii=False)), status=status.HTTP_400_BAD_REQUEST)
248 | ```
249 | 到目前为止,我们已经完成了一个简单接口的创建,接下来可以对项目进行测试
250 | #### 4. 测试我们的Web API。首先启动一个开发服务器,之后在浏览器里输入地址访问我们的接口。
251 | 启动开发服务器
252 | ``` shell {.line-numbers}
253 | python manage.py runserver
254 |
255 | Validating models...
256 |
257 | 0 errors found
258 | Django version 2.0, using settings 'attendances.settings'
259 | Development server is running at http://127.0.0.1:8000/
260 | Quit the server with CONTROL-C.
261 | ```
262 | 在浏览器里输入接口地址,获取到接口数据:http://127.0.0.1:8000/api/v1/user/?token=21cd4161-2a78-451e-8979-5fbd8538935e&user_id=4
263 | ``` python {.line-numbers}
264 | GET /api/v1/user/?token=21cd4161-2a78-451e-8979-5fbd8538935e&user_id=4
265 | ```
266 | ``` python {.line-numbers}
267 | HTTP 201 Created
268 | Allow: POST, GET, OPTIONS
269 | Content-Type: application/json
270 | Vary: Accept
271 |
272 | {
273 | "nick_name": "Band",
274 | "avatar": "http://wx.qlogo.cn/mmopen/vi_32/aSKcBBPpibyKNicHNTMM0qJVh8Kjgiak2AHWr8MHM4WgMEm7GFhsf8OYrySdbvAMvTsw3mo8ibKicsnfN5pRjl1p8HQ/0",
275 | "error_code": 0,
276 | "error": ""
277 | }
278 | ```
279 | ### 二、相关问题说明
280 | #### 1. 在配置文件里记得修改成本地时区以及将语言设置成中文。
281 | ``` python {.line-numbers}
282 | LANGUAGE_CODE = 'zh-Hans'
283 | TIME_ZONE = 'Asia/Shanghai'
284 | ```
285 | #### 2. 在安装python3之后,使用pip安装依赖的时候记得使用pip3,或者改掉python和pip的。
286 | ``` shell {.line-numbers}
287 | $ alias python='/usr/bin/python3'
288 | ```
289 | 为了不混淆项目,并且大家在项目中遇到的问题可能各不一样,暂时不列出更多的问题,如果有疑问可以留言。
290 | ## 第二部分 部署流程以及问题说明
291 | 部署的时候建议大家安装docker容器,如果你没有太多的时间了解docker,可以先不用安装,直接按下面的流程去部署,部署的方式都是一样的,只是运行的地方不一样而已。这里就不列出docker的安装以及使用了。
292 | ### 一、部署步骤
293 | #### 1. 安装python3
294 | 首先安装依赖包。libxml模块是为了让uwsig支持使用“-x"选项,能通过xml文件启动项目
295 | ``` shell {.line-numbers}
296 | $ yum gcc-c++
297 | $ yum install wget openssl-devel bzip2-devel expat-devel gdbm-devel readline-devel sqlite-devel
298 | $ yum install libxml*
299 | ```
300 | 下载python3的压缩包之后,解压并安装到/usr/local/python3/路径下,ln命令是为了方便在终端中直接使用python3和pip3命令。
301 | ``` shell {.line-numbers}
302 | $ wget https://www.python.org/ftp/python/3.6.3/Python-3.6.3.tgz
303 | $ tar -zxvf Python-3.6.3.tar.gz
304 | $ ./configure --prefix=/usr/local/python3
305 | $ make -j2
306 | $ make install -j2
307 | $ ln -s /usr/local/python3/bin/python3.5 /usr/bin/python3
308 | $ ln -s /usr/local/python3/bin/pip3 /usr/bin/pip3
309 | ```
310 | #### 2. 安装uWsgi
311 | ``` shell {.line-numbers}
312 | $ pip3 install uwsgi
313 | ```
314 | 为了在终端中使用uwsgi命令,执行以下命令
315 | ``` shell {.line-numbers}
316 | $ ln -s /usr/local/python3/bin/uwsgi /usr/bin/uwsgi3
317 | ```
318 | 编写一个简单的wsgi应用测试uwsgi是否能正常使用,创建一个test.py文件。
319 | ``` python {.line-numbers}
320 | # test.py
321 | def application(env, start_response):
322 | start_response('200 OK', [('Content-Type','text/html')])
323 | return [b"Hello World"] # python3
324 | ```
325 | 运行uwsgi,http :8000表示使用http协议,端口号为8000,wigi-file则表示要运行的wsgi应用程序文件。
326 | ``` shell {.line-numbers}
327 | # test.py
328 | $ uwsgi --http :8000 --wsgi-file test.py
329 | ```
330 | uwsgi运行后打开浏览器,访问http://127.0.0.1:8000/ ,或者是相应服务器地址的8000端口,就可以看到hello world 页面了。
331 | #### 3. 安装Django以及项目依赖,通过uWsgi测试项目是否能正常运行
332 | 安装依赖
333 | ``` shell {.line-numbers}
334 | $ pip3 install django
335 | $ pip3 install djangorestframework
336 | $ pip3 install pycrypto
337 | ```
338 | Django通过uWsgi测试,如果能正常浏览则运行成功,静态文件无法访问的话,我们这里先忽略,后面会通过Nginx配置静态资源访问
339 | #### 4. 安装MySQL,也可以直接使用SQLite或PostgreSQL、Oracle数据库,Django支持多种数据库,根据配置安装不同的驱动,本项目采用MySQL,数据表结构以及链接配置请参考文档
340 | ``` shell {.line-numbers}
341 | $ pip3 install mysql
342 | $ pip3 install mysql-server
343 | $ pip3 install mysql-devel
344 | ```
345 | MySQL的安装可以参考文档:[MySQL 安装 | 菜鸟教程](http://www.runoob.com/mysql/mysql-install.html)
346 | #### 5. 连接uwsgi与Django
347 | 该步骤只是检测Django项目能否在uwsgi下运行,下面我们将配置xml的启动配置文件
348 | ``` shell {.line-numbers}
349 | $ uwsgi3 --http :8000 --module attendances.wsgi
350 | ```
351 | xml的启动配置文件
352 | ``` python {.line-numbers}
353 |
354 | 127.0.0.1:8000
355 | /root/web/attendances/attendances
356 | attendances.wsgi
357 | 4
358 | uwsgi.log
359 |
360 | ```
361 | 进入项目执行以下命令
362 | ``` shell {.line-numbers}
363 | $ uwsgi3 -x attendances.xml
364 | ```
365 | #### 6. 安装nginx
366 | ``` shell {.line-numbers}
367 | $ wget http://nginx.org/download/nginx-1.13.7.tar.gz
368 | $ tar -zxvf nginx-1.13.7.tar.gz
369 | $ ./configure
370 | $ make
371 | $ make install
372 | $ nginx
373 | ```
374 | 通过链接查看nginx是否启动成功:http://192.168.2.110
375 | #### 6. 通过配置nginx.conf文件连接Django、uWsgi与Nginx
376 | 在/etc/nginx/nginx.conf修改nginx.conf
377 | ``` shell {.line-numbers}
378 | server {
379 | listen 80 default_server;#暴露给外部访问的端口
380 | listen [::]:80 default_server;
381 | server_name 127.0.0.1;
382 | index index.py index.html;
383 | root /root/web/attendances/attendances;
384 |
385 | location / {
386 | include uwsgi_params;
387 | uwsgi_pass 127.0.0.1:8000;#外部访问80就转发到内部8000
388 | }
389 |
390 | location /static/ {
391 | alias /root/web/attendances/attendances/static/;#项目静态路径设置
392 | }
393 | }
394 | ```
395 | 保存nginx.conf执行nginx -t命令先检查配置文件是否有错,没有错就执行以下命令:nginx启动nginx,可以通过链接查看nginx是否启动成功,之前启动过的话重启nginx.
396 | 重启nginx
397 | ``` shell {.line-numbers}
398 | $ nginx -t
399 | $ nginx -s reload
400 | ```
401 | 以上步骤都没有出错的话,打开你的浏览器,输入以下链接,记得关闭系统防火墙或者开放8000端口
402 | http://192.168.2.110/api/v1/user/?token=21cd4161-2a78-451e-8979-5fbd8538935e&user_id=4 (请将该ip替换成你的服务器ip)
403 | 网站访问成功!
404 | ### 二、相关问题说明
405 | #### 1. Nginx和Django静态文件处理
406 | Django项目可以正常打开,但是静态文件引用路径还有问题,在Django开发时Django自己可以正确处理静态文件的路径,但是部署后Nginx去无法找到静态文件路径。
407 |
408 | 检查Nginx配置文件夹sites-enabled里的nginx-pro文件,确保里面默认的try_files要删掉或者注释掉,否则Nginx会因此检查静态文件是否存在。
409 |
410 | 将Django的静态文件集中起来,Django为此有专门的工具
411 |
412 | 现在Django的Settings文件中加上StATIC_ROOT,把静态文件都集中到这个路径下
413 |
414 | ``` shell
415 | STATIC_ROOT = os.path.join(BASE_DIR, "static/")
416 | ```
417 | 执行命令
418 |
419 | ``` shell {.line-numbers}
420 | $ python3 ./manage.py collectstatic
421 | ```
422 | 这样所有Django前后台的静态文件都会集中到项目文件夹pro下static中,另外nginx-pro其中一个配置location /static即可让Nginx来处理静态内容。
423 | #### 2. Nginx权限问题(Nginx 403 forbidden)
424 | 如果nginx用户没有web目录的权限,则会导致该错误。解决办法:修改web目录的读写权限。或者是把nginx的启动用户改成目录的所属用户,重起一下就能解决,在nginx.conf头部加入一行:user root;因为项目是在root用户下建立的,通过这个用户去访问资源就可以访问。
425 | ``` shell
426 | chmod -R 766 /web
427 | ```
428 | #### 3. Nginx转发出现错误(502 BAD GATEWAY)
429 |
430 | ``` shell
431 | $ setsebool -P httpd_can_network_connect 1
432 | ```
433 | > 如果访问不了可以查看Nginx下的error.log文件,查看具体的问题,再找解决方法。
434 | ## 分享一些中文文档资料
435 | > 有关Python、Django以及Django REST FrameWork的学习可以参考官方文档,以及以下中文文档,在网上找了很久,感觉以下这几个中文文档还是写的很不错的。
436 |
437 | [**Python:** 廖雪峰老师Python教程,基于最新的Python 3版本](https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000)
438 |
439 | [**Django:** The Django Book 2.0--中文版](http://docs.30c.org/djangobook2/index.html)
440 |
441 | [**Django REST FrameWork:** Django REST FrameWork中文文档目录](http://www.chenxm.cc/post/299.html)
442 |
--------------------------------------------------------------------------------
/apis/__pycache__/__init__.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/herry-zhang/Python3-RESTfulAPI/e772e0beee284c50946e94c54a1d43071ca78b74/apis/__pycache__/__init__.cpython-36.pyc
--------------------------------------------------------------------------------
/apis/__pycache__/base.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/herry-zhang/Python3-RESTfulAPI/e772e0beee284c50946e94c54a1d43071ca78b74/apis/__pycache__/base.cpython-36.pyc
--------------------------------------------------------------------------------
/apis/__pycache__/enum.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/herry-zhang/Python3-RESTfulAPI/e772e0beee284c50946e94c54a1d43071ca78b74/apis/__pycache__/enum.cpython-36.pyc
--------------------------------------------------------------------------------
/apis/__pycache__/setting.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/herry-zhang/Python3-RESTfulAPI/e772e0beee284c50946e94c54a1d43071ca78b74/apis/__pycache__/setting.cpython-36.pyc
--------------------------------------------------------------------------------
/apis/__pycache__/urls.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/herry-zhang/Python3-RESTfulAPI/e772e0beee284c50946e94c54a1d43071ca78b74/apis/__pycache__/urls.cpython-36.pyc
--------------------------------------------------------------------------------
/apis/api_v1/__pycache__/__init__.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/herry-zhang/Python3-RESTfulAPI/e772e0beee284c50946e94c54a1d43071ca78b74/apis/api_v1/__pycache__/__init__.cpython-36.pyc
--------------------------------------------------------------------------------
/apis/api_v1/__pycache__/base.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/herry-zhang/Python3-RESTfulAPI/e772e0beee284c50946e94c54a1d43071ca78b74/apis/api_v1/__pycache__/base.cpython-36.pyc
--------------------------------------------------------------------------------
/apis/api_v1/__pycache__/enum.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/herry-zhang/Python3-RESTfulAPI/e772e0beee284c50946e94c54a1d43071ca78b74/apis/api_v1/__pycache__/enum.cpython-36.pyc
--------------------------------------------------------------------------------
/apis/api_v1/__pycache__/setting.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/herry-zhang/Python3-RESTfulAPI/e772e0beee284c50946e94c54a1d43071ca78b74/apis/api_v1/__pycache__/setting.cpython-36.pyc
--------------------------------------------------------------------------------
/apis/api_v1/__pycache__/urls.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/herry-zhang/Python3-RESTfulAPI/e772e0beee284c50946e94c54a1d43071ca78b74/apis/api_v1/__pycache__/urls.cpython-36.pyc
--------------------------------------------------------------------------------
/apis/api_v1/base.py:
--------------------------------------------------------------------------------
1 | import hashlib
2 | from apis.api_v1.setting import IS_TEST, APP_VERIFY_CODE
3 |
4 |
5 | class BaseApi(object):
6 |
7 | def authenticate(self, token):
8 | """
9 | 认证
10 | """
11 | if IS_TEST:
12 | return True
13 | elif not IS_TEST and self.md5(APP_VERIFY_CODE) == token:
14 | return True
15 | return False
16 |
17 | def authenticate_user(self, token, guid):
18 | """
19 | 登录用户认证
20 | """
21 | if IS_TEST:
22 | return True
23 | elif not IS_TEST and self.md5(APP_VERIFY_CODE + guid) == token:
24 | return True
25 | return False
26 |
27 | def md5(self, str):
28 | """
29 | MD5加密
30 | """
31 | m = hashlib.md5()
32 | m.update(str.encode("utf8"))
33 | return m.hexdigest()
34 |
35 | def is_in_enum(self, eunm, key=None, value=None):
36 | """
37 | 判断是否为枚举值的元素
38 | """
39 | for name, member in eunm.__members__.items():
40 | if key is not None and name == key or value is not None and value == member.value:
41 | return True
42 | return False
43 |
--------------------------------------------------------------------------------
/apis/api_v1/enum.py:
--------------------------------------------------------------------------------
1 | from enum import Enum, unique
2 |
3 |
4 | @unique
5 | class ErrorCode(Enum):
6 | # base
7 | 正确 = 0
8 | 参数错误 = 1
9 | 请求方法错误 = 2
10 | 认证错误 = 3
11 | # user
12 | 微信登录凭证错误 = 1000
13 | 用户不存在 = 1001
14 | 获取微信用户信息错误 = 1002
15 | 账户余额不足 = 1003
16 | 推送状态不正确 = 1004
17 |
--------------------------------------------------------------------------------
/apis/api_v1/setting.py:
--------------------------------------------------------------------------------
1 | # 是否测试环境,需要验证认证
2 | IS_TEST = True
3 |
--------------------------------------------------------------------------------
/apis/api_v1/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf.urls import url
2 | from apis.api_v1.user import views as api_user
3 | from apis.api_v1.scene import views as api_scene
4 | from apis.api_v1.joined_scene import views as api_joined_scene
5 | from apis.api_v1.my import views as api_my
6 | from apis.api_v1.other import views as api_other
7 |
8 | urlpatterns = [
9 | # user
10 | url(r'^user/$', api_user.user, name='user'),
11 | ]
12 |
13 | app_name = 'api-v1'
14 |
--------------------------------------------------------------------------------
/apis/api_v1/user/__pycache__/__init__.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/herry-zhang/Python3-RESTfulAPI/e772e0beee284c50946e94c54a1d43071ca78b74/apis/api_v1/user/__pycache__/__init__.cpython-36.pyc
--------------------------------------------------------------------------------
/apis/api_v1/user/__pycache__/json_models.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/herry-zhang/Python3-RESTfulAPI/e772e0beee284c50946e94c54a1d43071ca78b74/apis/api_v1/user/__pycache__/json_models.cpython-36.pyc
--------------------------------------------------------------------------------
/apis/api_v1/user/__pycache__/param_models.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/herry-zhang/Python3-RESTfulAPI/e772e0beee284c50946e94c54a1d43071ca78b74/apis/api_v1/user/__pycache__/param_models.cpython-36.pyc
--------------------------------------------------------------------------------
/apis/api_v1/user/__pycache__/serializers.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/herry-zhang/Python3-RESTfulAPI/e772e0beee284c50946e94c54a1d43071ca78b74/apis/api_v1/user/__pycache__/serializers.cpython-36.pyc
--------------------------------------------------------------------------------
/apis/api_v1/user/__pycache__/views.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/herry-zhang/Python3-RESTfulAPI/e772e0beee284c50946e94c54a1d43071ca78b74/apis/api_v1/user/__pycache__/views.cpython-36.pyc
--------------------------------------------------------------------------------
/apis/api_v1/user/serializers.py:
--------------------------------------------------------------------------------
1 | from rest_framework import serializers
2 | from apps.user.models import User
3 | from apis.api_v1.enum import ErrorCode
4 | from apis.api_v1.base import BaseApi
5 |
6 |
7 | class GetUserSerializer(serializers.Serializer):
8 | """
9 | 获取用户信息
10 | """
11 | token = serializers.CharField(max_length=150)
12 | user_id = serializers.IntegerField()
13 |
14 | def get_user(self, validated_data):
15 | result = dict()
16 | base_api = BaseApi()
17 | # 获取用户
18 | try:
19 | user = User.objects.get(user_id=validated_data["user_id"])
20 | except User.DoesNotExist:
21 | result["error_code"] = ErrorCode.用户不存在.value
22 | result["error"] = "用户不存在"
23 | return result
24 | # 认证
25 | if not base_api.authenticate_user(validated_data["token"], user.user_guid):
26 | result["error_code"] = ErrorCode.认证错误.value
27 | result["error"] = "认证错误"
28 | return result
29 | result["nick_name"] = user.user_name
30 | result["avatar"] = user.avatar
31 | result["error_code"] = ErrorCode.正确.value
32 | result["error"] = ""
33 | return result
34 |
35 |
36 |
--------------------------------------------------------------------------------
/apis/api_v1/user/views.py:
--------------------------------------------------------------------------------
1 | import json
2 | from rest_framework.decorators import api_view
3 | from rest_framework.response import Response
4 | from rest_framework import status
5 | from apis.api_v1.user.serializers import *
6 | from apis.api_v1.enum import ErrorCode
7 |
8 |
9 | @api_view(['GET', 'POST'])
10 | def user(request):
11 | """
12 | GET:获取用户信息
13 | POST:更新用户信息
14 | """
15 | if request.method == 'GET':
16 | param = dict()
17 | param["token"] = request.GET.get("token", None)
18 | param["user_id"] = request.GET.get("user_id", 0)
19 | serializer = GetUserSerializer(data=param)
20 | if serializer.is_valid():
21 | result = serializer.get_user(serializer.validated_data)
22 | return Response(result, status=status.HTTP_201_CREATED)
23 | return Response(dict(error_code=ErrorCode.参数错误.value, error=json.dumps(serializer.errors, ensure_ascii=False)), status=status.HTTP_400_BAD_REQUEST)
24 | # elif request.method == 'POST':
25 | # serializer = PostUserSerializer(data=request.data)
26 | # if serializer.is_valid():
27 | # result = serializer.update_user(serializer.validated_data)
28 | # return Response(result, status=status.HTTP_201_CREATED)
29 | # return Response(dict(error_code=ErrorCode.参数错误.value, error=json.dumps(serializer.errors, ensure_ascii=False)), status=status.HTTP_400_BAD_REQUEST)
30 |
--------------------------------------------------------------------------------
/apps/__pycache__/__init__.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/herry-zhang/Python3-RESTfulAPI/e772e0beee284c50946e94c54a1d43071ca78b74/apps/__pycache__/__init__.cpython-36.pyc
--------------------------------------------------------------------------------
/apps/user/__init__.py:
--------------------------------------------------------------------------------
1 | from os import path
2 | from django.apps import AppConfig
3 |
4 | VERBOSE_APP_NAME = "用户管理"
5 |
6 |
7 | def get_current_app_name(file):
8 | path_array = path.dirname(file).replace('\\', '/').split('/')
9 | return path_array[-2] + '.' + path_array[-1]
10 |
11 |
12 | class AppVerboseNameConfig(AppConfig):
13 | name = get_current_app_name(__file__)
14 | verbose_name = VERBOSE_APP_NAME
15 |
16 |
17 | default_app_config = get_current_app_name(
18 | __file__) + '.__init__.AppVerboseNameConfig'
19 |
--------------------------------------------------------------------------------
/apps/user/__pycache__/__init__.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/herry-zhang/Python3-RESTfulAPI/e772e0beee284c50946e94c54a1d43071ca78b74/apps/user/__pycache__/__init__.cpython-36.pyc
--------------------------------------------------------------------------------
/apps/user/__pycache__/admin.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/herry-zhang/Python3-RESTfulAPI/e772e0beee284c50946e94c54a1d43071ca78b74/apps/user/__pycache__/admin.cpython-36.pyc
--------------------------------------------------------------------------------
/apps/user/__pycache__/apps.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/herry-zhang/Python3-RESTfulAPI/e772e0beee284c50946e94c54a1d43071ca78b74/apps/user/__pycache__/apps.cpython-36.pyc
--------------------------------------------------------------------------------
/apps/user/__pycache__/models.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/herry-zhang/Python3-RESTfulAPI/e772e0beee284c50946e94c54a1d43071ca78b74/apps/user/__pycache__/models.cpython-36.pyc
--------------------------------------------------------------------------------
/apps/user/__pycache__/urls.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/herry-zhang/Python3-RESTfulAPI/e772e0beee284c50946e94c54a1d43071ca78b74/apps/user/__pycache__/urls.cpython-36.pyc
--------------------------------------------------------------------------------
/apps/user/__pycache__/views.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/herry-zhang/Python3-RESTfulAPI/e772e0beee284c50946e94c54a1d43071ca78b74/apps/user/__pycache__/views.cpython-36.pyc
--------------------------------------------------------------------------------
/apps/user/admin.py:
--------------------------------------------------------------------------------
1 | """
2 | 用户模块
3 | """
4 | from django.contrib import admin
5 | from apps.user.models import User
6 |
7 | class UserAdmin(admin.ModelAdmin):
8 | """
9 | 用户表
10 | """
11 | list_display = ('user_id', 'user_name', 'real_name', 'avatar', 'mobile',
12 | 'balance', 'available_balance', 'frozen_balance')
13 | search_fields = ('user_name', 'mobile')
14 |
15 | admin.site.register(User, UserAdmin)
16 |
--------------------------------------------------------------------------------
/apps/user/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class UserConfig(AppConfig):
5 | name = 'user'
6 |
--------------------------------------------------------------------------------
/apps/user/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.0 on 2018-01-08 15:34
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | initial = True
9 |
10 | dependencies = [
11 | ]
12 |
13 | operations = [
14 | migrations.CreateModel(
15 | name='User',
16 | fields=[
17 | ('user_id', models.AutoField(primary_key=True, serialize=False, verbose_name='用户id')),
18 | ('user_guid', models.CharField(max_length=32, verbose_name='用户guid')),
19 | ('user_name', models.CharField(blank=True, max_length=100, null=True, verbose_name='用户名')),
20 | ('real_name', models.CharField(blank=True, max_length=50, null=True, verbose_name='真实姓名')),
21 | ('avatar', models.CharField(blank=True, max_length=250, null=True, verbose_name='头像')),
22 | ('mobile', models.CharField(blank=True, max_length=50, null=True, verbose_name='手机')),
23 | ('balance', models.DecimalField(blank=True, decimal_places=2, max_digits=8, null=True, verbose_name='账户余额')),
24 | ('available_balance', models.DecimalField(blank=True, decimal_places=2, max_digits=8, null=True, verbose_name='可用金额')),
25 | ('frozen_balance', models.DecimalField(blank=True, decimal_places=2, max_digits=8, null=True, verbose_name='冻结金额')),
26 | ('all_balance', models.DecimalField(blank=True, decimal_places=2, max_digits=8, null=True, verbose_name='累计金额')),
27 | ('wx_open_id', models.CharField(max_length=150, verbose_name='微信OpenID')),
28 | ('wx_union_id', models.CharField(blank=True, max_length=150, null=True, verbose_name='微信UnionID')),
29 | ('create_date', models.FloatField(blank=True, null=True, verbose_name='创建时间')),
30 | ('last_login_date', models.FloatField(blank=True, null=True, verbose_name='最后登录时间')),
31 | ('ip_address', models.CharField(blank=True, max_length=50, null=True, verbose_name='IP地址')),
32 | ],
33 | options={
34 | 'verbose_name': '用户',
35 | 'verbose_name_plural': '用户',
36 | 'db_table': 'user',
37 | 'ordering': ['-create_date'],
38 | 'managed': False,
39 | },
40 | ),
41 | ]
42 |
--------------------------------------------------------------------------------
/apps/user/migrations/__pycache__/0001_initial.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/herry-zhang/Python3-RESTfulAPI/e772e0beee284c50946e94c54a1d43071ca78b74/apps/user/migrations/__pycache__/0001_initial.cpython-36.pyc
--------------------------------------------------------------------------------
/apps/user/migrations/__pycache__/__init__.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/herry-zhang/Python3-RESTfulAPI/e772e0beee284c50946e94c54a1d43071ca78b74/apps/user/migrations/__pycache__/__init__.cpython-36.pyc
--------------------------------------------------------------------------------
/apps/user/models.py:
--------------------------------------------------------------------------------
1 | """
2 | 用户模块
3 | """
4 | from django.db import models, transaction
5 |
6 | class User(models.Model):
7 | """
8 | 用户信息表
9 | """
10 | user_id = models.AutoField(primary_key=True, verbose_name='用户id')
11 | user_guid = models.CharField(max_length=150, verbose_name='用户guid')
12 | user_name = models.CharField(
13 | max_length=100, blank=True, null=True, verbose_name='用户名')
14 | real_name = models.CharField(
15 | max_length=50, blank=True, null=True, verbose_name='真实姓名')
16 | avatar = models.CharField(
17 | max_length=250, blank=True, null=True, verbose_name='头像')
18 | mobile = models.CharField(
19 | max_length=50, blank=True, null=True, verbose_name='手机')
20 | balance = models.DecimalField(
21 | max_digits=8, decimal_places=2, blank=True, null=True, verbose_name='账户余额')
22 | available_balance = models.DecimalField(
23 | max_digits=8, decimal_places=2, blank=True, null=True, verbose_name='可用金额')
24 | frozen_balance = models.DecimalField(
25 | max_digits=8, decimal_places=2, blank=True, null=True, verbose_name='冻结金额')
26 | all_balance = models.DecimalField(
27 | max_digits=8, decimal_places=2, blank=True, null=True, verbose_name='累计金额')
28 | wx_open_id = models.CharField(max_length=150, verbose_name='微信OpenID')
29 | wx_union_id = models.CharField(
30 | max_length=150, blank=True, null=True, verbose_name='微信UnionID')
31 | create_date = models.FloatField(blank=True, null=True, verbose_name='创建时间')
32 | last_login_date = models.FloatField(
33 | blank=True, null=True, verbose_name='最后登录时间')
34 | ip_address = models.CharField(
35 | max_length=50, blank=True, null=True, verbose_name='IP地址')
36 | gender = models.IntegerField(blank=True, null=True, verbose_name='性别')
37 | province = models.CharField(
38 | max_length=50, blank=True, null=True, verbose_name='省份')
39 | city = models.CharField(
40 | max_length=50, blank=True, null=True, verbose_name='城市')
41 | session_key = models.CharField(
42 | max_length=150, blank=True, null=True, verbose_name='会话秘钥')
43 | is_notify = models.IntegerField(blank=True, null=True, verbose_name='是否开启打卡通知')
44 |
45 | @classmethod
46 | def update_user_balance(cls, user_id, amount):
47 | # 手动让select for update和update语句发生在一个完整的事务里面
48 | with transaction.atomic():
49 | user = (
50 | cls.objects
51 | .select_for_update()
52 | .get(user_id=user_id)
53 | )
54 | user.available_balance += amount
55 | user.balance = user.available_balance + user.frozen_balance
56 | if amount > 0:
57 | user.all_balance += amount
58 | user.save()
59 | return user
60 |
61 | class Meta:
62 | managed = False
63 | db_table = 'user'
64 | ordering = ['-create_date']
65 | verbose_name = '用户'
66 | verbose_name_plural = '用户'
67 |
--------------------------------------------------------------------------------
/apps/user/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/apps/user/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf.urls import url
2 | from apps.user import views
3 |
4 | urlpatterns = [
5 | url(r'^user-add/(?P\d+)/$', views.add, name='user-add'),
6 | ]
7 |
8 |
9 | app_name = 'user'
10 |
--------------------------------------------------------------------------------
/apps/user/views.py:
--------------------------------------------------------------------------------
1 | """
2 | 用户表
3 | """
4 | from django.shortcuts import render_to_response
5 | from apps.user.models import User
6 |
7 |
8 | def add(request, id):
9 | """
10 | add
11 | """
12 | uid = id
13 | return render_to_response('user/user_add.html', locals())
14 |
--------------------------------------------------------------------------------
/attendances.xml:
--------------------------------------------------------------------------------
1 |
2 | 127.0.0.1:8000
3 | /root/web/attendances/attendances
4 | attendances.wsgi
5 | 4
6 | uwsgi.log
7 |
--------------------------------------------------------------------------------
/attendances/__pycache__/__init__.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/herry-zhang/Python3-RESTfulAPI/e772e0beee284c50946e94c54a1d43071ca78b74/attendances/__pycache__/__init__.cpython-36.pyc
--------------------------------------------------------------------------------
/attendances/__pycache__/settings.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/herry-zhang/Python3-RESTfulAPI/e772e0beee284c50946e94c54a1d43071ca78b74/attendances/__pycache__/settings.cpython-36.pyc
--------------------------------------------------------------------------------
/attendances/__pycache__/urls.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/herry-zhang/Python3-RESTfulAPI/e772e0beee284c50946e94c54a1d43071ca78b74/attendances/__pycache__/urls.cpython-36.pyc
--------------------------------------------------------------------------------
/attendances/__pycache__/view.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/herry-zhang/Python3-RESTfulAPI/e772e0beee284c50946e94c54a1d43071ca78b74/attendances/__pycache__/view.cpython-36.pyc
--------------------------------------------------------------------------------
/attendances/__pycache__/wsgi.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/herry-zhang/Python3-RESTfulAPI/e772e0beee284c50946e94c54a1d43071ca78b74/attendances/__pycache__/wsgi.cpython-36.pyc
--------------------------------------------------------------------------------
/attendances/settings.py:
--------------------------------------------------------------------------------
1 | """
2 | Django settings for attendances project.
3 |
4 | Generated by 'django-admin startproject' using Django 2.0.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/2.0/topics/settings/
8 |
9 | For the full list of settings and their values, see
10 | https://docs.djangoproject.com/en/2.0/ref/settings/
11 | """
12 |
13 | import os
14 |
15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
17 |
18 |
19 | # Quick-start development settings - unsuitable for production
20 | # See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/
21 |
22 | # SECURITY WARNING: keep the secret key used in production secret!
23 | SECRET_KEY = '+6$=@6_9ts&1jzyd^fh99k6f_$)5&xixcqv-z8hg1(!sd&9a^3'
24 |
25 | # SECURITY WARNING: don't run with debug turned on in production!
26 | DEBUG = True
27 |
28 | ALLOWED_HOSTS = ['127.0.0.1','192.168.2.110']
29 |
30 |
31 | # Application definition
32 |
33 | INSTALLED_APPS = [
34 | 'suit',
35 | 'rest_framework',
36 | 'django.contrib.admin',
37 | 'django.contrib.auth',
38 | 'django.contrib.contenttypes',
39 | 'django.contrib.sessions',
40 | 'django.contrib.messages',
41 | 'django.contrib.staticfiles',
42 | 'apps.user',
43 | ]
44 |
45 |
46 | MIDDLEWARE = [
47 | 'django.middleware.security.SecurityMiddleware',
48 | 'django.contrib.sessions.middleware.SessionMiddleware',
49 | 'django.middleware.common.CommonMiddleware',
50 | 'django.middleware.csrf.CsrfViewMiddleware',
51 | 'django.contrib.auth.middleware.AuthenticationMiddleware',
52 | 'django.contrib.messages.middleware.MessageMiddleware',
53 | 'django.middleware.clickjacking.XFrameOptionsMiddleware',
54 | ]
55 |
56 | ROOT_URLCONF = 'attendances.urls'
57 |
58 | TEMPLATES = [
59 | {
60 | 'BACKEND': 'django.template.backends.django.DjangoTemplates',
61 | 'DIRS': [
62 | os.path.join(BASE_DIR, 'templates')
63 | ],
64 | 'APP_DIRS': True,
65 | 'OPTIONS': {
66 | 'context_processors': [
67 | 'django.template.context_processors.debug',
68 | 'django.template.context_processors.request',
69 | 'django.contrib.auth.context_processors.auth',
70 | 'django.contrib.messages.context_processors.messages',
71 | ],
72 | },
73 | },
74 | ]
75 |
76 | WSGI_APPLICATION = 'attendances.wsgi.application'
77 |
78 |
79 | # Database
80 | # https://docs.djangoproject.com/en/2.0/ref/settings/#databases
81 |
82 | DATABASES = {
83 | 'default': {
84 | 'ENGINE': 'django.db.backends.mysql',
85 | 'NAME': 'attendances',
86 | 'USER': 'root',
87 | 'PASSWORD': '123',
88 | 'HOST': '192.168.2.110',
89 | 'PORT': '3306',
90 | }
91 | # 'default': {
92 | # 'ENGINE': 'django.db.backends.mysql',
93 | # 'NAME': 'attendances',
94 | # 'USER': 'root',
95 | # 'PASSWORD': 'admin!@#$1234',
96 | # 'HOST': '127.0.0.1',
97 | # 'PORT': '3306',
98 | # }
99 | }
100 |
101 |
102 | # Password validation
103 | # https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators
104 |
105 | AUTH_PASSWORD_VALIDATORS = [
106 | {
107 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
108 | },
109 | {
110 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
111 | },
112 | {
113 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
114 | },
115 | {
116 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
117 | },
118 | ]
119 |
120 |
121 | # Internationalization
122 | # https://docs.djangoproject.com/en/2.0/topics/i18n/
123 |
124 | LANGUAGE_CODE = 'zh-Hans'
125 |
126 | TIME_ZONE = 'Asia/Shanghai'
127 |
128 | USE_I18N = True
129 |
130 | USE_L10N = True
131 |
132 | USE_TZ = True
133 |
134 |
135 | # Static files (CSS, JavaScript, Images)
136 | # https://docs.djangoproject.com/en/2.0/howto/static-files/
137 | STATIC_ROOT = os.path.join(BASE_DIR, "static")
138 |
139 | STATIC_URL = '/static/'
140 |
141 | STATICFILES_DIRS = (
142 | os.path.join(BASE_DIR, "static"),
143 | )
144 |
--------------------------------------------------------------------------------
/attendances/urls.py:
--------------------------------------------------------------------------------
1 | """attendances URL Configuration
2 |
3 | The `urlpatterns` list routes URLs to views. For more information please see:
4 | https://docs.djangoproject.com/en/2.0/topics/http/urls/
5 | Examples:
6 | Function views
7 | 1. Add an import: from my_app import views
8 | 2. Add a URL to urlpatterns: path('', views.home, name='home')
9 | Class-based views
10 | 1. Add an import: from other_app.views import Home
11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
12 | Including another URLconf
13 | 1. Import the include() function: from django.urls import include, path
14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
15 | """
16 | from django.conf.urls import url, include
17 | from django.contrib import admin
18 |
19 | urlpatterns = [
20 | url('admin/', admin.site.urls),
21 | url(r'^user/', include('apps.user.urls', namespace='user')),
22 | url(r'^api/v1/', include('apis.api_v1.urls', namespace='api-v1')),
23 | ]
24 |
--------------------------------------------------------------------------------
/attendances/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for attendances project.
3 |
4 | It exposes the WSGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/2.0/howto/deployment/wsgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.wsgi import get_wsgi_application
13 |
14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "attendances.settings")
15 |
16 | application = get_wsgi_application()
17 |
--------------------------------------------------------------------------------
/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import os
3 | import sys
4 |
5 | if __name__ == "__main__":
6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "attendances.settings")
7 | try:
8 | from django.core.management import execute_from_command_line
9 | except ImportError as exc:
10 | raise ImportError(
11 | "Couldn't import Django. Are you sure it's installed and "
12 | "available on your PYTHONPATH environment variable? Did you "
13 | "forget to activate a virtual environment?"
14 | ) from exc
15 | execute_from_command_line(sys.argv)
16 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | Django==2.0
2 | djangorestframework==3.7.7
3 | pycrypto==2.6.1
4 | uwsgi
5 | request
--------------------------------------------------------------------------------
/test.py:
--------------------------------------------------------------------------------
1 | def application(env, start_response):
2 | start_response('200 OK', [('Content-Type','text/html')])
3 | return [b"Hello World"] # python3
--------------------------------------------------------------------------------