Django自学笔记

    一、Windows平台安装Django参考:

    http://www.runoob.com/django/django-install.html

    官网:https://www.djangoproject.com/download/

    二、查看版本操作

      1、查看版本:先导入,然后django.get_version()

    三、创建项目(使用django-admin.py来创建HelloWorld项目)

      1、

django-admin startproject HelloWorld

    2、进入HelloWorld目录启动服务:

python manage.py runserver 127.0.0.1:8000(不写默认8000)

    3、在浏览器输入:127.0.0.1:8000查看

    四、视图和URL配置

      1、配置view.py:

from django.http import HttpResponse 
    def hello(request): 
        return HttpResponse("Hello world ! ")

     2、绑定URL与视图函数,配置urls.py:

from django.urls import path 
from . import view
urlpatterns = [
	# 127.0.0.1:8000
	path(‘’,view.hello),
    # 127.0.0.1:8000/admin/
    path(‘admin/’,view.hello),  	 
]	

    五、Django模板

    在HelloWorld目录下创建templates目录并建立hello.html文件

      1、hello.html添加:<h1>{{hello}}</h1>

      2、修改settings.py:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        # 修改的地方
        'DIRS': [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',
            ],
        },
    },
]

   3、修改view.py,增加一个新的对象,用于向模板提交数据:

# from django.http import HttpResponse
from django.shortcuts import render
import datetime
def hello(request):
    athlete_list = ["第一","第二","第三","第四"]
    context = {}
    context['current_date'] = datetime.datetime.now().strftime('%H:%M:%S %Y/%m/%d')
    context['hellokey'] = 'Hello Word!'
    context['num1'] = 7
    context['num2'] = 6
    context['num3'] = 6
    context['num4'] = 6
    context['athlete_list'] = athlete_list
    return render(request,'hello.html',context)
    # return HttpResponse("Hello World!!!!")

     context 字典中元素的键值 "hello" 对应了模板中的变量 "{{ hello }}"

    六、Django模板标签

      if/else标签,在hello.html中操作:

{% if num1 > num2 %}
		<h2>{{ hellokey|first|lower}}取出第一个单词并小写</h2>
		<h1>{{ hellokey|lower}}所有单词小写,upper大写</h1>
		<h2>{{ hellokey|length}}hellokey的长度</h2>
		<i>显示num1的值,num1= {{num1}}</i>
		<br>
	{% elif num1 == num2 %}
		<h1>num1等于num2,值为:{{num1}}</h1>
	{% else %}
		<b>else语句加粗</b>
	{% endif %}

ifequal/ifnotequal标签(比较两个值是否相等): 

{% ifequal num3 num4 %}
			<h3>num3等于num4,值为:{{num3}}</h3>
		{% endifequal %}

for标签使用:

<ul>
{% for athlete in athlete_list %}
	<li>{{athlete}}</li>
	{# 注释:循环嵌套 #}
	{% for h in hellokey %}
		<li>{{h|truncatewords:”1”}}显示变量的前1个单词,0不显示用…代替</li>
	{% endfor %}
{% endfor %}
</ul>

 include标签:

{% include “base.html”  %}

   not使用:

{% if not num1 == 2 %}
	<b>not使用</b>
{% endif %}

 and使用:

{% if num1 == 7 and num2 == 6 %}
	<b>and使用</b>
{% endif %}

   or使用:

{% if num1 == 2 or num2 == 6 %}
		<b>or使用</b>
{% endif %}

 reversed反向迭代:

<div>
	<!—加上reversed反向迭代-->
	{% for athlete in athlete_list reversed  %}
	    <div>
            <b>{{athlete}}</b>
            </div>
	{% endfor %}
</div>

 注释标签:

{# 这是一个注释,不会显示出来!#}

模板继承操作: 

templates 目录中添加 base.html 文件:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>模板继承</title>
</head>
<body>
    <h1>Hello World!继承操作</h1>
    <p>Django测试继承</p>
    {% block mainbody %}
        <p>original</p>
    {% endblock %}
</body>
</html>

    以上代码中,名为 mainbody 的 block 标签是可以被继承者们替换掉的部分。

    hello.html 中继承 base.html,并替换特定 block,hello.html 修改后的代码如下:

继承中extends必须是第一个标签,否则会报错
{% extends "base.html" %}
{% block mainbody %}
<p>继承了 base.html 文件</p>
<p>It is now {{ current_date }}</p>
===========include=========***************
{% include "base.html" %}
{% endblock %}
=============endblock之后的东西都不会显示======================

 extends代码说明 hello.html 继承了 base.html 文件。可以看到,这里相同名字的 block 标签用以替换 base.html 的相应 block。

    继承中extends必须是第一个标签,否则会报错

    输出结果如下:

  以下是hello.html全部代码: 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Django模板标签</title>
</head>
<body>

继承中extends必须是第一个标签,否则会报错
{% extends "base.html" %}
{% block mainbody %}
<p>继承了 base.html 文件</p>
<p>It is now {{ current_date }}</p>
===========include=========***************
{% include "base.html" %}
{% endblock %}

=============endblock之后的东西都不会显示======================
<h1>{{ hellokey }}</h1>
<h2>{{hellokey}}</h2>
{# if判断取num1值的时候不加大括号#}
{% if num1 > num2 %}
    <h1>============</h1>
    <h2>{{ hellokey|first|lower}}取出第一个单词并小写</h2>
    <h2>{{ hellokey|lower}}所有单词小写</h2>
    <h2>{{ hellokey|length}}长度</h2>
    {# 显示num1的值要加两个大括号 #}
    <i>num1 = {{num1}}</i>
    <br>
    <i>num2 = {{num2}}</i>
    <h1>============</h1>
{% elif num1 == num2 %}
    <h1>num1等于num2,值为:{{num1}}</h1>
{% else %}
    <b>else加粗</b>
{% endif %}

{% ifequal num3 num4 %}
    <h3>num3等于num4,值为:{{num3}};{{ hellokey }}</h3>
{% endifequal %}

{% if num1 == 7 and num2 == 6 %}
    <h2>and使用</h2>
{% endif %}
<!--or使用-->
{% if num1 == 7 or num2 == 8%}
    <i>or使用</i>
{% endif %}
<br>
<!--not使用-->
{% if not num1 == 2 %}
    <b>not使用</b>
{% endif %}
<ul>
    {% for athlete in athlete_list %}
        <li>{{athlete}}</li>
        {% for h in hellokey %}
            <li>{{h|truncatewords:"1"}}显示变量的前1个词,0不显示用...代替</li>
        {% endfor %}
    {% endfor %}
</ul>
<div>
    <!--加上reversed反向迭代-->
    {% for athlete in athlete_list reversed %}
        <div>
            <b>{{athlete}}</b>
        </div>
    {% endfor %}
</div>
</body>
</html>

  七、Django模型-数据库配置

      下载对应操作系统的 whl 文件安装mysqlclient:https://www.lfd.uci.edu/~gohlke/pythonlibs/#mysqlclient

    修改settings.py 文件的 DATABASES 配置项:

DATABASES = {
    'default': {
        # 'ENGINE': 'django.db.backends.sqlite3',
        'ENGINE': 'django.db.backends.mysql',
        # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
        # 数据库名字
        'NAME': 'python3',
        # 用户
        'USER':'root',
        'PASSWORD':'123456',
        'HOST':'localhost',
        'PORT':'3306',
    }
}

   这里添加了中文注释,所以你需要在 HelloWorld/settings.py 文件头部添加 # -*- coding: UTF-8 -*-。上面包含数据库名称和用 户的信息,它们与 MySQL 中对应数据库和用户的设置相同。 

    定义模型-创建APP

django-admin startapp TestModel

       修改 TestModel/models.py 文件,代码如下:

# -*- coding: UTF-8 -*-
from django.db import models

class Test(models.Model):
    # 数据类型由CharField(相当于varchar)、DateField(相当于datetime), max_length 参数限定长度
    name = models.CharField(max_length=20)

     以上的类名代表了数据库表名,且继承了models.Model,类里面的字段代表数据表中的字段(name),数据类型则由    CharField(相当于varchar)、DateField(相当于datetime), max_length 参数限定长度。

        接下来在settings.py中找到INSTALLED_APPS这一项,如下:

INSTALLED_APPS = [
    'django.contrib.admin', # admin管理后台站点
    'django.contrib.auth', # 身份认证系统
    'django.contrib.contenttypes', # 内容类型框架
    'django.contrib.sessions', # 会话框架
    'django.contrib.messages', # 消息框架
    'django.contrib.staticfiles', # 静态文件管理框架
    # 新增此项
    'TestModel',
]

      在命令行中运行:

python manage.py migrate   # 创建表结构

python manage.py makemigrations TestModel  # 让 Django 知道我们在我们的模型有一些变更
python manage.py migrate TestModel   # 创建表结构

数据库操作:

      接下来我们在 HelloWorld 目录中添加 testdb.py 文件(下面介绍),并修改 urls.py

from django.urls import path
from . import view,testdb

urlpatterns = [
    # http://127.0.0.1:8000
    path('',view.hello),
    # http://127.0.0.1:8000/admin/
    path('admin/', view.hello),
    # http://127.0.0.1:8000/testdb/
    path('testdb/', testdb.testdb),
]

     添加数据(添加数据需要先创建对象,然后再执行 save 函数,相当于SQL中的INSERT)testdb.py:

# coding=utf-8

from django.http import HttpResponse
from TestModel.models import Test

# 数据库操作
def testdb(request):
    test1 = Test(name='runoob')
    test1.save()
    return HttpResponse("<p>网页每刷新一次添加一次name的值,数据添加成功!</p>")

获取数据,一定要先添加数据,之后才能获取数据,上面的步骤网页每刷新一次就会添加一次name的值,:

修改 testdb.py:

#!/usr/bin/env python
# coding=utf-8

from django.http import HttpResponse
from TestModel.models import Test

# 数据库操作
def testdb(request):
    # test1 = Test(name='runoob')
    # test1.save()
    # return HttpResponse("<p>网页每刷新一次添加一次name的值,数据添加成功!</p>")
    #初始化
    response = ""
    response1 = ""
    # 通过objects这个模型管理器的all()获得所有数据行,相当于SQl中的SELECT * FROM
    list = Test.objects.all()
    # filter相当于SQL中的WHERE,可设置条件过滤结果
    response2 = Test.objects.filter(id=7)
    # 获取单个对象
    response3 = Test.objects.get(id=7)

    # 更新数据:修改其中一个id=10的name字段,再save,相当于SQL中的UPDATE
    update_test = Test.objects.get(id=10)
    update_test.name = "python"
    update_test.save()
    # 更新数据另一种方法:
    Test.objects.filter(id=8).update(name="java")
    # 更新所有列:
    # Test.objects.all().update(name = "python!")

    # 删除数据,删除后此id则不会存在,再次调取会报错
    # test1 = Test.objects.get(id=2)
    # test1.delete()
    # 删除数据另一种方法
    # Test.objects.filter(id=3).delete()
    # 删除所有
    # Test.objects.all().delete()

    # 限制返回的数据 相当于SQL中的OFFSET 0 LIMIT 2(从索引为0的数据开始取出2条数据)按照id排序
    # response4 = Test.objects.order_by('id').all()[0::2]
    response4 = Test.objects.order_by('id')[0::2]
    # for i in response4:
    #     print(i.name)
    # 数据排序
    # Test.objects.order_by('id')
    # 这个是筛选出name为python的所有数据,并按照id排序
    re = Test.objects.filter(name="python").order_by("id")
    for i in re:
        print(i.id,i.name)
    # 输出response4获取的数据 每个数据前面加上序号
    for i in response4:
        response += str(i.id) + " " + i.name + "<br>"
    return HttpResponse("<p>" + response + "</p>")

    # 输出所有数据
    # for var in list:
    #     response1 += var.name + "<br>"
    # response = response1
    # return HttpResponse("<p>" +response.name +"</p>")

访问 http://127.0.0.1:8000/testdb 就可以看到数据,并且在mysql客户端(如Navicat中的testmodel_test表)可看到所有数据。

八、Django表单: 

  GET方法:在之前的项目中新建search.py

/HelloWorld/HelloWorld/search.py 文件代码:

#!/usr/bin/env python
# coding=utf-8

from django.http import HttpResponse
from django.shortcuts import render_to_response

# 表单操作 GET方法
def search_form(request):
    return render_to_response('search_form.html')
# 接收请求的数据
def search(request):
    request.encoding='utf-8'
    if 'q' in request.GET:
        if len(request.GET['q'])!=0:
            message = "你搜索的内容为:"+ request.GET['q']
        else:
            message = "你提交了空表单"
    else:
        message = "你提交了空表单"
    return HttpResponse(message)

在模板目录 templates 中添加 search_form.html 表单:

/HelloWorld/templates/search_form.html 文件代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>GET表单操作</title>
</head>
<body>
    <form action="/search" method="get">
        <input type="text" name="q">
        <input type="submit" value="搜索">
    </form>
</body>
</html>

urls.py 规则修改为如下形式:

# coding=utf-8
from django.urls import path
from . import view,testdb,search

urlpatterns = [
    # http://127.0.0.1:8000
    path('',view.hello),
    # http://127.0.0.1:8000/admin/
    path('admin/', view.hello),
    # http://127.0.0.1:8000/testdb/
    path('testdb/', testdb.testdb),
    path('search-form/', search.search_form),
    path('search/', search.search),
]

访问地址 http://127.0.0.1:8000/search-form 并搜索,结果如下所示:POS

  POS方法: 用一个URL和处理函数,同时显示视图和处理请求。

在 templates 创建 post.html:

/HelloWorld/templates/post.html 文件代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>POST表单操作</title>
</head>
<body>
    <form action="/search-post/" method="post">
        {#csrf全称Cross Site Request Forgery。这是Django提供的防止伪装提交请求的功能。POST方法提交的表格,必须有此标签。#}
        {% csrf_token %}
        <input type="text" name="q">
        <input type="submit" value="Submit">
    </form>
        <p>{{ rlt}}</p>
</body>
</html>

 rlt 为表格处理结果预留位置。

注意:提交表单报错:RuntimeError: You called this URL via POST,but the URL doesn’t end in a slash and you have APPEND_SLASH set。。。可将form的action地址改为/结尾:action="/search-post/"或者在settings.py中添加:APPEND_SLASH=False,具体参考(http://www.cnblogs.com/zhxhdean/p/3173663.html

在HelloWorld目录下新建 search2.py 文件并使用 search_post 函数来处理 POST 请求:

/HelloWorld/HelloWorld/search2.py 文件代码:

#!/usr/bin/env python
# coding=utf-8
from django.shortcuts import render
from django.views.decorators import csrf
# 接收POST请求数据
def search_post(request):
    ctx={}
    if request.POST:
        result = request.POST['q']
        if len(result)!=0:
            # rlt获取输入的结果
            ctx['rlt'] = '您输入的内容是:'+request.POST['q']
        else:
            ctx['rlt'] = '您未输入任何值!'
    return render(request,"post.html",ctx)

urls.py 规则修改为如下形式:

from django.urls import path
from . import view,testdb,search,search2

urlpatterns = [
    # http://127.0.0.1:8000
    path('',view.hello),
    # http://127.0.0.1:8000/admin/
    path('admin/', view.hello),
    # http://127.0.0.1:8000/testdb/
    path('testdb/', testdb.testdb),
    path('search-form/', search.search_form),
    path('search/', search.search),
    path('search-post/', search2.search_post),
]

访问 http://127.0.0.1:8000/search-post 显示结果如下:

九、Django Admin管理工具:

Django 自动管理工具是 django.contrib 的一部分。你可以在项目的 settings.py 中的 INSTALLED_APPS 看到它:

/HelloWorld/HelloWorld/settings.py 文件代码:
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

激活管理工具:

/HelloWorld/HelloWorld/urls.py 文件代码:

from django.contrib import admin
from django.urls import path

urlpatterns = [
    # admin管理工具http://127.0.0.1:8000/admin/
    path('admin/',admin.site.urls),
]

启动开发服务器,然后在浏览器中访问 http://127.0.0.1:8000/admin/,得到如下界面:

这里是英文界面,修改为中文的方法:

/HelloWorld/HelloWorld/settings.py 文件代码:

# 修改admin后台管理为中文
LANGUAGE_CODE = 'zh-Hans'
# LANGUAGE_CODE = 'en-us'

# UTC协调世界时,又称世界统一时间、世界标准时间、国际协调时间。
# TIME_ZONE = 'UTC'
#修改时区为东八区
TIME_ZONE = 'Asia/Shanghai'
# 改为False
USE_TZ = False

通过命令 python manage.py createsuperuser 来创建超级用户,如下所示:

执行命令 python manage.py createsuperuser
Username (leave blank to use 'root'): admin
Email address: admin@163.com
Password:
Password (again):
Superuser created successfully.

之后输入用户名密码登录,界面如下:

为了让 admin 界面管理某个数据模型,我们需要先注册该数据模型到 admin。比如,我们之前在 TestModel 中已经创建了模型 Test 。修改 TestModel/admin.py: 

HelloWorld/TestModel/admin.py: 文件代码:

from django.contrib import admin
from TestModel.models import Test

# Register your models here.
admin.site.register(Test)

刷新后即可看到 Testmodel 数据表:

复杂模型处理:

在 TestModel/models.py 中增加一个更复杂的数据模型(这里有两个表,Tag 以 Contact 为外部键。一个 Contact 可以对应多个 Tag。):

HelloWorld/TestModel/models.py: 文件代码:

# -*- coding: UTF-8 -*-
from django.db import models

class Test(models.Model):
    # 数据类型由CharField(相当于varchar)、DateField(相当于datetime), max_length 参数限定长度
    name = models.CharField(max_length=20)
class Contact(models.Model):
    name = models.CharField(max_length=200)
    age = models.IntegerField(default=0) #  IntegerField 用于存储整数默认0
    email = models.EmailField()
    # def __unicode__(self):
    # django admin下拉列表不显示值,显示为object的处理,python3用下面的方法
    def __str__(self):
        return self.name
class Tag(models.Model):
    # 使用ForeignKey定义了一个外键关系,每一个Tag关联到一个对应的Contact,注意要将外键写在‘多’的一方
    contact = models.ForeignKey('Contact',on_delete=models.CASCADE,)
    name = models.CharField(max_length=50)
    # def __unicode__(self):
    # django admin下拉列表不显示值,显示为object的处理,python3用下面的方法
    def __str__(self):
        return self.name

在 TestModel/admin.py 注册多个模型并显示:

HelloWorld/TestModel/admin.py: 文件代码:

from django.contrib import admin
from TestModel.models import Test,Contact,Tag
# Register your models here.
admin.site.register([Test,Contact,Tag])

 如果之前还未创建表结构,可使用以下命令创建:

python manage.py makemigrations TestModel  # 让 Django 知道我们在我们的模型有一些变更
python manage.py migrate TestModel   # 创建表结构

 自定义表单:

我们可以自定义管理页面,来取代默认的页面。比如上面的 "add" 页面。我们想只显示 name 和 email 部分。修改 TestModel/admin.py:

from django.contrib import admin
from TestModel.models import Test,Contact,Tag
# Register your models here.

# 自定义管理页面admin,来取代默认的页面
class ContactAdmin(admin.ModelAdmin):
    fields = ('name','email')
admin.site.register(Contact,ContactAdmin)
# 增加模型
admin.site.register([Test,Tag])

# 如果报错:django.contrib.admin.sites.NotRegistered: The model Contact is not registered
# 确认代码无误,再重新启动服务即可

以上代码定义了一个 ContactAdmin 类,用以说明管理页面的显示格式。 里面的 fields 属性定义了要显示的字段。 由于该类对应的是 Contact 数据模型,我们在注册的时候,需要将它们一起注册。显示效果如下:

 还可以将输入栏分块,每个栏也可以定义自己的格式。修改 TestModel/admin.py为:

from django.contrib import admin
from TestModel.models import Test,Contact,Tag
# Register your models here.

# 自定义管理页面admin,来取代默认的页面
class ContactAdmin(admin.ModelAdmin):
    # 将输入栏分块
    fieldsets = (
        ['Main必填项',{
            'fields':('name','email'),
        }],
        # collapse折叠插件CSS样式里
        ['Advance可选项',{
            'classes':('collapse',),
            'fields':('age',),
        }]
    )

admin.site.register(Contact,ContactAdmin)
# 增加模型
admin.site.register([Test,Tag])

# 如果报错:django.contrib.admin.sites.NotRegistered: The model Contact is not registered
# 确认代码无误,再重新启动服务即可

内联(Inline)显示

上面的 Contact 是 Tag 的外部键,所以有外部参考的关系。

而在默认的页面显示中,将两者分离开来,无法体现出两者的从属关系。我们可以使用内联显示,让 Tag 附加在 Contact 的编辑页面上显示。

修改TestModel/admin.py:

from django.contrib import admin
from TestModel.models import Test,Contact,Tag
# Register your models here.

# 内联显示 TabularInline表格形式嵌入;StackedInline默认嵌入
class TagInline(admin.TabularInline):
    model = Tag
    # 内联显示多少个
    extra = 3
# 自定义管理页面admin,来取代默认的页面
class ContactAdmin(admin.ModelAdmin):   
    # 内联显示
    inlines = [TagInline]
    # 将输入栏分块
    fieldsets = (
        ['Main必填项',{
            'fields':('name','email'),
        }],
        # collapse折叠插件CSS样式里
        ['Advance可选项',{
            'classes':('collapse',),
            'fields':('age',),
        }]
    )
admin.site.register(Contact,ContactAdmin)
# 增加模型
admin.site.register([Test,Tag])

# 如果报错:django.contrib.admin.sites.NotRegistered: The model Contact is not registered
# 确认代码无误,再重新启动服务即可

 

列表页的显示(输入多条数据后):

 

可以自定义该页面的显示,比如在列表中显示更多的栏目,只需要在 ContactAdmin 中增加 list_display 属性:

HelloWorld/TestModel/admin.py: 文件代码:

from django.contrib import admin
from TestModel.models import Test,Contact,Tag
# Register your models here.

# 内联显示
class TagInline(admin.TabularInline):
    model = Tag
# 自定义管理页面admin,来取代默认的页面
class ContactAdmin(admin.ModelAdmin):
    # 增加列表页显示更多栏目
    list_display = ('name','age','email')
    # 内联显示
    inlines = [TagInline]
    # 将输入栏分块
    fieldsets = (
        ['Main必填项',{
            'fields':('name','email'),
        }],
        # collapse折叠插件CSS样式里
        ['Advance可选项',{
            'classes':('collapse',),
            'fields':('age',),
        }]
    )
# admin.site.unregister(Contact)
admin.site.register(Contact,ContactAdmin)
# 增加模型
admin.site.register([Test,Tag])

# 如果报错:django.contrib.admin.sites.NotRegistered: The model Contact is not registered
# 确认代码无误,再重新启动服务即可

 

还可以在 ContactAdmin 中增加 list_filter 属性 ,增加过滤器:

# 过滤器
list_filter =  ['name']

 

 还可以在 ContactAdmin 中增加 list_per_page 属性 ,增加分页:

搜索功能在管理大量记录时非常有,我们可以使用 search_fields 为该列表页增加搜索栏:

HelloWorld/TestModel/admin.py: 文件代码:

from django.contrib import admin
from TestModel.models import Test,Contact,Tag
# Register your models here.

# 内联显示
class TagInline(admin.TabularInline):
    model = Tag
# 自定义管理页面admin,来取代默认的页面
class ContactAdmin(admin.ModelAdmin):
    # 增加列表页显示更多栏目
    list_display = ('name','age','email')
    # 增加搜索功能,是一个列表或者元组,按name搜索,也可以增加多个
    search_fields = ('name',)
    # 内联显示
    inlines = [TagInline]
    # 将输入栏分块
    fieldsets = (
        ['Main必填项',{
            'fields':('name','email'),
        }],
        # collapse折叠插件CSS样式里
        ['Advance可选项',{
            'classes':('collapse',),
            'fields':('age',),
        }]
    )
# admin.site.unregister(Contact)
admin.site.register(Contact,ContactAdmin)
# 增加模型
admin.site.register([Test,Tag])

# 如果报错:django.contrib.admin.sites.NotRegistered: The model Contact is not registered
# 确认代码无误,再重新启动服务即可

如果models.py里有布尔值,会显示不友好(不是一个直观的结果):

from django.db import models

# 图书表结构设计
class BookInfo(models.Model):
    # 图书名称
    btitle = models.CharField('图书名称',max_length=20)
    # 图书发布时间
    bpub_date =models.DateTimeField('图书发布时间')
    def __str__(self):
        return self.btitle

# 英雄表结构设计
class HeroInfo(models.Model):
    # 英雄姓名
    hname = models.CharField('英雄姓名',max_length=10)
    # 英雄性别
    hgender = models.BooleanField(default='男')
    # 英雄简介
    hcontent = models.CharField('英雄简介',max_length=1000)
    # 所属图书,外键,注意要将外键写在‘多’的一方
    hbook = models.ForeignKey('BookInfo',on_delete=models.CASCADE)
    def __str__(self):
        return self.hname

admin.py:

from django.contrib import admin
from .models import *

# 向admin注册booktest的模型

# 增加内联 TabularInline
class HeroInline(admin.StackedInline):
    model = HeroInfo
    # 内联显示多少个
    extra = 2

# 管理类修改
class BookInfoAdmin(admin.ModelAdmin):

    list_display = ['id','btitle','bpub_date']
    # 过滤器
    list_filter =  ['btitle']
    # 搜索
    search_fields = ['btitle']
    # 分页
    list_per_page = 1
    # 分组
    fieldsets = [
        ('基本字段',{'fields':['btitle']}),
        # 'classes':['collapse']折叠高级字段
        ('高级字段',
            {
            'fields':['bpub_date'],
             'classes':['collapse']
             }
         )
    ]
    # 内联显示
    inlines = [HeroInline]

class HeroInfoAdmin(admin.ModelAdmin):
    list_display = ['id','hname','hgender','hcontent']

admin.site.register(HeroInfo,HeroInfoAdmin)
admin.site.register(BookInfo,BookInfoAdmin)

models.py修改为(增加gender类):

from django.db import models

# 图书表结构设计
class BookInfo(models.Model):
    # 图书名称
    btitle = models.CharField('图书名称',max_length=20)
    # 图书发布时间
    bpub_date =models.DateTimeField('图书发布时间')
    def __str__(self):
        return self.btitle

# 英雄表结构设计
class HeroInfo(models.Model):
    # 英雄姓名
    hname = models.CharField('英雄姓名',max_length=10)
    # 英雄性别
    hgender = models.BooleanField(default='男')
    # 英雄简介
    hcontent = models.CharField('英雄简介',max_length=1000)
    # 所属图书,外键,注意要将外键写在‘多’的一方
    hbook = models.ForeignKey('BookInfo',on_delete=models.CASCADE)
    def __str__(self):
        return self.hname

    def gender(self):
        if self.hgender:
            return '男'
        else:
            return '女'
    gender.short_description = '性别'

 admin.py修改为(在admin注册中使用gender代替hgender):

from django.contrib import admin
from .models import *

# 向admin注册booktest的模型

# 增加内联 TabularInline
class HeroInline(admin.StackedInline):
    model = HeroInfo
    # 内联显示多少个
    extra = 2

# 管理类修改
class BookInfoAdmin(admin.ModelAdmin):

    list_display = ['id','btitle','bpub_date']
    # 过滤器
    list_filter =  ['btitle']
    # 搜索
    search_fields = ['btitle']
    # 分页
    list_per_page = 1
    # 分组
    fieldsets = [
        ('基本字段',{'fields':['btitle']}),
        # 'classes':['collapse']折叠高级字段
        ('高级字段',
            {
            'fields':['bpub_date'],
             'classes':['collapse']
             }
         )
    ]
    # 内联显示
    inlines = [HeroInline]

class HeroInfoAdmin(admin.ModelAdmin):
    list_display = ['id','hname','gender','hcontent']

admin.site.register(HeroInfo,HeroInfoAdmin)
admin.site.register(BookInfo,BookInfoAdmin)

设置哪些字段可以进入编辑界面以及排序,admin.py中: 

from django.contrib import admin
from .models import *

class HeroInline(admin.TabularInline):
    model = HeroInfo
# 装饰器注册
@admin.register(BookInfo)
class BookInfoAdmin(admin.ModelAdmin):
    list_display = ['id','btitle','bpub_date']
    # 设置列表页哪些字段可以点击进入编辑界面
    list_display_links = ['btitle','bpub_date']
    # 排序,注意是元组或者list,'-'倒序排序
    ordering = ('-bpub_date','btitle')
    # “操作选项”的位置,底部
    # actions_on_bottom = True
    fieldsets = [
        ('基本',{'fields':['btitle']}),
        ('高级',
         {
             'fields':['bpub_date'],
             'classes':['collapse']
         }
         )
    ]
    inlines = [
        HeroInline,
               ]

class HeroInfoAdmin(admin.ModelAdmin):
    list_display = ['id','hname']
    list_filter = ['hname']
    search_fields = ['hname']
    # 显示字段的顺序,如果使用元组表示显示到一行上,新增的时候这两个字段会在一行
    fields = [('hname', 'hcontent')]

# 不用装饰器注册情况
# admin.site.register(BookInfo,BookInfoAdmin)
admin.site.register(HeroInfo,HeroInfoAdmin)

 

十、自定义管理器对象:

自定义管理器类主要用于两种情况:

  • 情况一:向管理器类中添加额外的方法,BookInfoManager中的create()方法
  • 情况二:修改管理器返回的原始查询集:重写get_queryset()方法,BookInfoManager中的get_queryset()方法

     models.py中操作:

from django.db import models

# 自定义管理器对象
class BookInfoManager(models.Manager):
    def get_queryset(self):
        # 自定义管理器类主要用于两种情况:①更改默认查询集的结果,这个例子按照isDelete=False查询
        # 执行python manager.py shell 导入BookInfo(from booktest.models import BookInfo),
        # BookInfo.books2.all() 这样结果会把isDelete=False的结果筛选出来
        return super(BookInfoManager,self).get_queryset().filter(isDelete=False)

    # 自定义管理器类主要用于两种情况:②向管理器类中添加额外的方法
    # 定义一个模型类的方法,推荐此方法
    # 执行python manager.py shell 导入BookInfo(from booktest.models import BookInfo),
    # 使用:BookInfo.books2.create('某某书名','2019-1-1').save()添加数据
    def create(self,btitle,bpub_date):
        # b = BookInfo()和下面这个等同
        b = self.model()
        # 打印self为:booktest.BookInfo.books2
        # print(self)
        b.btitle = btitle
        b.bpub_date = bpub_date
        b.bread = 0
        b.bcommet = 0
        b.isDelete = False
        return b


class BookInfo(models.Model):
    # 默认管理器,使用方法:BookInfo.books1.all(),全部筛选出来,不能在使用:BookInfo.objects.all()
    books1 = models.Manager()
    # 自定义的管理器,使用方法:BookInfo.books2.all() 管理器是模型类的属性,用于将对象与数据表映射
    books2 = BookInfoManager()
    btitle = models.CharField('书名',max_length=20)
    # db_column显示在数据库中的字段名字为:pub_date
    bpub_date = models.DateTimeField(db_column='pub_date')
    # 阅读量
    bread = models.IntegerField(default=0)
    # 评论数
    bcommet = models.IntegerField(null=False)
    isDelete = models.BooleanField(default=False)
    # 元选项
    class Meta:
        # 表名称
        db_table = 'bookinfo'
    def __str__(self):
        return self.btitle

    # 自定义创建模型类对象方法,不推荐此方法
    # 执行python manager.py shell 导入BookInfo(from booktest.models import BookInfo),
    # 使用:BookInfo.create('abc','1990-1-1').save()
    @classmethod # 类方法
    def create(cls,btitle,bpub_date):
        b = BookInfo()
        b.btitle = btitle
        b.bpub_date = bpub_date
        b.bread = 0
        b.bcommet = 0
        b.isDelete = False
        return b


class HeroInfo(models.Model):
    hname = models.CharField(max_length=20)
    hgender = models.BooleanField(default=True)
    isDelete = models.BooleanField(default=False)
    hcontent = models.CharField(max_length=1000)
    hbook = models.ForeignKey('BookInfo',on_delete=models.CASCADE)

    def __str__(self):
        return self.hname

 十一、查询集:

# values一个对象构成一个字典,然后构成一个列表返回
BookInfo.books2.values().order_by('-id') # 按照id倒序
# 筛选出bcommet评论数为0的个数
BookInfo.books2.all().filter(bcommet=0).count()
# first():返回评论数为0的第一个对象
BookInfo.books2.all().filter(bcommet=0).first()
# exists():判断查询集中是否有数据,如果有则返回True
BookInfo.books2.all().filter(bcommet=0).exists()
# 返回评论数为0的前三个对象,因为是列表所以可以索引(只能为正数)
# 如果没有数据,[0]引发IndexError异常,[0:1].get()引发DoesNotExist异常,shell执行的时候返回空
BookInfo.books2.all().filter(bcommet=0)[0:3]
# 查询集的缓存
# 情况一:这构成了两个查询集,无法重用缓存,每次查询都会与数据库进行一次交互,增加了数据库的负载
print([e.title for e in BookInfo.books1.all()])
print([e.title for e in BookInfo.books1.all()])
# 情况二:两次循环使用同一个查询集,第二次使用缓存中的数据
querylist=BookInfo.books1.all()
print([e.title for e in querylist])
print([e.title for e in querylist])
# 比较运算符
# exact:表示判等,大小写敏感;如果没有写“ 比较运算符”,表示判等
# contains:是否包含,大小写敏感
BookInfo.books1.filter(btitle__contains='天') # 标题包含天的书名
# startswith、endswith:以value开头或结尾,大小写敏感
BookInfo.books1.filter(btitle__startswith='天')
# isnull、isnotnull:是否为null
BookInfo.books1.filter(btitle__isnull=False)
# 在前面加个i表示不区分大小写,如iexact、icontains、istarswith、iendswith
# in:是否包含在范围内
BookInfo.books1.filter(id__in=[1,2,3])
# gt、gte、lt、lte:大于、大于等于、小于、小于等于
BookInfo.books1.filter(bpub_date__gt=('2019-1-1')) # 图书发布时间大于2019-1-1的书籍
# year、month、day、week_day、hour、minute、second:对日期间类型的属性进行运算
BookInfo.books1.filter(bpub_date__year=1990) # 发布时间为1990年的书籍
BookInfo.books1.filter(bpub_date__gt=(datetime(1985,1,1))) # 发布时间大于1985-1-1的书籍
# 跨关联关系的查询(书籍和英雄已通过hbook_id外键关联)
BookInfo.books1.filter(heroinfo__hcontent__contains='八')# 查询英雄表中hcontent包含八的书籍

# 聚合:使用aggregate()函数返回聚合函数的值
# 函数:Avg,Count,Max,Min,Sum
list= BookInfo.books1.filter(bpub_date__gt='1980-1-1')
# 筛选出list中最大的日期
from django.db.models import Max
maxDate = list.aggregate(Max('bpub_date'))

# F对象使用:
#  筛选出阅读量大于评论数的数据
from django.db.models import F
BookInfo.books1.filter(bread__gt=F('bcommet'))
# django支持对F()对象使用算数运算
BookInfo.books1.filter(bread__gte=F('bcommet') * 2)
# F()对象中还可以写作“模型类__列名”进行关联查询
# 筛选英雄中isDelete的值与其所属的书籍中的isDelete相等的书籍
BookInfo.books1.filter(isDelete=F('heroinfo__isDelete'))
# 对于date/time字段,可与timedelta()进行运算
from datetime import timedelta
# 筛选出发布日期为小于发布日期第二天的书籍
BookInfo.books1.filter(bpub_date__lt=F('bpub_date') + timedelta(days=1))

# Q对象使用:
from django.db.models import Q
# Q对象可以使用&(and)、|(or)操作符组合起来,当操作符应用在两个Q对象时,会产生一个新的Q对象
# 筛选出id小于4或标题包含天的书籍
BookInfo.books1.filter(Q(pk__lt=4)|Q(btitle__contains='天'))
# 筛选出id小于4并且书标题包含天的书籍
BookInfo.books1.filter(pk__lt=4,btitle__contains='天')
BookInfo.books1.filter(pk__lt=4).filter(btitle__contains='天')
# 使用~(not)操作符在Q对象前表示取反
# 查询id大于等于6的书籍
BookInfo.books1.filter(~Q(pk__lt=6))

十二:HttpResponse对象

属性:

  • content:表示返回的内容,字符串类型
  • charset:表示response采用的编码字符集,字符串类型
  • status_code:响应的HTTP响应状态码
  • content-type:指定输出的MIME类型

方法:

  • init :使用页内容实例化HttpResponse对象
  • write(content):以文件的方式写
  • flush():以文件的方式输出缓存区
  • set_cookie(key, value='', max_age=None, expires=None):设置Cookie
    • key、value都是字符串类型
    • max_age是一个整数,表示在指定秒数后过期
    • expires是一个datetime或timedelta对象,会话将在这个指定的日期/时间过期,注意datetime和timedelta值只有在使用PickleSerializer时才可序列化
    • max_age与expires二选一
    • 如果不指定过期时间,则两个星期后过期
  • delete_cookie(key):删除指定的key的Cookie,如果key不存在则什么也不发生

在views.py中:

from django.shortcuts import HttpResponse

# cookie练习
def cookieTest(request):
    response = HttpResponse()
    cookie = request.COOKIES
    # 先设置cookie,cookie显示为:t1=abc
    response.set_cookie('t2','vbbbb')
    # 然后判断是否存在,如果存在则显示在页面中
    if 't1' in cookie:
        response.write(cookie['t1']+'\n')
    if 't2' in cookie:
        response.write(cookie['t2'])
    return response

 在urls.py中:

from django.urls import re_path


urlpatterns = [ 
    re_path(r'^cookieTest/$',views.cookieTest),
]

输入:http://127.0.0.1:8000/cookieTest/执行:

谷歌浏览器重F12查看:

重定向:

 在views.py中:

# from django.shortcuts import HttpResponseRedirect
from django.shortcuts import redirect
# 重定向
def redTest1(request):
    # 两个方法都可以
    # return HttpResponseRedirect('/redTest2/')
    return redirect('/redTest2/')

def redTest2(request):
    return HttpResponse('转向来的页面!')

在urls.py中:

from django.urls import re_path
from booktest import views

urlpatterns = [
    re_path(r'^redTest1/$',views.redTest1),
    re_path(r'^redTest2/$',views.redTest2),
]

在浏览器输入:http://127.0.0.1:8000/redTest1/,自动跳转到redTest2页面,显示“转向来的页面!”这句话,同时url地址变为

http://127.0.0.1:8000/redTest2/

十三、session练习

使用session

 

会话过期时间 :  

  • 启用会话后,每个HttpRequest对象将具有一个session属性,它是一个类字典对象
  • get(key, default=None):根据键获取会话的值
  • clear():清除所有会话
  • flush():删除当前的会话数据并删除会话的Cookie
  • del request.session['member_id']:删除会话
  • set_expiry(value):设置会话的超时时间
  • 如果没有指定,则两个星期后过期
  • 如果value是一个整数,会话将在values秒没有活动后过期
  • 若果value是一个imedelta对象,会话将在当前时间加上这个指定的日期/时间过期
  • 如果value为0,那么用户会话的Cookie将在用户的浏览器关闭时过期
  • 如果value为None,那么会话永不过期

 在views.py中:

from django.shortcuts import render,redirect
# session练习
def index(request):
    uname = request.session.get('myname','未登录')
    # 判断登录状态,默认未登录
    state = False
    # 有session情况,登录状态改为True
    if 'myname' in request.session:
        # session值为空的情况,删掉
        if request.session['myname'] == '':
            del request.session['myname']
        state = True

    context = {
        'uname':uname,
        'state':state,
    }
    return render(request,'index.html',context)
# 登录界面
def login(request):
    return render(request,'login.html')
# 存储session
def login_handle(request):
    # session是一个类字典对象,key值这里取名为'myname',value值为POST方式提交的值
    request.session['myname'] = request.POST['uname']
    # request.session.set_expiry(10)
    # request.session.set_expiry(timedelta(days=5))
    # 浏览器关闭时过期
    request.session.set_expiry(0)
    # request.session.set_expiry(None)
    return redirect('/index/')

def login_out(request):
    if 'myname' in request.session:
        del request.session['myname']
    return redirect('/index/')

在urls.py中:

from django.urls import path,re_path
from booktest import views

urlpatterns = [
    re_path(r'^index/$',views.index),
    re_path(r'^login/$',views.login),
    re_path(r'^login_out/$',views.login_out),
    re_path(r'^login_handle/$',views.login_handle),

]

templates文件夹中:

index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index主页</title>
</head>
<body>
<h2>index主页</h2>

{% if uname == '' %}
    登录名不能为空,请重新登录!
{% else %}
    {% if state == True %}
        已成功登录。
    {% else %}
        未登录,请您登录!
    {% endif %}
{% endif %}
<hr >
{% if uname == '' %}
    <a href="/login">点我登录</a><br >
{% else %}
    {% if state == True %}
        欢迎您:{{uname}}<br ><br >
        <a href="/login_out">退出</a>
    {% else %}
        <a href="/login">点我登录</a><br >
    {% endif %}
{% endif %}
</body>
</html>

login.html中:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>login页面</title>
</head>
<body>
<h2>login页面</h2>
<br >
<form method="post" action="/login_handle/">
<input type="text" name="uname">
<input type="submit" value="登录">
    {% csrf_token %}
</form>
</body>
</html>

效果如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值