安装:pip install django[==版本]
卸载:pip uninstall django
django-admin startproject 项目名称,如:
django-admin startproject project1
启动命令如下:
cd project1
python manage.py runserver [port]
port为可选,默认8000
如:python manage.py runserver 5000
创建好后,目录结构如下:
project1
project1
__init__.py
settings.py
urls.py
wsgi.py
manage.py
各文件作用如下:
BASE_DIR:自动生成的当前项目的绝对路径
DEBUG:True为调试模式,生产环境中设置为False
ALLOWED_HOSTS:允许访问该项目的地址列表,设置示例如下:
INSTALLED_APPS:应用列表
MIDDLEWARE:中间件
ROOT_URLCONF:根级url配置
TEMPLATES:模板配置
DATABASES:数据库配置
LANGUAGE_CODE:语言配置,中文"zh-Hans";英文"en-us"
TIME_ZONE:时区配置,“UTC"为格林威治时间,中国时区为"Asia/Shanghai”
Django采用MTV设计模式,MTV和MVC设计模式区别如下:
MVC(Model-View-Controller)
MTV(Model-Template-View)
作用:接收浏览器请求,通过HttpResponse对象返回数据。
创建视图函数:
在项目包下(settings.py同级)下创建views.py
视图函数编写:
def xxx_view(request[, params]):
return HttpResponse对象
settings.py中指定了根路由位置:ROOT_URLCONF = ‘project1.urls’,客户端发送请求时。通过路由配置urls.py找到对应的视图函数处理并返回。urls.py初始配置文件如下:
urlpatterns = [
path('admin/', admin.site.urls),
]
需要配置路由时,只需要在urlpatterns加入响应的配置即可。
配置路由时,需要用到url()函数,url()描述了路由和视图函数的对应关系,用法如下:
from django.conf.urls import url
url(regex, view, kwargs=None, name=None)
'''
regex 字符串类型,匹配的请求路径,支持正则
view 该路由对应的视图函数名
name 地址的别名
'''
URL的格式如下:
protocol://hostname[:port]/path[?query][#fragment]
protocol:协议,如http、https
hostname:主机名
port:端口
path:路由地址
query:参数参数,多个参数用&隔开
fragment:信息片段
如:http://127.0.0.1:8000/test/page?name=aaa&passwd=bbb#xxx
该方式为最基本的路由函数,不带参数,直接通过路由找到视图函数。
在regex参数中,用正则分组提取参数后,传递给视图函数。
在regex中,为分组起一个别名:(?P),参数传递时,使用键值对传参。
示例如下:
urls.py:
from django.contrib import admin
from django.urls import path
from django.conf.urls import url
from . import views
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^test1$', views.test1_view),
url(r'^(\w+)/test2/(\w+)', views.test2_view),
url(r'^test3/(?P\w+)/(?P\w+)' ,views.test3_view),
]
views.py:
from django.http import HttpResponse
def test1_view(request):
html = 'This is my first test page.
'
return HttpResponse(html)
def test2_view(request, str1, str2):
# 路由中第一个分组传递给str1,第二个传递个str2
html = 'The recieved data is %s and %s
' % (str1, str2)
return HttpResponse(html)
def test3_view(request, p1, p2):
# 参数名p1,p2需要和路由中的命名分组一致
html = 'The recieved data is %s and %s
' % (p1, p2)
return HttpResponse(html)
访问对应url,结果分别如下:
http://127.0.0.1:8000/test1
This is my first test page.
http://127.0.0.1:8000/abc/test2/def
The recieved data is abc and def
http://127.0.0.1:8000/test3/ab/cd
The recieved data is ab and cd
参考:https://yiyibooks.cn/xx/Django_1.11.6/ref/request-response.html
视图函数的第一个参数是HttpRequest对象,服务器接收http协议请求后,会根据请求报文创建HttpRequest对象
HttpRequest.scheme 字符串,表示请求方法,常为http或https
HttpRequest.body 字节串,HTTP请求正文
HttpRequest.path 请求页面的完整路径的字符串,如/test1
HttpRequest.path_info URL字符串,如/test1
HttpRequest.method 请求使用的HTTP方法,大写,如GET,POST
HttpRequest.encoding 字符串,提交的数据的编码方式,None表示默认设置,可手动设置该属性置
HttpRequest.content_type 从CONTENT_TYPE头解析的请求的MIME类型的字符串,如:text/plain
HttpRequest.content_params 包含在CONTENT_TYPE标题中的键/值参数字典
HttpRequest.GET 类字典对象,含GET所有参数,如:
HttpRequest.POST 类字典对象,含POST所有数据。
HttpRequest.FILES 类字典对象,含所有上传的文件。
HttpRequest.COOKIES 包含所有Cookie的字典。 键和值都为字符串。
HttpRequest.META 包含所有可用HTTP标头的字典。
HttpRequest.session 可读写的,类似字典的对象,表示当前会话。
get_host() 主机和端口,如:127.0.0.1:8000
get_port() 字符串格式,端口,如:8000
get_full_path() 返回path,含查询字符串,如:/test1?a=1&b=2&c=3
build_absolute_uri() 返回绝对URI,如:http://127.0.0.1:8000/testrequest?a=1&b=2
is_secure() 如果请求安全(HTTPS),则返回True,否则False
request.GET和request.POST属性都是QueryDict对象的实例。QueryDict是字典的子类,实现了字典的所有标准方法。
QueryDict对象常用方法如下:
QueryDict['key'] key不存在,则报错
QueryDict.get(key,default=None) key存在,则返回对应值,不存在,返回默认值
QueryDict.getlist(key,default=None) key存在,返回值列表,不存在,返回默认值,默认为[]
继承自HttpResponseBase,用于向客户端返回响应内容,格式如下:
HttpResponse(content, content_type=None, status=None)
'''
content 响应体
content_type 返回数据的MIME类型,常用如下:
text/html 默认,html文件
text/plain 纯文本
text/css css文件
text/javascript js文件
multipart/form-data 表单提交
application/json json传输
application/xml xml文件
status 状态码,默认200
'''
子类 作用 状态码
HttpResponseRedirect 重定向 302
HttpResponseNotModified 未修改 304
HttpResponseBadRequest 错误请求 400
HttpResponseNotFound 无资源 404
HttpResponseForbidden 请求被进制 403
HttpResponseServerError 服务器错误 500
模板的作用是根据视图函数中传递的字典数据,生成动态变化的html页面。
官方参考文档:https://docs.djangoproject.com/en/4.0/topics/templates/
在项目根路径下,创建templates文件夹
修改配置文件settings.py:
# 初始配置
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',
],
},
},
]
'''
BACKEND 模板引擎
DIRS 模板搜索路径
APP_DIRS 是否在应用的templates文件夹中搜索模板文件
'''
# 修改如下:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'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',
],
},
},
]
方式一:通过loader加载
from django.template import loader
temp = loader.get_template('模板文件名')
html = t.render(字典数据)
return HttpResponse(html)
方式二:使用render直接加载(常用)
from django.shortcuts import render
return render(request, '模板文件名', 字典数据)
{{ 变量名 }} 直接通过变量名获取变量
{{ 变量名.index }} 获取列表项,index从0开始
{{ 变量名.key }} 根据key,获取字典value
{{ 方法名 }} 调用方法
{{ 对象.方法名 }} 调用类方法
示例如下:
路由urls.py:
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^testtemplate$', views.test_template_view)
]
视图views.py:
from django.shortcuts import render
def test_template_view(request):
str1 = 'abc'
lst1 = ['abc', 123]
dic1 = {"key1": "value1", "key2": "value2"}
func1 = say("hello")
func2 = say()
cls1 = Student().get_name('Lilei')
cls2 = Student()
return render(request, 'test_template.html', locals())
def say(p1="byebye"):
return 'say ' + p1
class Student:
def get_name(self, name='Gaohui'):
return "My name is {}".format(name)
模板templates:test_template.html:
<h3>str1:{{ str1 }}h3>
<h3>lst1:{{ lst1 }}, lst1[0]:{{ dic1.0 }}, lst1[1]:{{ lst1.1 }}h3>
<h3>dic1:{{ dic1 }}, dic1['key1']:{{ dic1.key1 }}, dic1['key2']:{{ dic1.key2 }}h3>
<h3>func1:{{ func1 }}, func2:{{ func2 }}h3>
<h3>cls1:{{ cls1 }}, cls2:{{ cls2.get_name }}h3>
运行结果如下:
标签的作用是在模板中可以使用服务端的一些功能,如判断,循环等。
参考:https://docs.djangoproject.com/en/4.0/ref/templates/builtins/#ref-templates-builtins-tags
语法:
{% if 条件1 %}
...
{% elif 条件2 %}
...
{% else %}
...
{% endif %}
注意:if标签中使用()无效。
语法:
{% for 变量 in 可迭代对象 %}
...
{% empty %}
可迭代对象为空时执行的语句
{% endfor %}
内置变量forloop:
forloop.counter 从1开始计数的当前迭代
forloop.counter0 从0开始计数的当前迭代
forloop.revcounter 从len开始降序计数的当前迭代
forloop.revcounter0 从len-1开始降序计数的当前迭代
forloop.first 第一次循环,为真,否则为假
forloop.last 最后一次循环,为真,否则为假
forloop.parentloop 嵌套循环的外层循环
示例如下:
视图函数:
def test_label_view(request):
lst1 = ['东邪', '西毒', '南帝', '北丐']
lst2 = []
return render(request, 'test_label.html', locals())
模板html:
<h3>the lst1 is:{{ lst1 }}h3>
{% for i in lst2 %}
<h3>{{ forloop.counter0 }}:{{ i }}h3>
{% empty %}
<h3>lst2为空h3>
{% endfor %}
{% for i in lst1 %}
{% if forloop.first %}
<h3>#################h3>
{% endif %}
<h3>{{ forloop.counter }} {{ i }}h3>
{% if forloop.last %}
<h3>$$$$$$$$$$$$$$$$$h3>
{% endif %}
{% endfor %}
运行结果:
extends标签:子模版继承父模板,生成和父模板完全相同的一个页面,一般写在第一行。语法如下:
{% extends '父模板名称' %
block标签:在父模板中定义可由子模板覆盖的块,语法如下:
{% block block_name %}
该部分内容可以被子模块中的同名模块覆盖
{% endblock block_name %}
在urls.py中,定义路由时,可以指定name参数,给url起一个别名,在模板中,可以通过该别名反向解析出url路径。语法如下:
{% url '别名' %}
{% url '别名' '参数1' '参数2' %}
示例:一个网站包含注册登录栏、导航栏、内容栏、和网页底部;主页和导航栏中的条目整体页面使用相同的框架,具体页面内容不同,此时即可使用模板继承和覆盖,如下:
路由urls.py:
from django.conf.urls import url
from django.contrib import admin
from . import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$', views.index_view),
url(r'^sport$', views.sport_view),
url(r'^music$', views.music_view, name='music'),
url(r'^page(\d+)$', views.pagen_view, name='pagen')
]
视图views.py:
from django.http import HttpResponse
from django.shortcuts import render
def index_view(request):
return render(request, 'base.html')
def sport_view(request):
return render(request, 'sport.html')
def music_view(request):
return render(request, 'music.html')
def pagen_view(request, n):
return HttpResponse('第' + n + '页')
模板:
base.html:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
{% block page_title %}
<title>主页title>
{% endblock page_title %}
head>
<body>
<h1 style="background-color:blue;width:300px">注册,登录h1>
<a href="/">主页a>
<a href="/sport">体育a>
<a href="{% url 'music' %}">音乐a>
{% block page_info %}
<h2 style="background-color:orange;width:300px;height:200px">网站主页h2>
<a href="{% url 'pagen' 1 %}">第一页a>
<a href="{% url 'pagen' 2 %}">第二页a>
{% endblock page_info %}
<h1 style="background-color:gray;width:300px">联系我们h1>
body>
html>
sport.html:
{% extends 'base.html' %}
{% block page_title %}
<title>体育title>
{% endblock page_title %}
{% block page_info %}
<h2 style="background-color:green;width:300px;height:200px">体育专题页h2>
{% endblock page_info %}
music.html:
{% extends 'base.html' %}
{% block page_title %}
<title>音乐title>
{% endblock page_title %}
{% block page_info %}
<h2 style="background-color:red;width:300px;height:200px">音乐专题页h2>
{% endblock page_info %}
说明:在base.html中定义了两个block:page_title和page_info,这两个block在子模板中可以用同名block替换掉,起到部分继承主页面的效果。pagen使用了url反向解析,通过反向解析标签{% url ‘pagen’ 1 %}定位到url中name='pagen’的路由,并完成参数传递。运行结果如下:
作用:访问静态文件。静态文件是指不和服务器做动态交互的文件,如图片、视频、静态html文件等等。
访问静态文件有两种方式,一是通过{% static %}标签访问,二是通过STATIC_URL访问。
先在项目根目录下建static文件夹,在settings.py中做如下配置:
STATIC_URL = '/static/' # 静态文件url地址
STATICFILES_DIRS =(
os.path.join(BASE_DIR, 'static'), # 静态文件存储路径
)
通过路径访问:
<img src="/static/xxx.jpg" alt="">
<img src="http://127.0.0.1:8000/static/吴建剑.jpg" alt="">
通过{% static %}标签访问:
{% load static %}
{% static '静态资源路径' %}
如:
{% load static %}
标签中的内容被注释,用法如下:
{% comment %}
...
{% endcomment %}
参考文档:https://docs.djangoproject.com/en/4.0/ref/templates/builtins/#ref-templates-builtins-filters
在变量输出之前对其进行处理。语法格式如下:
{{ 变量|过滤器1:参数1|过滤器2:参数2... }}
常用过滤器如下:
add 将参数和值相加,如:{{ value|add:"2" }},4->6
addslashes 在引号前添加斜杠,如:{{ value|addslashes }},"I'm using"->"I\'m using"
capfirst 将值的第一个字符大写,如:{{ value|capfirst }},"django"->"Django"
...
详见参考文档。
一个项目可以包含多个应用,每个应用都是一个独立的模块,有自己的视图、路由、模板和模型。通过app的使用,可以降低模块之间的耦合性。
首先,用如下命令创建一个应用:
python manage.py startapp 应用名
如:
python manage.py startapp movie
然后在settings.py中配置应用:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'movie',
]
创建完成后,会在项目根目录下生成一个应用包。
每个应用都可以有自己的路由,由基础路由配置文件分发到应用,应用自行处理各自的请求。基础路由可以通过include函数将路由转发到各个应用进行分布式处理。函数格式如下:
from django.conf.urls import include
include('应用名.url模块名')
如:新建两个应用movie和music,并为两个应用各自单独建一个urls.py路由文件。基础路由中配置如下:
url(r'^movie/', include('movie.urls')),
url(r'^music/', include('music.urls')),
movie应用:
urls.py:
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^index$', views.index),
]
views.py:
from django.shortcuts import render
from django.http import HttpResponse
# Create your views here.
def index(request):
return HttpResponse("this is movie's index.")
music应用:
urls.py:
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^index$', views.index),
]
views.py:
from django.shortcuts import render
from django.http import HttpResponse
# Create your views here.
def index(request):
return HttpResponse("this is music's index.")
前端访问url:
http://127.0.0.1:8000/movie/index
http://127.0.0.1:8000/music/index
显示结果分别如下:
this is movie's index.
this is music's index.
模型层主要用于数据库层的封装,通过封装可以以类、对象的方式来操作数据库,避免了通过sql语句直接操作。
ORM框架全称Object Relational Mapping,对象关系映射。通过ORM映射可以建立模型类和数据表之间的映射关系。对数据库的操作都转化为对类和对象的操作,可以避免不同数据库之间操作的差异。
ORM映射关系如下:
类 数据表
属性 字段
对象 数据行
模型类继承自django.db.models.Model。
以MySQL数据库为例,需先安装 pymysql包:pip install pymysql
第一步:注册一个app:movie
第二步:创建数据库:
create database myweb character set utf8 collate utf8_general_ci; -- 大小写不敏感
第三步:配置settings.py:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'myweb',
'USER': 'xxx',
'PASSWORD': 'xxx',
'HOST': '127.0.0.1',
'PORT': 3306,
}
}
第四步:配置项目的__init__.py:
import pymysql
pymysql.install_as_MySQLdb()
第五步:在app中添加模型类:movie/models.py
from django.db import models
# Create your models here.
class Movie(models.Model):
name = models.CharField(max_length=30, verbose_name='电影名')
country = models.CharField(max_length=30, verbose_name='国家')
price = models.DecimalField('票价', max_digits=6, decimal_places=2, default=0.0)
第六步:数据库迁移
数据库迁移的作用是将模型类同步到数据库。在app下有一个mi’grations的文件夹,用来存放迁移文件。迁移分两步完成,首先生成/更新迁移文件;然后再执行迁移脚本,完成迁移。
生成迁移文件:
python manage.py makemigrations
提示信息如下:
Migrations for 'movie':
movie\migrations\0001_initial.py
- Create model Movie
查看movie/migratins文件夹下成功生成了迁移文件:
0001_initial.py
此时数据库中还未真正的创建表,需要执行迁移脚本:
python manage.py migrate
提示信息如下:
Operations to perform:
Apply all migrations: admin, auth, contenttypes, movie, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying auth.0010_alter_group_name_max_length... OK
Applying auth.0011_update_proxy_permissions... OK
Applying auth.0012_alter_user_first_name_max_length... OK
Applying movie.0001_initial... OK
Applying sessions.0001_initial... OK
迁移完成后,可以查看表已生成,生成的表名默认为app名_类名:
mysql> desc movie_movie;
+---------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+--------------+------+-----+---------+----------------+
| id | bigint | NO | PRI | NULL | auto_increment |
| name | varchar(30) | NO | | NULL | |
| country | varchar(30) | NO | | NULL | |
| price | decimal(6,2) | NO | | NULL | |
+---------+--------------+------+-----+---------+----------------+
参考官方文档:https://docs.djangoproject.com/en/4.0/ref/models/fields/#model-field-types
常见的对应关系如下:
BooleanField(**options) tinyint(1)
CharField(max_length=None, **options) varchar
DateField(auto_now=False, auto_now_add=False, **options) date
auto_now:保存对象时,自动设置当前时间
auto_now_add:创建对象时,自动设置当前时间
DateTimeField(auto_now=False, auto_now_add=False, **options) datetime
DecimalField(max_digits=None, decimal_places=None, **options) decimal
max_digits:总位数
decimal_places:小数位数
EmailField(max_length=254, **options) varchar
FloatField(**options) double
IntegerField(**options) int
TextField(**options) longtext
TimeField(auto_now=False, auto_now_add=False, **options) time
URLField(max_length=200, **options) varchar(200)
null 默认False,True时表示该字段可以为空
blank 默认False,True时表示该字段可以为空
db_column 列名,未指定时使用属性名作为列名
db_index 默认False,True时表示为该字段创建索引
default 设置默认值,null=False时建议加上
primary_key True时表示设置该字段为主键
unique True时,表示该字段不可重复
verbose_name 别名,在admin上以该名称显示
数据库的基本操作通过管理器对象来实现。继承自models.Model的模型类,都会继承一个objects对象,这个对象就是管理器对象。
数据库的CRUD可以通过模型的管理器对象来实现。
方式1:通过管理器对象创建
from movie import models
models.Movie.objects.create(name='十面埋伏',country='中国')
方式2:创建Movie实例对象,调用save()保存
from movie import models
mv = models.Movie(name='月光宝盒',country='中国')
mv.save()
示例如下:
数据库中初始共3条数据:
+----+----------+---------+-------+--------+
| id | name | country | price | isOpne |
+----+----------+---------+-------+--------+
| 1 | 十面埋伏 | 中国 | 0.00 | 0 |
| 2 | 大圣娶亲 | 中国 | 0.00 | 1 |
| 3 | 月光宝盒 | 中国 | 0.00 | 0 |
+----+----------+---------+-------+--------+
from movie import models
mvs = models.Movie.objects.all()
# , , ]>
for mv in mvs:
print(mv.name, mv.country)
# 十面埋伏 中国
# 大圣娶亲 中国
# 月光宝盒 中国
models.Movie.objects.get(id=1)
#
models.Movie.objects.filter(id__gt=1)
# , ]>
models.Movie.objects.exclude(id__gt=1)
# ]>
mvs = models.Movie.objects.values('id','name')
#
for mv in mvs:
print(mv["name"], mv["id"])
# 十面埋伏 1
# 大圣娶亲 2
# 月光宝盒 3
models.Movie.objects.filter(id__gt=2).values('id','name')
#
models.Movie.objects.get(id__exact=1).values('id','name')
# 报错:AttributeError: 'Movie' object has no attribute 'values'
models.Movie.objects.filter(id__exact=1).values_list('id','name')
#
models.Movie.objects.filter(id__gt=1).order_by('-id')
# , ]>
models.Movie.objects.order_by('-id')
# , , ]>
描述查询条件。如下:
id_exact=1 id=1
name__contains='ab' name like '%ab%'
name__startswith('ab') name like 'ab%'
name__endswith('ab') name like '%ab'
id__gt=1 id>1
id__gte=1 id>=1
id__lt=1 id<1
id__lte=1 id<=1
id__in=[1,2] id in (1,2)
id__range=[10,20] id between 10 and 20
聚合函数包含:Sum、Avg、Count、Max、Min。
不带分组的聚合
查询语法如下:
models.模型类名.objects.aggregate(结果变量名=聚合函数('字段'))
# 返回值为结果变量名和值组成的字典。
分组聚合
查询语法如下:
models.模型类名.objects.values('字段').annotate(结果变量名=聚合函数('字段'))
models.模型类名.objects.values_list('字段').annotate(结果变量名=聚合函数('字段'))
# 返回值为QuerySet
示例如下:
数据库数据:
+----+----------+---------+-------+--------+
| id | name | country | price | isOpne |
+----+----------+---------+-------+--------+
| 1 | 十面埋伏 | 中国 | 50.00 | 0 |
| 2 | 大圣娶亲 | 中国 | 60.00 | 1 |
| 3 | 月光宝盒 | 中国 | 70.00 | 0 |
| 4 | 蝴蝶效应 | 美国 | 35.00 | 0 |
| 5 | 黑客帝国 | 美国 | 45.00 | 0 |
+----+----------+---------+-------+--------+
from movie import models
models.Movie.objects.aggregate(avgPrice=Avg('price'))
# {'avgPrice': Decimal('52.000000')}
models.Movie.objects.values_list('country').annotate(max_price=Max('price'))
#
models.Movie.objects.values('country').annotate(max_price=Max('price'))
#
单条更新:通过get查出结果对象,对结果对象进行更新
from movie import models
mv = models.Movie.objects.get(id__exact=1)
mv.price=80
mv.isOpne=1
mv.save()
批量更新:通过filter查出QuerySet对象,对其更新,或者针对objects对象,更新所有值:
from movie import models
mvs = models.Movie.objects.filter(id__gte=3)
mvs.update(price=50) # 将id>=3的记录price字段更新为50
models.Movie.objects.update(price=35) # 将所有记录的price更新为35
不论是单条,还是结果集,都用delete()方法删除,objects对象无delete方法。
示例如下:
models.Movie.objects.get(id__exact=1).delete() # 删除id为1的记录
models.Movie.objects.filter(id__gt=3).delete() # 删除id>3的记录
models.Movie.objects.all().delete() # 删除全部记录
F对象用于不获取字段值的情况下操作字段值,或两个字段间的比较。
用法如下:
F('列名')
如:
from django.db.models import F
from movie import models
# 将所有电影价格下降70%
models.Movie.objects.all().update(price=F('price')*0.7)
在条件中实现或、与、非操作,语法如下:
Q(条件1)|Q(条件2) 条件1或条件2成立
Q(条件1)&Q(条件2) 条件1和条件2都要成立
~Q(条件1) 条件1不成立
示例如下:
from django.db.models import Q
models.Movie.objects.filter(Q(country__exact='中国')|Q(price__gt=45))
# 查找country为中国,或price>45的记录
models.Movie.objects.filter(Q(country__exact='美国')&Q(price__lt=45))
# 查找country为美国,且price小于45的记录
models.Movie.objects.filter(~Q(country__exact='美国'))
# 查找country不为美国的记录
使用objects的raw()方法,返回RawQuerySet对象。示例如下:
from movie import models
mvs = models.Movie.objects.raw("select * from movie_movie where country='中国'")
#
for mv in mvs:
print(mv.name, mv.price)
# 霸王别姬 24.50
# 藏龙卧虎 21.00
# 英雄本色 28.00
增删改通过游标cursor实现。游标在django.db.connection包中,使用前需先导入,示例如下:
from django.db import connection
connection.cursor().execute('update movie_movie set price=80 where id=10')
# 更新id=10的记录price为80
为防止出现异常未释放cursor资源,一般用with语句进行操作:
from django.db import connection
with connection.cursor() as c:
c.execute('delete from movie_movie where id=10')
# 删除id=10的记录。
关联关系映射分为1对1,1对多,多对多。
一对一表示两个表的对象有唯一的对应关系,如一个丈夫对应一个妻子。一对一通过models.OneToOneField()实现,具体语法如下:
class M1(models.Model):
xxx
class M2(models.Model):
xxx
attr = models.OneToOneField(M1)
示例:
在应用music的models.py下建两个类,一个是Musician,一个是Spouse,二者为1对1关系。
from django.db import models
# Create your models here.
class Musician(models.Model):
name = models.CharField('音乐家', max_length=30)
class Meta:
db_table = 'musician' # 内置类,将表名修改为musician
class Spouse(models.Model):
name = models.CharField('配偶', max_length=30)
musician = models.OneToOneField(Musician, on_delete=models.CASCADE)
class Meta:
db_table = 'spouse'
完成数据迁移后,查看表结构:
mysql> desc musician;
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| id | bigint | NO | PRI | NULL | auto_increment |
| name | varchar(30) | NO | | NULL | |
+-------+-------------+------+-----+---------+----------------+
mysql> desc spouse;
+-------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-------------+------+-----+---------+----------------+
| id | bigint | NO | PRI | NULL | auto_increment |
| name | varchar(30) | NO | | NULL | |
| musician_id | bigint | NO | UNI | NULL | |
+-------------+-------------+------+-----+---------+----------------+
数据插入:
from music import models
mus1 = models.Musician.objects.create(name='周杰伦')
mus2 = models.Musician.objects.create(name='陈奕迅')
mus3 = models.Musician.objects.create(name='王心凌')
sp1 = models.Spouse.objects.create(name='昆凌',musician=mus1)
sp2 = models.Spouse.objects.create(name='陈夫人',musician=mus2)
查看插入结果:
mysql> select * from musician;
+----+--------+
| id | name |
+----+--------+
| 1 | 周杰伦 |
| 2 | 陈奕迅 |
| 3 | 王心凌 |
+----+--------+
mysql> select * from spouse;
+----+--------+-------------+
| id | name | musician_id |
+----+--------+-------------+
| 1 | 昆凌 | 1 |
| 3 | 陈夫人 | 2 |
+----+--------+-------------+
数据查询:
通过musician查spouse,查询方式为:实例对象.映射对象小写类名:
mus1 = models.Musician.objects.get(name='陈奕迅')
mus2 = models.Musician.objects.get(name='王心凌')
print(mus1.spouse.name)
# 陈夫人
print(mus2.spouse.name)
# 无关联对象时,会抛异常:RelatedObjectDoesNotExist
通过spouse查musician,查询方式为:实例对象.属性名:
sp = models.Spouse.objects.get(name='陈夫人')
print(sp.musician.name)
# 陈奕迅
一对多映射表示一个对象关联多个对象,如一个音乐家有多首作品。一对多语法如下:
class M1(models.Model):
xxx
class M2(models.Model):
xxx
attr = models.ForeignKey(M1)
示例:新建一个Music类,和Musician是一对多的关系:
from django.db import models
# Create your models here.
class Musician(models.Model):
name = models.CharField('音乐家', max_length=30)
class Meta:
db_table = 'musician'
class Spouse(models.Model):
name = models.CharField('配偶', max_length=30)
musician = models.OneToOneField(Musician, on_delete=models.CASCADE)
class Meta:
db_table = 'spouse'
class Music(models.Model):
title = models.CharField('歌名', max_length=30)
musician = models.ForeignKey(Musician, null=True, on_delete=models.SET_NULL)
class Meta:
db_table = 'music'
表结构如下:
mysql> desc music;
+-------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-------------+------+-----+---------+----------------+
| id | bigint | NO | PRI | NULL | auto_increment |
| title | varchar(30) | NO | | NULL | |
| musician_id | bigint | YES | MUL | NULL | |
+-------------+-------------+------+-----+---------+----------------+
数据插入:
from music import models
m1 = models.Musician.objects.get(name='陈奕迅')
mus1 = models.Music.objects.create(title='K歌之王', musician=m1)
mus2 = models.Music.objects.create(title='十面埋伏', musician=m1)
mus3 = models.Music.objects.create(title='富士山下', musician=m1)
查看插入的数据:
mysql> select * from musician;
+----+--------+
| id | name |
+----+--------+
| 1 | 周杰伦 |
| 2 | 陈奕迅 |
| 3 | 王心凌 |
+----+--------+
mysql> select * from music;
+----+----------+-------------+
| id | title | musician_id |
+----+----------+-------------+
| 1 | K歌之王 | 2 |
| 2 | 十面埋伏 | 2 |
| 3 | 富士山下 | 2 |
+----+----------+-------------+
数据查询:
通过1查多,对象.关联对象小写_set,如:
m1 = models.Musician.objects.get(name='陈奕迅')
mus = m1.music_set.all()
# 支持all()、filter()、get()等方法
# , , ]>
for mu in mus:
print(mu.title)
# K歌之王
# 十面埋伏
# 富士山下
通过多查1:
mu = models.Music.objects.get(id=1)
mu.musician.name
# 陈奕迅
一个音乐家可以签约多个平台,一个平台可以有多个音乐家,音乐家和平台之间就是多对多的关系。多对多映射通过中间表实现。
示例如下:
from django.db import models
# Create your models here.
class Musician(models.Model):
name = models.CharField('音乐家', max_length=30)
class Meta:
db_table = 'musician'
class Spouse(models.Model):
name = models.CharField('配偶', max_length=30)
musician = models.OneToOneField(Musician, on_delete=models.CASCADE)
class Meta:
db_table = 'spouse'
class Music(models.Model):
title = models.CharField('歌名', max_length=30)
musician = models.ForeignKey(Musician, null=True, on_delete=models.SET_NULL)
class Meta:
db_table = 'music'
class Platform(models.Model):
platname = models.CharField('平台', max_length=30)
musician = models.ManyToManyField(Musician)
class Meta:
db_table = 'platform'
数据库迁移完成后,查询表结构:
mysql> desc musician;
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| id | bigint | NO | PRI | NULL | auto_increment |
| name | varchar(30) | NO | | NULL | |
+-------+-------------+------+-----+---------+----------------+
mysql> desc platform;
+----------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+----------------+
| id | bigint | NO | PRI | NULL | auto_increment |
| platname | varchar(30) | NO | | NULL | |
+----------+-------------+------+-----+---------+----------------+
mysql> desc platform_musician;
+-------------+--------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------+------+-----+---------+----------------+
| id | bigint | NO | PRI | NULL | auto_increment |
| platform_id | bigint | NO | MUL | NULL | |
| musician_id | bigint | NO | MUL | NULL | |
+-------------+--------+------+-----+---------+----------------+
数据插入:
from music import models
m1 = models.Musician.objects.get(id=1) # 周杰伦
m2 = models.Musician.objects.get(id=2) # 陈奕迅
p1 = models.Platform.objects.create(platname='QQ音乐')
p2 = models.Platform.objects.create(platname='网易云音乐')
p3 = models.Platform.objects.create(platname='咪咕音乐')
m1.platform_set.add(p1) # m1关联p1
m1.platform_set.add(p2) # m1关联p2
m1.platform_set.create(platname='酷我音乐') # 创建新的platform,并关联m1
p2.musician.add(m2) # p2关联m2
查看结果:
mysql> select * from musician;
+----+--------+
| id | name |
+----+--------+
| 1 | 周杰伦 |
| 2 | 陈奕迅 |
| 3 | 王心凌 |
+----+--------+
mysql> select * from platform;
+----+------------+
| id | platname |
+----+------------+
| 1 | QQ音乐 |
| 2 | 网易云音乐 |
| 3 | 咪咕音乐 |
| 4 | 酷我音乐 |
+----+------------+
mysql> select * from platform_musician;
+----+-------------+-------------+
| id | platform_id | musician_id |
+----+-------------+-------------+
| 1 | 1 | 1 |
| 2 | 2 | 1 |
| 4 | 2 | 2 |
| 3 | 4 | 1 |
+----+-------------+-------------+
数据查询:
通过musician查platform:
m1 = models.Musician.objects.get(id=1)
m1.platform_set.all()
# , , ]>
通过platform查musician:
p1 = models.Platform.objects.get(id=2)
p1.musician.all()
# , ]>