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类型的列表