Django请求周期

url ->  路由系统  ->函数或者类 -> 返回字符串 或者 模板语言

Form表单提交:

  点击提交 -> 进入url系统  ->  执行函数或者类的方法 - > 返回字符串

ajax提交:

  

路由url

 1.path('index/', views.index),一个url对应一个函数

2.path('home/', views.Home.as_view()),一个url对应一个类

3.url(r'^detail-(\d+).html',views.detail),一类url对应一个函数或者一个类,在view中那个detail要传入匹配到的值,严格按照形式参数的顺序获取

4.url(r'detail-(?P<nid>\d+)-(?P<uid>\d+).html',view.detail),用这样的方式进行定义url就 会让view中的函数的形参能够对应起来。

实战

a.
    url(r'^detail-(\d+)-(\d+).html',views.detail),

    def func(request,nid,uid):
        pass
    def func(request,*args):
        args=(传入的第一个数,传入的第二个数)
    def func(request,*args,**kwargs):
        args=(传入的第一个数,传入的第二个数)
        kwargs={}
b.
    url(r'^detail-(?P<nid>\d+)-(?P<uid>\d+).html',views.detail)

    def func(request,nid,uid):#nid和uid位置互换不影响传值
        pass
    def func(request,**kwargs):
        kwargs={'nid':1,'uid':3}
    def func(request,*args,**kwargs):
        args=[]
        kwargs={'nid':1,'uid':3}

 

5.name:对url路由的关系进行命名,以后可以根据此名称生成自己想要的url

path('indexasdfad/', views.index,name="i1"),

模板语言:
<form action="{% url 'i1' %}" method="post">

后面有参数:
    url(r'^indexasdfad/(\d+)', views.index,name="i2"),
    模板语言:
    <form action="{% url 'i2' 3 %}" method="post">
当前url:
  request.path_info

url(r'^indexadff/(?P<nid>\d+)/(?P<uid>\d+)/',views.index,name="i3")
如果想要根据name生成url:
from django.urls import reverse
def func(requset,*args,**kwargs):
  url1=reverse('i1')                #
indexasdfad
  url2=reverse('i2',args=(1,2))         #indexasdfad/1/2
  url3=reverse('i3',kwargs={'nid':1,'uid':3}) #indexadff/1/9
xxx.html
{%url "i1" %}#indexasdfad
{%url "i1" 1 2 %}#indexasdfad/1/2
{%url "i1" nid=1 uid=3 %}#indexasdfad/1/2

 6.路由分发

首先是主程序中的url设置,用include来包含两个app的路由路径,大的分类

 

app01的路由设置:

app02的路由设置:

效果:

7.默认值

在创建url的时候设置一个默认值,然后views里面的方法就要有一个参数接受,参数的名称就是这个字典中的key

8.命令空间

多个 url对应一个app函数:

主project里的urls.py:通过include函数在里面设置namespace设置空间名

from django.contrib import admin
from django.urls import path
from django.conf.urls import url,include
from app01 import views
urlpatterns = [
    url(r'a/',include('app01.urls',namespace='author')),
]

 

 app01里面的urls.py:在里面写上app的名称,并且在url中设置name

from django.conf.urls import url,include
from app01 import views
app_name = 'app01'
urlpatterns = [

    url(r'^index/', views.index,name='index'),

]

 

app01中views.py:翻转的时候要用命名空间:name

from django.shortcuts import render,HttpResponse
from django.urls import reverse
# Create your views here.
def index(request):
    v = reverse('author:index')
    print(v)
    return HttpResponse("index")

 

通过reverse函数翻转出来的url:/a/index/ 

 

视图

1.form表单提交数据的种类

  request.body:所有数据内容的原生值,POST,GET都是由这个转换过来的

    request.POST

    request.GET  

    request.FILES:只取上传的文件

    request.POST.getlist():获取checkbox,select等多选的内容

  request.environ:这里面包含了所有请求需要的参数信息,以字典的形式存储,

  request.Meta(...)

    request.method(POST,GET,PUT)

    request.path_info

    request.COOKIES

2.上传文件,form标签中一定要加enctype="multipart/form-data"

  obj=request.FILES.get('name值')

  obj.name文件名

  f=open(obj.name,mode="wb")

  for item in obj.chunks():

    f.write(item)

  f.close()这样就实现了文件的上传功能

3.FBV      &       CBV

function base view       

  url.py

    index->函数名

  view.py

    def 函数(request):......

当然我们还有一种写法就是:

class base view

  url.py

    home->类名.as_view(),即path('home/',views.Home.as_view())

  view.py

    from django.views import View

    class 类名(View):

      def get(self,request):pass

      def post(self,request):pass

4.装饰器:

比如我们有个网站有很多的页面,我们只有登录了之后才能够查看内容,这个时候我们不能够一个函数一个函数的去加login的代码,那我们就可以用装饰器进行验证

FBV的装饰器:

 1 def auth(func):
 2     def inner(request,*args,**kwargs):
 3         v = request.COOKIES.get('username')
 4         if not v:
 5             return redirect('/login/')
 6         return func(request,*args,**kwargs)
 7     return inner
 8 @auth
 9 def index(request):
10     #获取当前已经登录的用户
11     v = request.COOKIES.get('username')
12     return render(request,'index.html',{'current_user':v})

 

CBV的装饰器:

urls.py:

url(r'^order/',views.Order.as_view()),

 

views.py:

1 class Order(views.View):
2     def get(self,request):
3         v = request.COOKIES.get('username')
4         return render(request, 'index.html', {'current_user': v})
5 
6     def post(self,request):
7         v = request.COOKIES.get('username')
8         return render(request, 'index.html', {'current_user': v})

 

这里面有两个方法,如果我们只想要给其中的get函数加上装饰器,那么我们直接加上就可以了:

1  @method_decorator(auth)
2     def get(self,request):
3         v = request.COOKIES.get('username')
4         return render(request, 'index.html', {'current_user': v})

 

但是如果我们想要给这个类里的所有方法都加上装饰器的话

1.类中有一个方法叫做dispatch,是在所有方法执行之前执行的,可以在那个函数上加

 1 class Order(views.View):
 2     @method_decorator(auth)
 3     def dispatch(self, request, *args, **kwargs):
 4         return super(Order,self).dispatch(request, *args, **kwargs)
 5   
 6     def get(self,request):
 7         v = request.COOKIES.get('username')
 8         return render(request, 'index.html', {'current_user': v})
 9 
10     def post(self,request):
11         v = request.COOKIES.get('username')
12         return render(request, 'index.html', {'current_user': v})

 

2.直接在类名上面加装饰器:注意里面有一个name属性,值要为dispatch

 1 @method_decorator(auth,name='dispatch')
 2 class Order(views.View):
 3    
 4     def get(self,request):
 5         v = request.COOKIES.get('username')
 6         return render(request, 'index.html', {'current_user': v})
 7 
 8     def post(self,request):
 9         v = request.COOKIES.get('username')
10         return render(request, 'index.html', {'current_user': v})

 

通过上面两个方法都可以把类中所有的方法加上装饰器  

模板

模板的继承: 

一个html只能继承一个模板:

模板文件master.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %}{% endblock %}</title>
    <link rel="stylesheet" href="/static/commons.css" >
    <style>
        .pg-header{
            height:48px;
            background-color: seashell;
            color:green;
        }
    </style>
    {% block css %}{% endblock %}
</head>
<body>
    <div class="pg-header">后台管理</div>
    {% block content %}{% endblock %}
    <script src="/static/jquery-1.12.4.js"></script>
    {% block js %}{% endblock %}
</body>
</html>

 

继承模板的html文件:

{% extends 'master.html' %}
{% block title %}用户管理{% endblock %}
{% block content %}
    <h1>用户管理</h1>
    <ul>
        {% for i in u %}
            <li>
                {{ i }}
            </li>
        {% endfor %}
    </ul>
    <script src="/static/jquery-1.12.4.js"></script>
    <script>

    </script>
{% endblock %}
{% block css %}
    <style>
        body{
            background-color: red;
        }
    </style>
{% endblock %}
{% block js %}
    <script></script>
{% endblock %}

 

模板的导入:

相同的html标签模块可以写在单独的文件中,然后进行模板导入

重复的html:tag.html

<form>
    <input type="text" />
    <input type="submit" value="提交" />
</form>

 

模板的导入:

 {% include "tag.html" %}

 自定义single tag:

django中有许多的模板参数,但是如果无法满足我们的需求,那怎么办呢?这个时候我们可以自定义模板参数:

首先我们在app01中写一个模板函数:文件夹必须要用templatetags,其他的文件名都不可以

from django import template
from django.utils.safestring import mark_safe

register = template.Library()
@register.simple_tag
def xiaohong():
    return 123

 register的名字也不能够改

下面我们需要在settings中注册app

然后我们在html中使用看看:顶部要有load

{% load xxoo %}
。。。。。。
{% xiaohong %}

 显示出了上面函数返回的值

那我们把上面自定义的函数改一下:

from django import template
from django.utils.safestring import mark_safe

register = template.Library()

@register.simple_tag
def xiaohong(a1,a2):
    return a1+a2

 

然后我们在模板html文件中使用:{%函数名 arg1 arg2.....%}

{% load xxoo %}
。。。。。。。。。。
{% xiaohong 5 2 %}

这样我们以后想要在页面上想要做一些操作,只要通过一个自定义函数就可以了,这个函数中的参数任意个数,但是不能放在if后面做判断

 自定义filter:

自定义的模板文件中:

from django import template
from django.utils.safestring import mark_safe

register = template.Library()

@register.filter
def liangliang(a1,a2):
    return a1+a2

 html文件中使用:{{'参数一'|函数名:'参数二'}}

{% load xxoo %}
。。。。
{{ 'maliya'|liangliang:'LS' }}

上面的自定义filter中参数只能是两个,如果多了就报错,而且也不能加空格

 应用场景:if else判断中

{% if 'maliya'|liangliang:'LS' %}
        
{% endif %}

 

ORM操作

创建类

1.根据类自动创建数据表

  app下的models.py

a.先写类

#表名为app01_userinfo
class UserInfo(models.Model):
    #id列,自增,主键
    username = models.CharField(max_length=32)
    password = models.CharField(max_length=64)
AutoField(Field)
        - int自增列,必须填入参数 primary_key=True

    BigAutoField(AutoField)
        - bigint自增列,必须填入参数 primary_key=True

        注:当model中如果没有自增列,则自动会创建一个列名为id的列
        from django.db import models

        class UserInfo(models.Model):
            # 自动创建一个列名为id的且为自增的整数列
            username = models.CharField(max_length=32)

        class Group(models.Model):
            # 自定义自增列
            nid = models.AutoField(primary_key=True)
            name = models.CharField(max_length=32)

    SmallIntegerField(IntegerField):
        - 小整数 -32768 ~ 32767

    PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
        - 正小整数 0 ~ 32767
    IntegerField(Field)
        - 整数列(有符号的) -2147483648 ~ 2147483647

    PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
        - 正整数 0 ~ 2147483647

    BigIntegerField(IntegerField):
        - 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807

    自定义无符号整数字段

        class UnsignedIntegerField(models.IntegerField):
            def db_type(self, connection):
                return 'integer UNSIGNED'

        PS: 返回值为字段在数据库中的属性,Django字段默认的值为:
            'AutoField': 'integer AUTO_INCREMENT',
            'BigAutoField': 'bigint AUTO_INCREMENT',
            'BinaryField': 'longblob',
            'BooleanField': 'bool',
            'CharField': 'varchar(%(max_length)s)',
            'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
            'DateField': 'date',
            'DateTimeField': 'datetime',
            'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
            'DurationField': 'bigint',
            'FileField': 'varchar(%(max_length)s)',
            'FilePathField': 'varchar(%(max_length)s)',
            'FloatField': 'double precision',
            'IntegerField': 'integer',
            'BigIntegerField': 'bigint',
            'IPAddressField': 'char(15)',
            'GenericIPAddressField': 'char(39)',
            'NullBooleanField': 'bool',
            'OneToOneField': 'integer',
            'PositiveIntegerField': 'integer UNSIGNED',
            'PositiveSmallIntegerField': 'smallint UNSIGNED',
            'SlugField': 'varchar(%(max_length)s)',
            'SmallIntegerField': 'smallint',
            'TextField': 'longtext',
            'TimeField': 'time',
            'UUIDField': 'char(32)',

    BooleanField(Field)
        - 布尔值类型

    NullBooleanField(Field):
        - 可以为空的布尔值

    CharField(Field)
        - 字符类型
        - 必须提供max_length参数, max_length表示字符长度

    TextField(Field)
        - 文本类型

    EmailField(CharField):
        - 字符串类型,Django Admin以及ModelForm中提供验证机制

    IPAddressField(Field)
        - 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制

    GenericIPAddressField(Field)
        - 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6
        - 参数:
            protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
            unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启刺功能,需要protocol="both"

    URLField(CharField)
        - 字符串类型,Django Admin以及ModelForm中提供验证 URL

    SlugField(CharField)
        - 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)

    CommaSeparatedIntegerField(CharField)
        - 字符串类型,格式必须为逗号分割的数字

    UUIDField(Field)
        - 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证

    FilePathField(Field)
        - 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能
        - 参数:
                path,                      文件夹路径
                match=None,                正则匹配
                recursive=False,           递归下面的文件夹
                allow_files=True,          允许文件
                allow_folders=False,       允许文件夹

    FileField(Field)
        - 字符串,路径保存在数据库,文件上传到指定目录
        - 参数:
            upload_to = ""      上传文件的保存路径
            storage = None      存储组件,默认django.core.files.storage.FileSystemStorage

    ImageField(FileField)
        - 字符串,路径保存在数据库,文件上传到指定目录
        - 参数:
            upload_to = ""      上传文件的保存路径
            storage = None      存储组件,默认django.core.files.storage.FileSystemStorage
            width_field=None,   上传图片的高度保存的数据库字段名(字符串)
            height_field=None   上传图片的宽度保存的数据库字段名(字符串)

    DateTimeField(DateField)
        - 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]

    DateField(DateTimeCheckMixin, Field)
        - 日期格式      YYYY-MM-DD

    TimeField(DateTimeCheckMixin, Field)
        - 时间格式      HH:MM[:ss[.uuuuuu]]

    DurationField(Field)
        - 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型

    FloatField(Field)
        - 浮点型

    DecimalField(Field)
        - 10进制小数
        - 参数:
            max_digits,小数总长度
            decimal_places,小数位长度

    BinaryField(Field)
        - 二进制类型

字段
字段类型

 

null                数据库中字段是否可以为空
    db_column           数据库中字段的列名
    default             数据库中字段的默认值
    primary_key         数据库中字段是否为主键
    db_index            数据库中字段是否可以建立索引
    unique              数据库中字段是否可以建立唯一索引
    unique_for_date     数据库中字段【日期】部分是否可以建立唯一索引
    unique_for_month    数据库中字段【月】部分是否可以建立唯一索引
    unique_for_year     数据库中字段【年】部分是否可以建立唯一索引
    
    auto_now          无论是你添加还是修改对象,时间为你添加或者修改的时间。
    auto_now_add    为添加时的时间,更新对象时不会有变动
    想要在添加数据时更新时间要用:
        obj=UserGroup.objects.filter(id=1).first()
        obj.caption="CEO"
        obj.save()
    如果使用:
        obj=UserGroup.objects.filter(id=1).update(caption="CEO")则不会更新
    verbose_name        Admin中显示的字段名称
    blank               Admin中是否允许用户输入为空
    editable            Admin中是否可以编辑
    help_text           Admin中该字段的提示信息
    choices             Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
                        如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1)

    error_messages      自定义错误信息(字典类型),从而定制想要显示的错误信息;
                        字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date
                        如:{'null': "不能为空.", 'invalid': '格式错误'}

    validators          自定义错误验证(列表类型),从而定制想要的验证规则
                        from django.core.validators import RegexValidator
                        from django.core.validators import EmailValidator,URLValidator,DecimalValidator,\
                        MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator
                        如:
                            test = models.CharField(
                                max_length=32,
                                error_messages={
                                    'c1': '优先错信息1',
                                    'c2': '优先错信息2',
                                    'c3': '优先错信息3',
                                },
                                validators=[
                                    RegexValidator(regex='root_\d+', message='错误了', code='c1'),
                                    RegexValidator(regex='root_112233\d+', message='又错误了', code='c2'),
                                    EmailValidator(message='又错误了', code='c3'), ]
                            )
参数

 

b.注册app

settings:添加要创建表的app

  

c.执行命令

python manage.py makemigrations

python manage.py migrate   这样就自动把表创建下来了

d.注意:django内部默认用的是sqlite

如果需要使用mysql,django默认用的是mysqldb这个模块,我们要导入

a.主动修改为pymysql.在project同名的文件夹下的__init__文件中添加如下代码:

import pymysql
pymysql.install_as_MySQLdb()

b.修改settings.py

DATABASES = {
    'default': {
    'ENGINE': 'django.db.backends.mysql',
    'NAME':'dbname',
    'USER': 'root',
    'PASSWORD': 'xxx',
    'HOST': '',
    'PORT': '',
    }
}

创建之后如下图显示:

 

2.根据类对数据库中的数据进行各种操作  

 创建数据:

#创建数据
第一种方式:    models.UserInfo.objects.create(username='root',password='123',)

第二种方式:
dic = {'username':'xiaoming','password':'6666'}
models.UserInfo.objects.create(**dic)

第三种方式:
obj=models.UserInfo(username='root1',password='1234')
obj.save()

 

 查找数据:

#查找所有数据
result = models.UserInfo.objects.all()
for row in result:
     print(row.id,row.username,row.password)
#普通的条件查询
result = models.UserInfo.objects.filter(username='root',password='123')
for row in result:
     print(row.id,row.username,row.password)
result = models.UserInfo.objects.all().values('id','username')#这个返回的就是字典,比如[{'id':1,'username':'xiaoming'},{'id':2,'username':'xiaohong'}]
result = models.UserInfo.objects.all().value_list('id','username')#返回的内部是一个元组[(1,'xiaoming'),(2,'xiaohong')]
result = models.UserInfo.objects.get(id=1)#获得到一个对象,如果不存在就报错
对象或者None = models.UserInfo.objects.filter(id=1).first()
result = models.UserInfo.objects.filter(id__gt=1)>
result = models.UserInfo.objects.filter(id__it=1)<
result = models.UserInfo.objects.filter(id__gte=1)>=
result = models.UserInfo.objects.filter(id__lte=1)<=

 

删除数据

#删除所有数据
models.UserInfo.objects.all().delete()
#按条件查询
models.UserInfo.objects.filter(id=4).delete()

 

更新数据

#更新所有数据
models.UserInfo.objects.all().update(password='6669')
#按条件更新数据
models.UserInfo.objects.filter(id=3).update(password='6669')

 一对多:

  a.外键

b = models.ForeignKey(to='Business',to_field='id',on_delete=models.CASCADE)
                                   - models.CASCADE,删除关联数据,与之关联也删除
                                                   - models.DO_NOTHING,删除关联数据,引发错误IntegrityError
                                                   - models.PROTECT,删除关联数据,引发错误ProtectedError
                                                   - models.SET_NULL,删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空)
                                                   - models.SET_DEFAULT,删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)
                                                   - models.SET,删除关联数据,
                                                          a. 与之关联的值设置为指定值,设置:models.SET(值)
                                                          b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)

 

  b.生成在数据库的字段为外键字段_id

  c.创建数据的时候就根据这个id来创建就可以了

  d.取数据

v1 = models.Host.objects.filter(nid__gt=0)
v[0].b.caption ---> 通过.实现跨表

 如果想要在查询的时候获取多表的字段就要用双下划綫

v1 = models.Host.objects.filter(nid__gt=0).values('nid','hostname','b_id','b__caption')返回的还是一个字典,
取值:for row in v1:
    print(row['nid'],row['hostname'],row['b_id'],row['b__caption'])
在模板中:
    {{ row.b__caption }}

 那么我们能够在host通过外键查询到Bussiness中的数据,那能不能在Business表中反向查询到host中的数据呢?(反向查询) 

  虽然两张表没有在host中体现出来关联,只要用表名_set,就可以找到Business中的数据了

多对多:

 创建多对多:

方式一:自定义关系表
class Host(models.Model):
    nid = models.AutoField(primary_key=True)
    hostname = models.CharField(max_length=32,db_index=True)
    ip = models.GenericIPAddressField(protocol='ipv4',db_index=True)
    port = models.IntegerField()
    b = models.ForeignKey(to='Business',to_field='id',on_delete=models.CASCADE)

class Application(models.Model):
    name = models.Char  Field(max_length=32)

class HostToApp(models.Model):
    hobj = models.ForeignKey(to='Host',to_field='nid',on_delete=models.CASCADE)
    aobj = models.ForeignKey(to='Application',to_field='id',on_delete=models.CASCADE)

方式二:自动创建关系表(默认生成3列class Host(models.Model):
    nid = models.AutoField(primary_key=True)
    hostname = models.CharField(max_length=32,db_index=True)
    ip = models.GenericIPAddressField(protocol='ipv4',db_index=True)
    port = models.IntegerField()
    b = models.ForeignKey(to='Business',to_field='id',on_delete=models.CASCADE)

class Application(models.Model):
    name = models.CharField(max_length=32)
    r = models.ManyToManyField('Host')

方式二创建之后我们看数据库:多了一张表叫做app01_application_r,相当于写了两个类,创建了三张数据表

我们看一下里面的字段:里面有两个字段一个是application_id,一个是host_id,自动创建外键

 第二种创建多个外键的方法的缺点:

  • 只能够创建3个字段,如果想要在添加另外表的外键就不可以了
  • 无法直接的向创建的外键表添加字段,即无法使用models.表名.objects.create()

 那我们怎么为这个第三张表创建数据呢?

首先我们先查找到application表id为1:

obj  = Application.objects.get(id = 1)

增加数据:

obj.r.add(1)      obj.r.add(2)           obj.r.add(2,3,4)     obj.r.add(*[1,2,3,4])

删除数据:

obj.r.remove(1)       obj.r.remove(2,4)        obj.r.remove(*[1,2,3])

清除所有application_id为1的数据:

obj.r.clear()

更新数据

obj.r.set([3,5,7])数据库中只会存在1,3;1,5;1,7三组数据,其他的都被删除

查询数据

obj.r.all()返回的是QuerySet类型的列表