Django 框架基础知识汇总,包括安装、管理、数据库配置和定时任务celery等。
使用
安装
pip install django
创建新项目
django-admin.py startproject my_project
创建新的App
# 在Django项目(my_project)的根目录下执行
python manage.py startapp my_app
创建用户
python manage.py createsuperuser
python3 manage.py changepassword admin
访问地址:http://127.0.0.1:8888/admin
shell 调试
$ python manage.py shell
from moments.models import Status
statuses = Status.objects.all()
print statuses.query
print statuses
statuses[0].user
启动服务
python manage.py runserver 80
settings.py
配置数据库
测试环境,没有mysql时,可以将 mysql 切换为 sqlite3,修改 settings.py
:
import os
from settings import APP_ID
from settings import BASE_DIR
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3', # 默认用mysql
'NAME': os.path.join(BASE_DIR, APP_ID),
...
# 'ENGINE': 'django.db.backends.mysql',
# 'NAME': 'eastwind',
# 'USER': 'root',
# 'PASSWORD': '<pwd>',
# 'HOST': '127.0.0.1',
# 'PORT': '3306',
}
}
升级数据库
# make new migrations
python manage.py makemigrations
# apply all migrations
python manage.py migrate
# 解决 django.db.utils.OperationalError: (1060, "Duplicate column name 'uid'") 问题
python3 manage.py migrate --fake
显示 SQL
$ python manage.py sqlmigrate my_app 0001
BEGIN;
--
-- Create model Status
--
CREATE TABLE "moments_status" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "text" varchar(140) NOT NULL, "pics" varchar(400) NULL, "pub_time" datetime NOT NULL);
--
-- Create model WeChatUser
--
CREATE TABLE "moments_wechatuser" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "motto" varchar(500) NULL, "pic" varchar(200) NULL, "region" varchar(50) NULL, "user_id" integer NOT NULL UNIQUE REFERENCES "auth_user" ("id"));
--
-- Add field user to status
--
ALTER TABLE "moments_status" RENAME TO "moments_status__old";
CREATE TABLE "moments_status" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "text" varchar(140) NOT NULL, "pics" varchar(400) NULL, "pub_time" datetime NOT NULL, "user_id" integer NOT NULL REFERENCES "moments_wechatuser" ("id"));
INSERT INTO "moments_status" ("text", "pub_time", "user_id", "id", "pics") SELECT "text", "pub_time", NULL, "id", "pics" FROM "moments_status__old";
DROP TABLE "moments_status__old";
CREATE INDEX "moments_status_user_id_d38910b1" ON "moments_status" ("user_id");
COMMIT;
Mac MySQL 依赖安装
pip3 install mysqlclient==2.0.3
时报错:
OSError: mysql_config not found
mysql_config --version
mariadb_config --version
mysql_config --libs
是由于缺少 MySQL 依赖导致的,修复方法如下:
xcode-select --install
brew install mysql mysql-client
时区
使用时区
修改 settings.py
中的
USE_TZ = True
TIME_ZONE = 'UTC'
为:
USE_TZ = True
TIME_ZONE = 'Asia/Shanghai'
- 当使用时区时,
Django
存储在数据库中的日期都以 UTC 时区为准
- 在后台使用有时区的
datetime
,前台用户使用时,需在网页上翻译成用户所在的时区
使用创建的时间对象为 aware datetime
ValueError: Database returned an invalid datetime value. Are time zone definitions for your database installed?
数据库不区分时区,Django区分时区,导致兼容问题,可以使用如下命令检测:
> select convert_tz('2018-08-18 08:08:00', 'UTC', 'Asia/Shanghai');
输出为 null 表示数据库不支持时区,执行如下命令:
# mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql
执行后在次检测,可以看到数据库已经可以正常的把 UTC
时间转化为 Asia/Shanghai
时区时间。
不使用时区
修改 settings.py
中的
USE_TZ = False
- 这样Django存储的时间是无时区(naive datetime) (datetime with no timezone information)
示例
# demo 1
import pytz
now_time = datetime.now().replace(tzinfo=pytz.timezone('Asia/Shanghai'))
# demo 2
def datetime_str_2_datetime(datetime_str):
"""
params:
datetime_str = '2021-05-14 07:25:45.062837183 +0800'
return datetime(year=2021, month=05, day=14, hour=07, minute=25, second=45,
microsecond=062837183, tzinfo=+8)
"""
date, time, tz = datetime_str.split(' ')
year, month, day = date.split('-')
hour, minute, _second = time.split(':')
second, microsecond = _second.split('.')
year = int(year)
month = int(month)
day = int(day)
hour = int(hour)
minute = int(minute)
second = int(second)
microsecond = int(microsecond[:6])
_datetime = datetime(
year=year, month=month, day=day,
hour=hour, minute=minute, second=second, microsecond=microsecond)
# return _datetime.replace(tzinfo=get_timezone_info())
return _datetime
Celery
启动
python manage.py celery worker --settings=settings -l info
python manage.py celerybeat --settings=settings
使用
# home_application.celery_tasks 方法
@task()
def async_task(x, y):
"""
定义一个 celery 异步任务
"""
logger.error(u"celery 定时任务执行成功,执行结果:{:0>2}:{:0>2}".format(x, y))
return x + y
>>> from home_application.celery_tasks import async_task
>>> import datetime
>>> now = datetime.datetime.now()
>>> async_task.apply_async(args=[now.hour, now.minute], eta=now + datetime.timedelta(seconds=60))
<AsyncResult: 2350fd61-1f32-46c0-b9d9-da0de2a918e1>
输出如下:
[2019-07-25 15:21:40,658: INFO/MainProcess] Received task: home_application.celery_tasks.async_task[2350fd61-1f32-46c0-b9d9-da0de2a918e1] eta:[2019-07-25 15:22:32.038230]
[2019-07-25 15:22:32,746: ERROR/Worker-10] celery 定时任务执行成功,执行结果:15:21
[2019-07-25 15:22:32,771: INFO/MainProcess] Task home_application.celery_tasks.async_task[2350fd61-1f32-46c0-b9d9-da0de2a918e1] succeeded in 0.0256261270006s: 36
from home_application import celery_tasks
celery_tasks.async_task(5, 8) # 实时输出
celery_tasks.async_task.dely(5, 8) # 延时执行
celery_tasks.async_task.apply_async(args=(5, 8))
import datatime
celery_tasks.async_task.apply_async(args=(5, 8), eta=datatime.datatime.now() + datatime.timedeta(seconds=60)) # 指定时间执行
@periodic_task(run_every=crontab(minute='*/1', hour='*', day_of_week="*"))
def task_name():
celery 添加 task 后,需要在 conf/default.py 中,添加 CELERY_IMPORTS
# docker exec -it cbf /bin/bash
# su apps
# /cache/.py/env/bin/python /data/app/code/manage.py shell
>>> from ntds import celery_tasks
>>> celery_tasks.<periodic_task_name>.apply()
<EagerResult: c1adbc71-cc09-4901-818e-8281251178a1>
其他
去重
def remove_duplicates(old_str):
old_list = old_str.split(',')
new_list = []
for a in old_list:
if a not in new_list:
new_list.append(a)
print ",".join(new_list)
remove_duplicates("a,b,c,a")
错误
升级问题
报 django.db.utils.InternalError: (1050, u"Table 'django_content_type' already exists")
错误:
File "/cache/.py/env/lib/python2.7/site-packages/pymysql/connections.py", line 1138, in read
first_packet = self.connection._read_packet()
File "/cache/.py/env/lib/python2.7/site-packages/pymysql/connections.py", line 906, in _read_packet
packet.check_error()
File "/cache/.py/env/lib/python2.7/site-packages/pymysql/connections.py", line 367, in check_error
err.raise_mysql_exception(self._data)
File "/cache/.py/env/lib/python2.7/site-packages/pymysql/err.py", line 120, in raise_mysql_exception
_check_mysql_exception(errinfo)
File "/cache/.py/env/lib/python2.7/site-packages/pymysql/err.py", line 115, in _check_mysql_exception
raise InternalError(errno, errorvalue)
django.db.utils.InternalError: (1050, u"Table 'django_content_type' already exists")
------FAILURE: Migrate Database------
[172.19.11.14]20190409-162750 105 [JOB FAILURE]
解决办法:
pip install -r requirements.txt -i http://<url>/simple --trusted-host <url>
# 1. 执行
python manage.py migrate --fake
# 2. 再次执行
python manage.py migrate
时区
USE_TZ = False
后,django orm
创建带时间的示例报错:
MySQL backend does not support timezone-aware datetimes when USE_TZ is False.
解决方法:
把 datetime 的 tzinfo_ 信息去掉或使用默认(不带时区)。