配置
安装
python install django
创建项目
django-admin startproject [项目名]
- 示例, 创建名为TestDjango 项目
(1) init: 一个空文件, 声明所在目录包为一个 python 包
(2) settings: 管理项目配置信息
(3) urls: 声明请求 url 映射关系
(4) wsgi: python 程序和 web 服务器通信协议
(5) manage: 一个命令行工具, 用来和 Django 项目进行交互
创建应用
- 示例, 创建App 应用
python manage.py startapp App
应用目录结构
(1) admin: App 应用后台管理配置文件
(2) apps: App 应用配置文件
(3) models: 数据模块, 用于设计数据库等
(4) tests: 编写测试脚本
(5) views: 视图层, 直接和浏览器进行交互
应用注册
新建应用需在 settings.py文件 INSTALLED_APPS 列表中注册, 使程序找到该服务
setting.py默认内容
import os
# 项目相对路径, 启动服务时候会运行这个文件所在路径的manage.py
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# 安全密钥
SECRET_KEY = 'oyj48d_pm2jhr2!4e9cmv+&h5j^4y6im_a7t)pqs87q0!5p4+4'
# 是否开启Debug
DEBUG = True
# 允许访问主机ip, 可以用通配符*
ALLOWED_HOSTS = []
# Application definition
# 用来注册App 前6个是django自带应用
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
# 中间件, 需要加载的中间件.比如在请求前和响应后根据规则去执行某些代码的方法
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
# 指定URL列表文件 父级URL配置
ROOT_URLCONF = 'demo.urls'
# 加载网页模板路径
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
# WSGI的配置文件路径
WSGI_APPLICATION = 'demo.wsgi.application'
# 数据库配置 默认的数据库为sqlite
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
# 相关密码验证
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# 语言设置 默认英语, 中文是zh-hans
LANGUAGE_CODE = 'en-us'
# 时区设置, 中国的是:Asia/Shanghai
TIME_ZONE = 'UTC'
# i18n字符集是否支持
USE_I18N = True
USE_L10N = True
# 是否使用timezone
# 保证存储到数据库中的是 UTC 时间;
# 在函数之间传递时间参数时, 确保时间已经转换成 UTC 时间;
USE_TZ = True
# 静态文件路径
STATIC_URL = '/static/'
视图
编辑App/view.py
from django.http import HttpResponse
from django.shortcuts import render
# Create your views here.
def hello(request):
return HttpResponse('Hello World')
路由
编辑TestDjango/urls.py
from django.contrib import admin
from django.urls import path
import App.views
urlpatterns = [
path('admin/', admin.site.urls),
# 将hello()函数绑定路由
path('hello/', App.views.hello)
]
测试
python manage.py runserver 8080
访问 http://127.0.0.1:8000/hello
数据库
迁移
# 终端执行, 为改动创建迁移记录
python manage.py makemigrations
# 将操作同步到数据库
python manage.py migrate
- 同步到多个数据库
python manage.py migrate --database=路由表中应用对应数据库
创建管理员用户
python manage.py createsuperuser
部署
uwsgi部署
建立项目mysite
django-admin.py startproject mysite
python manage.py runserver 0.0.0.0:8000
- uwsgi
[uwsgi]
socket = 127.0.0.1:8000
# 启动主进程, 来管理其他进程
master = true
# 开启进程数量
processes = 2
# 运行线程
threads = 8
# 设置用于uwsgi包解析内部缓存区大小为64k.默认是4k
buffer-size = 32768
- nginx
server {
listen 80;
server_name localhost;
location / {
include uwsgi_params;
# 必须和 uwsgi中设置一致
+ uwsgi_pass 127.0.0.1:8000;
# 入口文件, 即wsgi.py相对于项目根目录位置, "."相当于一层目录
+ uwsgi_param UWSGI_SCRIPT /mysite/mysite.wsgi;
# 项目根目录
+ uwsgi_param UWSGI_CHDIR /mysite;
index index.html index.htm;
client_max_body_size 35m;
}
}
问题
跨域
pip install django-cors-headers
- 修改settings.py文件
INSTALLED_APPS = [
...
# 增加
+ 'corsheaders',
...
]
...
MIDDLEWARE = [
...
# 增加
+ 'corsheaders.middleware.CorsMiddleware',
+ 'django.middleware.common.CommonMiddleware',
...
]
数据库操作
MySQL
建立应用 App
python3 manage.py startapp App
主目录下 settings.py文件中DATABASES为默认配置, 会建立 sqlite3 数据库
若使用其他数据库需进行修改, 以MySQL为例,
DATABASES = {
'default': {
# 数据库引擎
'ENGINE': 'django.db.backends.mysql',
'NAME': 数据库名,
'USER': 用户名,
'PASSWORD': 密码,
'HOST': IP,
'PORT': 端口,
}
}
建表
编辑 App/models.py
from django.db import models
# 学生表
class Stu(models.Model):
choices=(('M', '男'), ('W', '女')),
num = models.CharField(primary_key=True, verbose_name='学号', help_text='请输入学号', max_length=5)
name = models.CharField(verbose_name='姓名', help_text='请输入姓名', max_length=5)
age = models.IntegerField(verbose_name='年龄', help_text='请输入年龄')
sex = models.CharField(verbose_name='性别', help_text='请选择性别', default='M', max_length=1)
# 元数据
class Meta:
# 按'age'字段升序排列
ordering = ['age']
# 显示类信息
def __str__(self):
sex = '男' if self.sex == 'M' else '女'
return '学号:%s 姓名:%s 年龄:%s 性别:%s' % (self.num, self.name, self.age, sex)
字段
类型 | 说明 |
---|---|
AutoField | 一个自动增加整数类型字段, django 会自动添加自增字段:id = models.AutoField(primary_key=True), 从 1 开始计数 |
CharField | 字符串类型.必须接收一个 max_length 参数, 表示字符串长度不能超过该值.默认表单标签是 input text |
TextField | 大量文本内容, 在 HTML 中表现为 Textarea 标签 |
IntegerField | 整数类型, 取值范围-2147483648 到 2147483647 |
DateField | 日期类型, python 中datetime.date()实例, 例如 2020-08-05 |
DateTimeField | 日期时间类型, python datetime.datetime()实例.多了小时、分和秒显示, 例如 2020-08-05 23:08 |
FileField | 上传文件类型 |
ImageField | 图像类型 |
字段参数
类型 | 说明 |
---|---|
default | 字段默认值, 可以是值或者一个可调用对象 |
help_text | 额外显示在表单部件上帮助文本 |
primary_key | 若为字段设置了 primary_key=True, 则当前字段变为主键; primary_key=True 隐含 null=False 和 unique=True 意思 |
verbose_name | 为字段设置可读, 直观别名 |
choices | 选择框标签, 值为一个二维二元元组;第一个元素表示数据库内真实值, 第二个表示页面上显示内容 |
# 为改动创建迁移记录
python manage.py makemigrations
# 将操作同步到数据库
python manage.py migrate
此时 App/migrations 下生成 0001_initial.py 文件
管理
Django 自带后台管理页面, 使用前需创建管理员用户
python manage.py createsuperuser
输入用户名和密码, 邮箱地址可选
启动项目, 访问http://127.0.0.1:8000/admin/
现在还无法看到建好表, 需在 admin 中注册, 将 app 模型加入站点内, 接受站点管理
打开 App/admin.py 文件, 修改
from django.contrib import admin
from .models import Stu
# Register your models here.
# 注册Stu
admin.site.register(Stu)
新增
可视化, 直接使用 Django 管理页面新增数据
由于之前设定了 ordering = [‘age’], 故添加数据会按从小到大顺序排列
MongoDB
MongoEngine
- Models
from mongoengine import *
connect('admin', host='localhost', port=27017, username='admin', password='123456')
class Score(EmbeddedDocument):
name = StringField(required=True, max_length=200)
score = IntField(required=True)
class User(Document):
name = StringField(required=True, max_length=200)
age = IntField(required=True)
scores = ListField(EmbeddedDocumentField(Score))
meta ={
'collection': 'user'
}
转JSON
user = User.objects.filter(name='Wang').first().to_json(ensure_ascii=False)
增加
User(....).create()
# 嵌套文档增加
scores = User.objects.filter(name='Wang').first().scores
scores = list(scores)
scores.append(Score(name='C++', score=90))
User.objects.filter(name='Wang').first().update(scores=scores)
修改
# 修改值 set__
User.objects.filter(name='Wang').update(set__age=27)
# 修改嵌套文档
连接多数据库
设置
建立Django项目, 在建立两个应用app1与app2
修改settings.py文件中DATABASES
配置
连接sqlite, mysql
DATABASES = {
# 默认数据库
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
},
# MySQL
'test_mysql': {
'ENGINE': 'django.db.backends.mysql',
# 数据库名
'NAME': 'test_mysql',
'USER': 'root',
'PASSWORD': '123456',
# 数据库ip地址
'HOST': '123.56.233.200',
# 访问端口
'PORT': 3306,
#设置mysql启用严格模式
'OPTIONS': {
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
'charset': 'utf8'
}
}
连接Redis
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://[IP]:6379/0",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"CONNECTION_POOL_KWARGS": {
# 最大连接数
"max_connections": 10,
# 以字符串形式写入Redis, 为False话写入字节类型
"decode_responses": True
},
"PASSWORD": "[密码]"
}
}
}
数据库路由方法类
与settings.py同级目录下建立database_router.py文件
from django.conf import settings
DATABASE_MAPPING = settings.DATABASE_APPS_MAPPING
class DatabaseAppsRouter(object):
"""
A router to control all database operations on models for different
databases.
In case an app is not set in settings.DATABASE_APPS_MAPPING, the router
will fallback to the `default` database.
Settings example:
DATABASE_APPS_MAPPING = {'app1': 'db1', 'app2': 'db2'}
"""
def db_for_read(self, model, **hints):
""""Point all read operations to the specific database."""
if model._meta.app_label in DATABASE_MAPPING:
return DATABASE_MAPPING[model._meta.app_label]
return None
def db_for_write(self, model, **hints):
"""Point all write operations to the specific database."""
if model._meta.app_label in DATABASE_MAPPING:
return DATABASE_MAPPING[model._meta.app_label]
return None
def allow_relation(self, obj1, obj2, **hints):
"""Allow any relation between apps that use the same database."""
db_obj1 = DATABASE_MAPPING.get(obj1._meta.app_label)
db_obj2 = DATABASE_MAPPING.get(obj2._meta.app_label)
if db_obj1 and db_obj2:
if db_obj1 == db_obj2:
return True
else:
return False
return None
def allow_syncdb(self, db, model):
"""Make sure that apps only appear in the related database."""
if db in DATABASE_MAPPING.values():
return DATABASE_MAPPING.get(model._meta.app_label) == db
elif model._meta.app_label in DATABASE_MAPPING:
return False
return None
def allow_migrate(self, db, app_label, model=None, **hints):
"""
Make sure the auth app only appears in the 'auth_db'
database.
"""
if db in DATABASE_MAPPING.values():
return DATABASE_MAPPING.get(app_label) == db
elif app_label in DATABASE_MAPPING:
return False
return None
增加数据路由表与规则方法
settings.py文件中添加内容
# 数据库路由规则方法
DATABASE_ROUTERS = ['项目名.database_router.DatabaseAppsRouter']
# 数据库路由表
DATABASE_APPS_MAPPING = {
'app1':'default',
'app2': 'test_mysql',
}
Django Manager
Models
class User(models.Model):
name = models.CharField(max_length = 10)
pwd = models.CharField(max_length = 300)
此时对数据库操作需通过,
User.objects.create(name = name, pwd = pwd)
User.objects.filter(name = name)
...
若在操作过程中执行其他操作显得异常麻烦, 因此可以自定义管理器
class UserManager(models.Manager):
def add_user(self, name, pwd):
# 可执行若干代码
...
user = self.create(name = name, pwd = generate_password_hash(pwd))
return user
def get_user(self, name):
# 可执行若干代码
...
return self.get(name = name)
def find_name(self, name):
# 可执行若干代码
...
return self.filter(name = name).exists()
class User(models.Model):
name = models.CharField(max_length = 10)
pwd = models.CharField(max_length = 300)
# 赋值objects
objects = UserManager()
对User类相关操作可简化为
User.objects.add_user(name, pwd)
User.objects.find_name(name)
DRF
# models.py
import uuid as uuid
from werkzeug.security import generate_password_hash
from django.db import models
class User(models.Model):
uuid = models.UUIDField(primary_key=True, auto_created=True, default=uuid.uuid4, editable=False)
name = models.CharField(max_length=300)
pwd = models.CharField(default=generate_password_hash('123456'), max_length=300)
time = models.DateTimeField(auto_now_add=True)
from django.shortcuts import render
from rest_framework import generics
from rest_framework.viewsets import ModelViewSet
from .models import User
from .serializers import UserModelSerializer
class UserList(generics.ListCreateAPIView):
"""
get:返回全部数据
post:创建新数据
"""
queryset = User.objects.all()
serializer_class = UserModelSerializer
class UserDetail(generics.RetrieveUpdateDestroyAPIView):
"""
get:返回指定数据
put:更新数据
"""
queryset = User.objects.all()
serializer_class = UserModelSerializer
app/urls.py
from .views import UserList, UserDetail
from rest_framework.routers import DefaultRouter
from django.urls import path
# 路由列表
urlpatterns = [
path("user/", UserList.as_view(), name="user_list"),
path("user/<str:pk>", UserDetail.as_view(), name="user_detail")
]
# urls.py
from rest_framework import serializers
from app.models import User
class UserModelSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = "__all__"
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('app/', include("app.urls")),
]
视图与路由
访问网站本质即为访问对应 html 文件, 后再由浏览器等对其进行渲染, 最终展示出页面
视图
创建项目TestDjango并创建App应用
静态读取
- 创建目录
在 App 目录下新建 templates 文件夹
注册模板目录, 新建模板目录需在项目设置文件中进行注册
打开主目录 settings.py文件, 找到 TEMPLATES, 将新增模板路径添加至’DIRS’项中:
TEMPLATES = [
{
...
'DIRS': [
os.path.join(BASE_DIR, 'templates'),
+ os.path.join(BASE_DIR, 'App/templates')
],
...
},
]
- 创建静态文件
在 App/templates 目录下新建 index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Title</title>
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>
- 编写视图函数
App/views.py 文件
from django.shortcuts import render
# Create your views here.
def index(request):
return render(request, 'index.html')
- 绑定子路由
编写好函数后, 需将其绑定到对应路由, 由于此处是在项目中应用里配置, 故为子路由
在 App 目录下新建 urls.py 文件
from django.urls import path
from App import views
urlpatterns = [
# 将函数绑定至对应路由
path('index/', views.index)
]
- 注册子路由
绑定本应用路由后, 还需在项目中进行注册
主目录urls.py文件添加
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
...
# 注册app应用路由
+ path('App/', include('App.urls'))
...
]
此处 include()函数含义为包含 App 中所有路由, 即实现从主路由分发至子路由(路由转发)
运行, 访问http://127.0.0.1:8000/App/index
python manage.py runserver 8080
读取数据
访问http://127.0.0.1:8000/App/db, 在网页上显示数据库中所有元素信息
在 App/templates 目录下新建 db.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Title</title>
</head>
<body>
{% for i in data %}
<h1>学号 : {{ i.num }}</h1>
<h2>姓名 : {{ i.name }}</h2>
<h2>年龄 : {{ i.age }}</h2>
{% if i.sex == 'M' %}
<h2>性别 : 男</h2>
{% elif i.sex == 'W' %}
<h2>性别 : 男</h2>
{% endif %} {% endfor %}
</body>
</html>
此处 data 为数据库中值, 读取 html 作为参数传入
- 编写视图函数
编辑 App/views.py, 增加
...
def get_db(request):
# 获取数据中全部信息
stu_list = [i for i in Stu.objects.all()]
return render(request, 'db.html', {'data' : stu_list})
- 添加路由
编辑 app/urls.py, 增加
urlpatterns = [
...
path('get_db/', views.db)
]
运行项目, 访问http://127.0.0.1:8000/App/get_db
动态路由
关键字实现
- 单关键字
App/views.py
from django.http import HttpResponse
from django.shortcuts import render
# Create your views here.
def index(request, value):
return HttpResponse("URL value = " + value)
App/urls.py
from django.urls import path, re_path
from App import views
urlpatterns = [
# 将函数绑定至对应路由
re_path(r'^index/(\w+)$', views.index)
]
项目urls.py文件
from django.contrib import admin
from django.urls import path, include
import App.views
urlpatterns = [
path('admin/', admin.site.urls),
# 注册app应用路由
path('App/', include('App.urls'))
]
参数 | 含义 |
---|---|
\w |
匹配字母、数字、下划线, 等价于[A-Za-z0-9_] |
+ |
匹配前面的子表达式一次或多次 |
$ |
表示结尾 |
此时可匹配127.0.0.1:8080/index/<字符>, 并且<字符>部分值将作为 index 函数第二个参数字符>字符>
- 多关键字
App/views.py
from django.http import HttpResponse
def value(request, v1, v2):
res = "v1:%s v2:%s"%(v1, v2)
return HttpResponse(res)
App/urls.py
from django.urls import path, re_path
from App import views
urlpatterns = [
re_path(r'^value/(?P<v1>\w+)/(?P<v2>\w+)', views.value),
]
前面 w+传给 v1, 后面 w+传给 v2, 此时可匹配127.0.0.1:8000/value/<字符1>/<字符2>
这类 url, 并且字符1将传给 value 函数v1参数, 字符2将传给value函数v2参数
反射实现
反射, 通过输入函数名调用函数
App/urls.py
from django.urls import path, re_path
from App import views
urlpatterns = [
re_path(r'^func/(?P<fuc_name>\w+)/$', views.use_fuc_byname),
]
App/views.py
from django.http import HttpResponse
def use_fuc_byname(request, fuc_name):
return eval(fuc_name)(request)
def hello_world(request):
return HttpResponse('HELLO WORLD')
def goodbye_world(request):
return HttpResponse('GOODBYE WORLD')
访问http:127.0.0.1:8000/func/hello_world
, 会自动调用 hello_world()
- 删除硬编码URL
硬编码即href里的”/polls/”部分
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
它对于代码修改非常不利, 前面给urls定义了一个name别名, 可以用它来解决这个问题, 具体代码如下:
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
Django会在polls.urls文件中查找name=’detail’的路由, 具体的就是下面这行:
path('<int:question_id>/', views.detail, name='detail'),
若想将polls的detail视图的URL更换为polls/specifics/12/, 那么仅仅只需要在polls/urls.py文件中, 将对应的正则表达式改成下面这样的就行, 所有模板中对它的引用都会自动修改成新的链接
# 添加新的单词'specifics'
path('specifics/<int:question_id>/', views.detail, name='detail'),