Django 框架

发布时间: 更新时间: 总字数:1281 阅读时间:3m 作者: 分享 复制网址

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_ 信息去掉或使用默认(不带时区)。

Home Archives Categories Tags Statistics
本文总阅读量 次 本站总访问量 次 本站总访客数