一、安装和卸载

安装: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

创建好后,目录结构如下:

project1project1__init__.pysettings.pyurls.pywsgi.pymanage.py

各文件作用如下:

  • manage.py:项目管理主程序,用于管理整个项目的开发运行的调式。
  • project1:项目包文件夹
    • __init__.py:包初始化文件,当项目包被导入(import)时此文件会自动运行。
    • settings.py:项目配置文件,启动服务时自动调用
    • urls.py:基础路由配置文件
    • wsgi.py:Web Server Gateway Interface,WEB服务网关接口,部署项目时使用

三、配置文件settings.py说明

  • BASE_DIR:自动生成的当前项目的绝对路径

  • DEBUG:True为调试模式,生产环境中设置为False

  • ALLOWED_HOSTS:允许访问该项目的地址列表,设置示例如下:

    • []:仅127.0.0.1和localhost可访问
    • [‘*’]:所有网络地址均可访问
    • [‘192.168.11.11’, ‘192.168.22.22’]:仅列表中的两个地址可访问
  • INSTALLED_APPS:应用列表

  • MIDDLEWARE:中间件

  • ROOT_URLCONF:根级url配置

  • TEMPLATES:模板配置

  • DATABASES:数据库配置

  • LANGUAGE_CODE:语言配置,中文"zh-Hans";英文"en-us"

  • TIME_ZONE:时区配置,“UTC"为格林威治时间,中国时区为"Asia/Shanghai”

四、Django框架模式

Django采用MTV设计模式,MTV和MVC设计模式区别如下:

  • MVC(Model-View-Controller)

    • M模型层:主要用于数据库层的封装
    • V视图层:主要用于用户交互和界面展示
    • C控制层:处理请求、获取数据、返回数据
  • MTV(Model-Template-View)

    • M模型层:主要用于数据库层的封装
    • T模板层:主要用于用户交互和界面展示
    • V视图层:处理请求、获取数据、返回数据

五、View视图层

5.1、视图函数view

  • 作用:接收浏览器请求,通过HttpResponse对象返回数据。

  • 创建视图函数:

    在项目包下(settings.py同级)下创建views.py

  • 视图函数编写:

    def xxx_view(request[, params]):return HttpResponse对象
    

5.2、路由配置urls

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

5.2.1、不带分组的路由

该方式为最基本的路由函数,不带参数,直接通过路由找到视图函数。

5.2.2、带分组的路由

在regex参数中,用正则分组提取参数后,传递给视图函数。

5.2.3、带命名分组的路由

在regex中,为分组起一个别名:(?P),参数传递时,使用键值对传参。

示例如下:

urls.py:

from django.contrib import admin
from django.urls import path
from django.conf.urls import url
from . import viewsurlpatterns = [path('admin/', admin.site.urls),url(r'^test1$', views.test1_view),url(r'^(\w+)/test2/(\w+)', views.test2_view),url(r'^test3/(?P<p1>\w+)/(?P<p2>\w+)',views.test3_view),
]

views.py:

from django.http import HttpResponsedef test1_view(request):html = '<h3>This is my first test page.</h3>'return HttpResponse(html)def test2_view(request, str1, str2):# 路由中第一个分组传递给str1,第二个传递个str2html = '<h3>The recieved data is %s and %s</h3>' % (str1, str2)return HttpResponse(html)def test3_view(request, p1, p2):# 参数名p1,p2需要和路由中的命名分组一致html = '<h3>The recieved data is %s and %s</h3>' % (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 defhttp://127.0.0.1:8000/test3/ab/cd
The recieved data is ab and cd

5.3、HttpRequest请求对象

参考:https://yiyibooks.cn/xx/Django_1.11.6/ref/request-response.html

视图函数的第一个参数是HttpRequest对象,服务器接收http协议请求后,会根据请求报文创建HttpRequest对象

5.3.1、对象常用属性

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所有参数,如:<QueryDict:{'a':['1'],'b:['2']}>
HttpRequest.POST            类字典对象,含POST所有数据。
HttpRequest.FILES           类字典对象,含所有上传的文件。
HttpRequest.COOKIES         包含所有Cookie的字典。 键和值都为字符串。
HttpRequest.META            包含所有可用HTTP标头的字典。
HttpRequest.session         可读写的,类似字典的对象,表示当前会话。

5.3.2、对象常用方法

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

5.4、QueryDict对象

request.GET和request.POST属性都是QueryDict对象的实例。QueryDict是字典的子类,实现了字典的所有标准方法。

QueryDict对象常用方法如下:

QueryDict['key']                   key不存在,则报错
QueryDict.get(key,default=None)        key存在,则返回对应值,不存在,返回默认值
QueryDict.getlist(key,default=None)    key存在,返回值列表,不存在,返回默认值,默认为[]

5.5、HttpResponse对象

5.5.1、参数说明

继承自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
'''

5.5.2、HttpResponse常用子类

子类                               作用          状态码
HttpResponseRedirect             重定向         302
HttpResponseNotModified          未修改         304
HttpResponseBadRequest           错误请求        400
HttpResponseNotFound             无资源         404
HttpResponseForbidden            请求被进制      403
HttpResponseServerError          服务器错误      500

六、Template模板层

模板的作用是根据视图函数中传递的字典数据,生成动态变化的html页面。

官方参考文档:https://docs.djangoproject.com/en/4.0/topics/templates/

6.1、模板创建

  • 在项目根路径下,创建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',],},},
    ]
    

6.2、模板传参

  • 方式一:通过loader加载

    from django.template import loadertemp = loader.get_template('模板文件名')
    html = t.render(字典数据)
    return HttpResponse(html)
    
  • 方式二:使用render直接加载(常用)

    from django.shortcuts import renderreturn render(request, '模板文件名', 字典数据)
    

6.3、模板语言

6.3.1、变量

{{ 变量名 }}            直接通过变量名获取变量
{{ 变量名.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 renderdef 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 ' + p1class 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>

运行结果如下:

6.3.2、标签

标签的作用是在模板中可以使用服务端的一些功能,如判断,循环等。

参考:https://docs.djangoproject.com/en/4.0/ref/templates/builtins/#ref-templates-builtins-tags

6.3.2.1、if标签

语法:

{% if 条件1 %}
...
{% elif 条件2 %}
...
{% else %}
...
{% endif %}

注意:if标签中使用()无效。

6.3.2.2、for标签

语法:

{% 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 %}

运行结果:

6.3.2.3、extends和block标签

  • extends标签:子模版继承父模板,生成和父模板完全相同的一个页面,一般写在第一行。语法如下:

    {% extends '父模板名称' %
    
  • block标签:在父模板中定义可由子模板覆盖的块,语法如下:

    {% block block_name %}该部分内容可以被子模块中的同名模块覆盖
    {% endblock block_name %}
    

6.3.2.4、url反向解析标签

在urls.py中,定义路由时,可以指定name参数,给url起一个别名,在模板中,可以通过该别名反向解析出url路径。语法如下:

{% url '别名' %}
{% url '别名' '参数1' '参数2' %}

示例:一个网站包含注册登录栏、导航栏、内容栏、和网页底部;主页和导航栏中的条目整体页面使用相同的框架,具体页面内容不同,此时即可使用模板继承和覆盖,如下:

路由urls.py:

from django.conf.urls import url
from django.contrib import admin
from . import viewsurlpatterns = [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 renderdef 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’的路由,并完成参数传递。运行结果如下:



6.3.2.5、static标签

作用:访问静态文件。静态文件是指不和服务器做动态交互的文件,如图片、视频、静态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 %}
    <img src="{% static 'xxx.jpg' %}" alt="">
    

6.3.2.6、comment标签

标签中的内容被注释,用法如下:


{% comment %}...
{% endcomment %}

6.3.3、过滤器

参考文档: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

一个项目可以包含多个应用,每个应用都是一个独立的模块,有自己的视图、路由、模板和模型。通过app的使用,可以降低模块之间的耦合性。

7.1、创建应用

首先,用如下命令创建一个应用:

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',
]

创建完成后,会在项目根目录下生成一个应用包。

7.2、应用的分布式路由

每个应用都可以有自己的路由,由基础路由配置文件分发到应用,应用自行处理各自的请求。基础路由可以通过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 viewsurlpatterns = [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 viewsurlpatterns = [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.

八、Model模型层

模型层主要用于数据库层的封装,通过封装可以以类、对象的方式来操作数据库,避免了通过sql语句直接操作。

8.1、ORM映射

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... OKApplying auth.0001_initial... OKApplying admin.0001_initial... OKApplying admin.0002_logentry_remove_auto_add... OKApplying admin.0003_logentry_add_action_flag_choices... OKApplying contenttypes.0002_remove_content_type_name... OKApplying auth.0002_alter_permission_name_max_length... OKApplying auth.0003_alter_user_email_max_length... OKApplying auth.0004_alter_user_username_opts... OKApplying auth.0005_alter_user_last_login_null... OKApplying auth.0006_require_contenttypes_0002... OKApplying auth.0007_alter_validators_add_error_messages... OKApplying auth.0008_alter_user_username_max_length... OKApplying auth.0009_alter_user_last_name_max_length... OKApplying auth.0010_alter_group_name_max_length... OKApplying auth.0011_update_proxy_permissions... OKApplying auth.0012_alter_user_first_name_max_length... OKApplying movie.0001_initial... OKApplying 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    |                |
    +---------+--------------+------+-----+---------+----------------+
    

8.2、字段类型和数据类型对应

参考官方文档: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)      dateauto_now:保存对象时,自动设置当前时间auto_now_add:创建对象时,自动设置当前时间
DateTimeField(auto_now=False, auto_now_add=False, **options)  datetime
DecimalField(max_digits=None, decimal_places=None, **options) decimalmax_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)

8.3、字段选项

null                     默认False,True时表示该字段可以为空
blank                       默认False,True时表示该字段可以为空
db_column                   列名,未指定时使用属性名作为列名
db_index                    默认False,True时表示为该字段创建索引
default                     设置默认值,null=False时建议加上
primary_key                 True时表示设置该字段为主键
unique                      True时,表示该字段不可重复
verbose_name                别名,在admin上以该名称显示

8.4、数据库操作

数据库的基本操作通过管理器对象来实现。继承自models.Model的模型类,都会继承一个objects对象,这个对象就是管理器对象。

数据库的CRUD可以通过模型的管理器对象来实现。

8.4.1、创建Create

  • 方式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()
    

8.4.2、查询Read

8.4.2.1、查询方法

  • all():查询全量数据,返回QuerySet数组
  • get():查询指定条件的单一数据,返回结果对象,满足条件的数据不存在或超过一条都会报错
  • filter():查询符合条件的多条记录,返回QuerySet数组
  • exclude():查询不符合条件的全部记录,返回QuerySet数组
  • values():查询返回指定字段(字典)。objects对象和QuerySet均支持该属性,结果对象不支持
  • values_list():查询返回指定字段(元素)。objects对象和QuerySet均支持该属性,结果对象不支持
  • order_by():排序查询,默认升序,降序在字段前加‘-’。objects对象和QuerySet支持该属性,结果对象不支持

示例如下:

数据库中初始共3条数据:

+----+----------+---------+-------+--------+
| id | name     | country | price | isOpne |
+----+----------+---------+-------+--------+
|  1 | 十面埋伏 | 中国    |  0.00 |      0 |
|  2 | 大圣娶亲 | 中国    |  0.00 |      1 |
|  3 | 月光宝盒 | 中国    |  0.00 |      0 |
+----+----------+---------+-------+--------+
from movie import modelsmvs = models.Movie.objects.all()
# <QuerySet [<Movie: Movie object (1)>, <Movie: Movie object (2)>, <Movie: Movie object (3)>]>for mv in mvs:print(mv.name, mv.country)
# 十面埋伏 中国
# 大圣娶亲 中国
# 月光宝盒 中国models.Movie.objects.get(id=1)
# <Movie: Movie object (1)>models.Movie.objects.filter(id__gt=1)
# <QuerySet [<Movie: Movie object (2)>, <Movie: Movie object (3)>]>models.Movie.objects.exclude(id__gt=1)
# <QuerySet [<Movie: Movie object (1)>]>mvs = models.Movie.objects.values('id','name')
# <QuerySet [{'id': 1, 'name': '十面埋伏'}, {'id': 2, 'name': '大圣娶亲'}, {'id': 3, 'name': '月光宝盒'}]>for mv in mvs:print(mv["name"], mv["id"])
# 十面埋伏 1
# 大圣娶亲 2
# 月光宝盒 3models.Movie.objects.filter(id__gt=2).values('id','name')
# <QuerySet [{'id': 3, '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')
# <QuerySet [(1, '十面埋伏')]>models.Movie.objects.filter(id__gt=1).order_by('-id')
# <QuerySet [<Movie: Movie object (3)>, <Movie: Movie object (2)>]>models.Movie.objects.order_by('-id')
# <QuerySet [<Movie: Movie object (3)>, <Movie: Movie object (2)>, <Movie: Movie object (1)>]>

8.4.2.2、查询谓词

描述查询条件。如下:

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

8.4.2.3、聚合查询

聚合函数包含: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 modelsmodels.Movie.objects.aggregate(avgPrice=Avg('price'))
# {'avgPrice': Decimal('52.000000')}models.Movie.objects.values_list('country').annotate(max_price=Max('price'))
# <QuerySet [('中国', Decimal('70.00')), ('美国', Decimal('45.00'))]>models.Movie.objects.values('country').annotate(max_price=Max('price'))
# <QuerySet [{'country': '中国', 'max_price': Decimal('70.00')}, {'country': '美国', 'max_price': Decimal('45.00')}]>

8.4.3、更新Update

  • 单条更新:通过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字段更新为50models.Movie.objects.update(price=35)       # 将所有记录的price更新为35
    

8.3.5、删除Delete

不论是单条,还是结果集,都用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()                 # 删除全部记录

8.5、F对象和Q对象

8.5.1、F对象

F对象用于不获取字段值的情况下操作字段值,或两个字段间的比较。

用法如下:

F('列名')

如:

from django.db.models import F
from movie import models# 将所有电影价格下降70%
models.Movie.objects.all().update(price=F('price')*0.7)

8.5.2、Q对象

在条件中实现或、与、非操作,语法如下:

Q(条件1)|Q(条件2)        条件1或条件2成立
Q(条件1)&Q(条件2)       条件1和条件2都要成立
~Q(条件1)               条件1不成立

示例如下:

from django.db.models import Qmodels.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不为美国的记录

8.6、原生数据库语句

8.6.1、查询

使用objects的raw()方法,返回RawQuerySet对象。示例如下:

from movie import modelsmvs = models.Movie.objects.raw("select * from movie_movie where country='中国'")
# <RawQuerySet: select * from movie_movie where country='中国'>for mv in mvs:print(mv.name, mv.price)
# 霸王别姬 24.50
# 藏龙卧虎 21.00
# 英雄本色 28.00

8.6.2、增删改

增删改通过游标cursor实现。游标在django.db.connection包中,使用前需先导入,示例如下:

from django.db import connectionconnection.cursor().execute('update movie_movie set price=80 where id=10')
# 更新id=10的记录price为80

为防止出现异常未释放cursor资源,一般用with语句进行操作:

from django.db import connectionwith connection.cursor() as c:c.execute('delete from movie_movie where id=10')# 删除id=10的记录。

8.7、关联关系映射

关联关系映射分为1对1,1对多,多对多。

8.7.1、一对一映射

一对一表示两个表的对象有唯一的对应关系,如一个丈夫对应一个妻子。一对一通过models.OneToOneField()实现,具体语法如下:

class M1(models.Model):xxxclass M2(models.Model):xxxattr = 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'      # 内置类,将表名修改为musicianclass 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 modelsmus1 = 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)
# 陈奕迅

8.7.2、一对多映射

一对多映射表示一个对象关联多个对象,如一个音乐家有多首作品。一对多语法如下:

class M1(models.Model):xxxclass M2(models.Model):xxxattr = 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 modelsm1 = 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()等方法
# <QuerySet [<Music: Music object (1)>, <Music: Music object (2)>, <Music: Music object (3)>]>for mu in mus:print(mu.title)
# K歌之王
# 十面埋伏
# 富士山下

通过多查1:

mu = models.Music.objects.get(id=1)mu.musician.name
# 陈奕迅

8.7.3、多对多映射

一个音乐家可以签约多个平台,一个平台可以有多个音乐家,音乐家和平台之间就是多对多的关系。多对多映射通过中间表实现。

示例如下:

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 modelsm1 = 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()
# <QuerySet [<Platform: Platform object (1)>, <Platform: Platform object (2)>, <Platform: Platform object (4)>]>

通过platform查musician:

p1 = models.Platform.objects.get(id=2)p1.musician.all()
# <QuerySet [<Musician: Musician object (1)>, <Musician: Musician object (2)>]>

【Django】Django配置文件和设计模式详解相关推荐

  1. pythondjango教程_Python 中Django安装和使用教程详解

    一.安装 一般使用cmd 安装就可以 手动安装通过下载方式 二.配置使用 1.通过cmd新建一个项目,我是在桌面新建 上面命令会在桌面新建pythonDjango文件夹,在里面会生成如下图两个文件 m ...

  2. 《设计模式详解》手写简单的 Spring 框架

    自定义 Spring 框架 自定义 Spring 框架 Spring 使用回顾 Spring 核心功能结构 bean 概述 Spring IOC 相关接口 BeanFactory 接口 BeanDef ...

  3. 《设计模式详解》创建型模式 - 工厂模式

    <设计模式详解> 4.2 工厂模式 4.2.1 概述 4.2.2 简单工厂模式 4.2.2.1 结构 4.2.2.2 实现 4.2.2.3 优缺点 4.2.2.4 扩展 - 静态工厂 4. ...

  4. 常见的java设计模式详解

    常见的java设计模式详解 1. 根据目的来分 2 GoF的23种设计模式的功能 3.下面介绍几种常见的模式 单例(Singleton)模式 前言 1)单例(Singleton)模式的定义 2)特点 ...

  5. GitLab CI流水线配置文件.gitlab-ci.yml详解(三)

    GitLab CI流水线配置文件.gitlab-ci.yml详解 - contents:: 目录 本文讲解在 :ref:GitLab的汉化与CI持续集成gitlab-runner的配置 <con ...

  6. Tomcat(二):tomcat配置文件server.xml详解和部署简介

    1. 入门示例:虚拟主机提供web服务 该示例通过设置虚拟主机来提供web服务,因为是入门示例,所以设置极其简单,只需修改$CATALINA_HOME/conf/server.xml文件为如下内容即可 ...

  7. Javascript常用的设计模式详解

    Javascript常用的设计模式详解 阅读目录 一:理解工厂模式 二:理解单体模式 三:理解模块模式 四:理解代理模式 五:理解职责链模式 六:命令模式的理解: 七:模板方法模式 八:理解javas ...

  8. iOS中MVC等设计模式详解

    iOS中MVC等设计模式详解 在iOS编程,利用设计模式可以大大提高你的开发效率,虽然在编写代码之初你需要花费较大时间把各种业务逻辑封装起来.(事实证明这是值得的!) 模型-视图-控制器(MVC)设计 ...

  9. mysql配置文件my.cnf详解

    mysql配置文件my.cnf详解 basedir = path 使用给定目录作为根目录(安装目录). character-sets-dir = path 给出存放着字符集的目录. datadir = ...

最新文章

  1. python周末列表的表示形式合并_Python 列表合并题
  2. 【多线程】0.理解一下5种IO模型、阻塞IO和非阻塞IO、同步IO和异步IO
  3. 20个数据库设计的最佳实践
  4. java京东查询物流轨迹事例_Java爬虫实现京东物流查询
  5. hadoop(3)——yarn查看方式
  6. 「软件项目管理」一文详解软件项目管理概述
  7. 通过引入switch表达式来增强Java switch语句
  8. OneNote使用说明
  9. MATLAB集合运算
  10. 树莓派putty远程登录windows
  11. 蓝桥杯 ADV-237 算法提高 三进制数位和
  12. 基于Multisim的循环彩灯控制器仿真设计
  13. C#窗体程序打开Word或Excel文档代码实现
  14. 马化腾:与CNTV合作是产业的延展
  15. python idle界面_3.7 IDLE 用户界面
  16. 使程序默认以管理员权限运行(包括注册表修改法)
  17. 11月第5周业务风控关注|重磅!瓜子二手车“遥遥领先”被罚天价1250万
  18. Zabbix Agent 主被动模式 坑与技巧
  19. Stroke – 开源鼠标手势软件[Windows]
  20. 严格模式和标准模式的区别(附严格模式实战实例)

热门文章

  1. 堆+贪心——nkoj1587【Usaco Nov07 Gold】分配防晒霜
  2. Set中的HashSet和TreeSet特点及用法
  3. 用OpenSSL做自签名的证书(by quqi99)
  4. 想学神经调控-价格你来定
  5. 使用淘宝IP库获取用户ip地理位置
  6. 儿童保健管理系统技术方案
  7. DELL G3 3590 Ubuntu16.04(14.04) 网卡驱动 RTL8111/8168/8411
  8. 无法删除文件,因为已在Windows资源管理器中打开
  9. 医疗机构如何确保符合HIPAA标准 保障网络安全
  10. Audio的播放流程