Django常用操作笔记

注:适用于 2.x 版本

1.pip 命令安装方法

pip install Django #指定版本  Django==2.2.3

2.新建一个项目

django-admin startproject 项目名

3.新建项目下新建 app

django-admin startapp app名

4.启动

python manage.py runserver 0.0.0.0:8000 (IP:端口)

5.settings.py 文件配置

------------------

1.INSTALLED_APPS 添加创建app

INSTALLED_APPS = [

  ....xxx,

  'app名1',

]

2.TEMPLATES 配置模板文件路径在 templates 文件下

TEMPLATES = [

    {

        'BACKEND': 'django.template.backends.django.DjangoTemplates',

        'DIRS': [os.path.join(BASE_DIR, 'templates')], #模板文件路径

        'APP_DIRS': True,

        ...xxx

    },

]

3.静态文件配置

STATIC_URL = '/static/' #静态指向别名 如:/static/index.css

STATICFILES_DIRS=(

    os.path.join(BASE_DIR,'static'), #静态目录地址配置,一般放在static文件夹下

)

4.配置404

DEBUG = False

ALLOWED_HOSTS = ["*"]

6.urls.py 路由配置

from django.urls import include, path, re_path

from blog import views #自己创建app指向配置,一般指向views.py

urlpatterns = [

    path('admin/', admin.site.urls),

    path('', views.index),

    path('cbv', views.CBV.as_view()), # class CBV形式

    path('articles/<int:year>/<int:month>', views.year_archive),

    path('blog/', include('blog.urls')), #分发url 在 blog/urls.py

    re_path(r'page/(\d{1,4})',views.pageNum,name="page"), #正则用法

]

handler404=views.page404 #配置404

如:views.py

from django.shortcuts import render,HttpResponse,redirect

from django.views import View # class形式

from django.urls import reverse #获取别名 urls.py 的 name 指定值

class CBV(View):

    def get(self,request):

        return render(request,'index.html')

    def post(self,request):

        return render(request,'index.html')

def index(request):

    return render(request,'index.html',{'title':'我是首页'})

def year_archive(request,year,month):

    return render(request,'time.html',{'time':'%s - %s'%(year,month)})

def pageNum(request,num):

    # reverse('page',args=(1,)) #获取urls.py 里别名 name="page" 的路径:page/1

    return render(request,'page.html',{'num':num})

redirect('/show/111') #页面跳转

#配置404

def page404(request, exception):

    return render(request,'404.html')

request 取值

-------

if request.method == 'GET':

    request.GET.get('name')

elif request.method == 'POST':

    request.POST.get('name')

request.path #获取路径 /home

request.get_full_path() #获取全路径 /home?age=11

7.templates模板用法:

变量语法:

{

  obj:{

    'name':66,

    'list':[1,2]

  }

}

{{obj.name}} 对象 , {{obj.list.0}} 列表

获取当前网址:{{ request.path }}

获取当前 GET 参数:{{ request.GET.urlencode }}

form 表单验证:{% csrf_token %} #不带回报403

settings.py 文件配置

MIDDLEWARE = [

    # 'django.middleware.csrf.CsrfViewMiddleware', #取消csrf 验证

]

if 判断:

{% if age >= 90 %}

...

{% elif age >= 80 %}

...

{% else %}

...

{% endif %}

for 循环:

{% for athlete in athlete_list %}

    <li>{{forloop.counter}}:{{ athlete.name }}</li>

{% empty %}

    <li>抱歉,列表为空</li>

{% endfor %}

forloop.counter 索引从 1 开始算

forloop.counter0 索引从 0 开始算

forloop.revcounter 索引从最大长度到 1

forloop.revcounter0 索引从最大长度到 0

forloop.first 当遍历的元素为第一项时为真

forloop.last 当遍历的元素为最后一项时为真

forloop.parentloop 用在嵌套的 for 循环中,获取上一层 for 循环的 forloop

遍历字典

{% for key, value in info_dict.items %}

    {{ key }}: {{ value }}

{% endfor %}

模块引入

{% include 'nav.html' %}

{% block content %}

<div>这里是默认内容,所有继承自这个模板的,如果不覆盖就显示这里的默认内容。</div>

{% endblock %}

模板继承

{% extends 'base.html' %}

数据库操作

-----------

#settings.py 文件配置

DATABASES = {

    'default': {

        'ENGINE': 'django.db.backends.mysql',

        'NAME': 'django', #数据库名称

        'USER': 'root', #用户名

        'PASSWORD': 'heng123456', #密码

        'HOST': '', #地址 默认localhost

        'PORI': '3306', #端口

    }

}

#配置引擎

pip install PyMySQL #先安装PyMySQL

在当前项目__init__.py里配置

import pymysql

pymysql.install_as_MySQLdb()

创建表

python manage.py makemigrations #生成配置

python manage.py migrate #执行配置

报错:

# 找到base.py文件,注释掉 base.py 中如下部分(35/36行)

if version < (1, 3, 3):

    raise ImproperlyConfigured("mysqlclient 1.3.3 or newer is required; you have %s" % Database.__version__)

此时仍会会报错,报错信息如下:

AttributeError: ‘str’ object has no attribute ‘decode’

#找到operations.py文件(146行),将decode改为encode

表记录操作

models.py里配置

from django.db import models

# 定义表

class Book(models.Model):

    name=models.CharField(max_length=20)

    price=models.IntegerField() #models.FloatField(3,1)

    pub_data=models.DateField()

    author=models.CharField(max_length=32,null=False)

    #外键(默认关联主键),加参数 related_name="xxx" 设置反向查找名称, 默认是publish

    publish=models.ForeignKey("Author",on_delete=models.CASCADE) # ForeignKey("self") 表示关联自己

    #多对多(会新建个对应id表 info_id)

    info=models.ManyToManyField("Info")

#取消 ForeignKey 外键约束,保留双下划线跨表查询功能:(外键约束会影响数据库性能推荐取消)

----

models.ForeignKey("Author",db_constraint=False) #取消外键约束

----

# ForeignKey 里的 on_delete 参数机制

-----------------------------------

参数说明:

on_delete有CASCADE、PROTECT、SET_NULL、SET_DEFAULT、SET()五个可选择的值

on_delete=None,              # 删除关联表中的数据时,当前表与其关联的field的行为

on_delete=models.CASCADE,    # 删除关联数据,与之关联也删除

on_delete=models.DO_NOTHING,  # 删除关联数据,什么也不做

on_delete=models.PROTECT,    # 删除关联数据,引发错误ProtectedError

# models.ForeignKey('关联表', on_delete=models.SET_NULL, blank=True, null=True)

on_delete=models.SET_NULL,    # 删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空,一对一同理)

# models.ForeignKey('关联表', on_delete=models.SET_DEFAULT, default='默认值')

on_delete=models.SET_DEFAULT, # 删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值,一对一同理)

on_delete=models.SET(),      # 删除关联数据,此值设置,会调用外面的值,可以是一个函数

a. 与之关联的值设置为指定值,设置:models.SET(值)

b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)

-------------------------

# ManyToManyField 多对多

--------

参数说明:

symmetrical,只用在自己对自己进行关联的时候。比如说Friend,你的朋友是我,我的朋友是你。

through,如果不想要Django自动创建的多对多的关系表(默认建立就三列),可以通过指定through指定自己定义的中介表。

through_fields,在上面的基础上指定中间模型的**哪些字段**来建立是多对多关联。

db_table,设定多对多关系表的名称。

db_constraint,同上

#自定义第三张表如:

models.ManyToManyField(through='UserToTag') #加 through_fields=['u','t'] 相当于加 class Meta

class UserToTag(models.Model):

    u=models.ForeignKey('User',db_constraint=False)

    t=models.ForeignKey('Tag',db_constraint=False)

    new_time=models.DateField()

    class Meta:

        #设置联合唯一,User和Tag不能再创建两个相同的否则报错

        unique_together=[('u','t')]

        db_table='UserToTag' #数据库表名

        verbose_name_plural='用户表' # admin使用的名称

------------------------

表记录添加 ,一共有四种方法

例:

---

from blog.models import *

def addbook(request):

    b=Book(name="python基础教程",price=67,author="小明",pub_data="2017-10-09")

    b.save()

---

# 方法 1

Book.objects.create(name="python基础教程")

# 批量创建

objs = [

    models.Book(name='r11'),

    models.Book(name='r22')

]

models.Book.objects.bulk_create(objs, 10) # 10 是最多插入数

# 方法 2

b = Book(name="python基础教程",price=67)

b.save()

# 方法 3

b = Book()

b.name="python基础教程"

b.save()

# 方法 4,首先尝试获取,不存在就创建,可以防止重复

Book.objects.get_or_create(name="python基础教程",price=67)

# 返回值(object, True/False)

#表更新

------

批量更新 (filter是拿到的集合)

Book.objects.filter(name="python基础教程").update(name='xxx') # 名称中包含 "abc"的人 都改成 xxx

单个 object 更新

b = Book.objects.get(name="WeizhongTu")

b.name="WeizhongTu"

b.save()  # 最后不要忘了保存!!!

如果存在,则更新,否则,创建, defaults 指定创建时或更新时的其他字段

obj, created = models.UserInfo.objects.update_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 1})

#表删除

------

Book.objects.filter(name="python基础教程").delete()

Book.objects.all().delete() # 删除所有 Person 记录

------

#表查询 注:filter和values通过 __下划线跨表查

b=Book.objects

b.filter(name="python基础教程") #条件查询返回集合

.values('name','age') #只显示两个值,vlaues 是返回字典形式 [{},{}]

.values('name','publish__author') # 跨表查publish表里的author字段 (publish 外键)

注:跨多表 publish__info__name # publish表里info外键表里的name字段

.values_list('name','age') #元组形式 [(),()]

b.exclude(id=3) #查询所有id不等于3的人

b.all() #查询所有 all()[:3] 支持支持切片

b.get(name="python基础教程") #取单个

b.filter(name="").first() #取第一个

b.all().last() #取最后一个

b.all().order_by('name') #查询结果排序

b.all().order_by('-name') # 在 column name 前加一个负号,可以实现倒序

b.all().order_by('name').reverse() #取反

b.all().values('name').distinct() #去重

.count() #计数

b.all().only('name','email') # only 是指只取当前这列的属性'name','email'

b.all().defer('name','email') # defer和only正好相反,除了括号内的属性其他都要取出来

------------

# 跨表查询优化(默认通过外键取值会触发一次查询,多次取多次触发)《优化重点 !!!》

# 跨表查询时用 select_related('a','b',..)

b.all().select_related('publish') #表优化减少sql请求(会一次拿到指定表的数据)

#select_related() 接受可变长参数,每个参数是需要获取的外键的字段名,以及外键的外键的字段名…。若要选择外键的外键需要使用两个下划线“__”来连接。

如:

obj = Person.objects.select_related('publish__info')

obj.publish.info

注:prefetch_related效果和select_related类似,不过使用的场景不同:

b.select_related 适用于外键和多对一的关系查询;

b.prefetch_related('外键字段') 适用于一对多或者多对多的查询

select_related() 也可以不加参数,这样表示要求Django尽可能深的select_related,但会浪费性能。

------------

# extra 用于额外的查询条件或者映射,如:子查询

Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,))

Entry.objects.extra(where=['headline=%s'], params=['Lennon'])

Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])

Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])

取值例:

v = models.Uinfo.objects.all().extra(select={

    'n':"select count(1) from app01_utype WHERE id=%s or id=%s",

    'm':"select count(1) from app01_uinfo WHERE id=%s or id=%s",

},select_params=[1,2,3,4])

for i in v:

    print(i.n,i.m,i.id)

------------

filter连接符

-----

filter(age__gt=10)

__exact 精确等于 like ‘aaa'

__iexact 精确等于 忽略大小写 ilike ‘aaa'

__contains 包含 like ‘%aaa%'

__icontains 包含 忽略大小写 ilike ‘%aaa%',但是对于sqlite来说,contains的作用效果等同于icontains。

__gt 大于

__gte 大于等于

__lt 小于

__lte 小于等于

__in=[1,3,5] 查询值为1,3,5的人

__startswith 以…开头

__istartswith 以…开头 忽略大小写

__endswith 以…结尾

__iendswith 以…结尾,忽略大小写

__range 在…范围内

__year 日期字段的年份

__month 日期字段的月份

__day 日期字段的日

__isnull=True/False

__overlap 集合至少有一个元素重合

__regex 匹配正则表达式

#多表操作

--------

添加记录 (publish 外键)

#publish_id=2

Book.objects.create(name="xx",publish_id=2)

#publish=object

publish_obj=Publish.objects.get(name="xx")

Book.objects.create(name="xx",publish=publish_obj.id)

#查询记录(通过对象)

#正向查询 (通过Book外键publish绑定的主键id 查publish里对应的数据)

book_obj=Book.objects.get(name="xx")

pub_obj=book_obj.publish

pub_obj.name

根据 publish 查 Book 的数据 (publish 外键名 下划线查询 __xx 对象名)

Book.objects.filter(publish__name="xx").values('name')

#反向查询 (通过publish反向查book里对应的数据)

pub_obj=Publish.objects.filter(name="xx")[0]

pub_obj.book_set.all().values('name')

通过Book绑定的外键 查Publish里对应的数据

Publish.objects.filter(book__name="xx").values('name')

注:OneToOneField 反向查询直接点名字就行,不用 _ 如:pub_obj.book

#多对多

正向

b=Book.objects.get(id=1) #Book的所有Info里的对应信息(底层通过外键来实现的)

b.info.all() #对应 info=models.ManyToManyField("Info")

反向

i=Info.objects.get(id=1)

i.book_set.all()

创建多对多关系

i=Info.objects.get(id=1)

b=Book.objects.get(id=5)

b.info.add(i) #添加

b.info.add([2,4]) #添加多个

b.info.remove(i) #删除 可以是id

b.info.remove([2,4]) #删除多个

b.info.clear() #删除所有绑定

b.info.set(1) #重置数据

b.info.set([1,2,3]) #重置多个

b.info.all() #查询所有关联

类似:left join 跨表查询 Book显示全部

Book.objects.filter(info__name="xx").values('name') #查看 book_info表里对应的book数据

聚合函数 aggregate

from django.db.models import Avg, Max, Min,Sum,Count #平均值:Avg()  求和:sum() 总数:Count()

b=Book.objects.all().aggregate(name=Avg("price")) #name 自己取的名字

b.name

分组 annotate

Book.objects.values('name').annotate(sum=Sum("price"))

查询 Q, F

from django.db.models import Q,F

Book.objects.all().update(price=F('price')+10) #相当于 update book set price=price+10;

Book.objects.filter(Q(price=10)|Q(name="小明"),age=10) # | 或操作 ~ 非操作 (Q 放前面)

# Q 添加多个用法

q = Q()

q.connector = 'OR' # 或操作

q.children.append((price,10))

q.children.append((name,"小明"))

Book.objects.filter(q)

# 迭代器取值 iterator (节约内存)

ret=Book.objects.all().iterator()

for i in ret:

  print(i.name)

------------------

# 执行原始SQL查询

---------

1.导入django.db.connection对像,它代表当前数据库连接。

2.通过connection.cursor()得到一个游标对像。

3.使用cursor.execute(sql, [params])来执行SQL语句。

4.使用cursor.fetchone()或者cursor.fetchall()来返回记录集。

注:fetchall()返回的是元组的列表

例:

from django.db import connection, connections

cursor = connection.cursor()

#cursor = connections['default'].cursor() #指定sttings.py 里配置的数据库

cursor.execute("""

    SELECT DISTINCT first_name

    FROM people_person

    WHERE last_name = %s""", ['Lennon'])

row = cursor.fetchone() #返回结果 ['John']

# models.Manager 整合 class

from django.db import connection, models

class PersonManager(models.Manager):

    def first_names(self, last_name):

        cursor = connection.cursor()

        cursor.execute("""

            SELECT DISTINCT first_name

            FROM people_person

            WHERE last_name = %s""", [last_name])

        return [row[0] for row in cursor.fetchone()]

class Person(models.Model):

    first_name = models.CharField(max_length=50)

    last_name = models.CharField(max_length=50)

    objects = PersonManager()

>>Person.objects.first_names('Lennon')

#返回结果 ['John', 'Cynthia']

---

#另一种原始SQL查询

Book.objects.raw("select id,name form book where id=%s",params=[12,]) #必须有id主键否则会报错

--------

#Django表model创建字段说明

-------------------------

一、字段

1、models.AutoField  自增列 = int(11)

  如果没有的话,默认会生成一个名称为 id 的列,如果要显示的自定义一个自增列,必须将给列设置为主键 primary_key=True。

2、models.CharField  字符串字段

  必须 max_length 参数

3、models.BooleanField  布尔类型=tinyint(1)

  不能为空,Blank=True

4、models.ComaSeparatedIntegerField  用逗号分割的数字=varchar

  继承CharField,所以必须 max_lenght 参数

5、models.DateField  日期类型 date

  对于参数,auto_now = True 则每次更新都会更新这个时间;auto_now_add 则只是第一次创建添加,之后的更新不再改变。

6、models.DateTimeField  日期类型 datetime

  同DateField的参数

7、models.Decimal  十进制小数类型 = decimal

  必须指定整数位max_digits和小数位decimal_places

8、models.EmailField  字符串类型(正则表达式邮箱) =varchar

  对字符串进行正则表达式

9、models.FloatField  浮点类型 = double (3,1) 第一个总数第二个小位数

10、models.IntegerField  整数

11、models.BigIntegerField  长整型

  integer_field_ranges = {

    'SmallIntegerField': (-32768, 32767),

    'IntegerField': (-2147483648, 2147483647),

    'BigIntegerField': (-9223372036854775808, 9223372036854775807),

    'PositiveSmallIntegerField': (0, 32767),

    'PositiveIntegerField': (0, 2147483647),

  }

12、models.IPAddressField  字符串类型(ip4正则表达式)

13、models.GenericIPAddressField  字符串类型(ip4和ip6是可选的)

  参数protocol可以是:both、ipv4、ipv6

  验证时,会根据设置报错

14、models.NullBooleanField  允许为空的布尔类型

15、models.PositiveIntegerFiel  正Integer

16、models.PositiveSmallIntegerField  正smallInteger

17、models.SlugField  减号、下划线、字母、数字

18、models.SmallIntegerField  数字

  数据库中的字段有:tinyint、smallint、int、bigint

19、models.TextField  字符串=longtext

20、models.TimeField  时间 HH:MM[:ss[.uuuuuu]]

21、models.URLField  字符串,地址正则表达式

22、models.BinaryField  二进制<br>23、models.ImageField  图片<br>24、models.FilePathField 文件

二、字段参数

1、null=True

  数据库中字段是否可以为空

2、blank=True

  django的 Admin 中添加数据时是否可允许空值

3、primary_key = False

  主键,唯一不为空,对AutoField设置主键后,就会代替原来的自增 id 列

4、auto_now 和 auto_now_add

  auto_now  自动创建---无论添加或修改,都是当前操作的时间

  auto_now_add  自动创建---永远是创建时的时间

5、choices 获取对应值

set_value = (

    (1, '确认'),

    (2, '取消'),

)

class Back():

    gender = models.CharField(max_length=2,choices = set_value)

Back.objects.filter(gender=1).first().get_gender_display() # gender 字段数据库值为 1 时得到值:确认

6、max_length 长度

7、default  默认值

8、verbose_name  Admin中字段的显示名称

9、name|db_column  数据库中的字段名称

10、unique=True  不允许重复

11、db_index = True  数据库索引

12、editable=True  在Admin里是否可编辑

13、error_messages=None  错误提示

14、auto_created=False  自动创建

15、help_text  在Admin中提示帮助信息

16、validators=[]

17、upload-to

附录表之间的关系

1、一对多,models.ForeignKey(ColorDic) # 就是加一个外键

    应用场景:在某表中创建一行数据时,有一个单选的下拉框(下拉框中的内容被用过一次就消失了)。

2、一对一,models.OneToOneField(OneModel) # 就是外键加唯一索引

    应用场景:当一张表中创建一行数据时,有一个单选的下拉框(可以被重复选择)。

3、一对多,models.ManyToManyField(Author) # 建立第三张表,关联第三张表

    应用场景:在某表中创建一行数据是,有一个可以多选的下拉框。

-------------------------

#序列化

------|

from django.core import serializers

obj = models.Student.objects.all().values()

#转成字典对象形式(推荐用法)

list(obj) #=> [{},{}]

#转成json格式但会有多层

#serializers.serialize('json',obj)

-------------------------

#分页设置

--------

from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger

arr=Book.objects.all()

#如 arr = ['john','paul','george','ringo','lucy','meiry','checy','wind','flow','rain']

p = Paginator(arr,3)  # 3 一页显示3条,实例化分页对象

p.count  # 10 对象总共10个元素

p.num_pages  # 4 对象可分4页

p.page_range  # xrange(1, 5) 对象页的可迭代范围

page1 = p.page(1)  # 取对象的第一分页对象

page1.object_list  # 第一分页对象的元素列表['john', 'paul', 'george']

page1.number  # 第一分页对象的当前页值 1

page2 = p.page(2)  # 取对象的第二分页对象

page2.object_list  # 第二分页对象的元素列表 ['ringo', 'lucy', 'meiry']

page2.number  # 第二分页对象的当前页码值 2

page1.has_previous()  # 第一分页对象是否有前一页 False

page1.has_other_pages()  # 第一分页对象是否有其它页 True

page2.has_previous()  # 第二分页对象是否有前一页 True

page2.has_next()  # 第二分页对象是否有下一页 True

page2.next_page_number()  # 第二分页对象下一页码的值 3

page2.previous_page_number()  # 第二分页对象的上一页码值 1

page2.start_index()  # 第二分页对象的元素开始索引 4

page2.end_index()  # 第2分页对象的元素结束索引 6

---------

#表单验证

------------------------

from django import forms

from django.forms import fields,widgets

from django.core.exceptions import ValidationError

from django.core.validators import RegexValidator

class ReForm(forms.Form):

    name = fields.CharField(

        min_length=2, #最小值

        max_length=18, #最大值

        required=True, #是否必填

        error_messages={ #自定义错误信息

        'required':'名称不能为空',

        'min_length':'名字不能小于两位'

        },

        validators=[ # 自定制正则验证,可以定义多个

            RegexValidator(r'^[0-9]\\d{5}$','邮政编码格式不正确'),

            ...

        ],

        widget=widgets.Select() #定制html插件

    )

    author = fields.CharField(min_length=1,max_length=10,required=True,error_messages={

        'required':'作者不能为空',

        'max_length':'作者名字不能大于10位'

    })

    price = fields.IntegerField(

        min_value=0, #最小值

        max_value=50, #最大值

        required=True,

        error_messages={

        'required':'价格不能为空',

        'invalid':'必须为数字' #格式问题统一叫 invalid

    })

    #自定义单字段扩展 clean_*

    def clean_name(self):

        v = self.cleaned_data['name']

        if Book.objects.filter(name=v).count():

            raise ValidationError('名称已存在')

        return v

    #整体自定义扩展可以验证多字段

    def clean(self):

        obj = self.cleaned_data

        name= obj.get('author')

        age= obj.get('age')

        if Book.objects.filter(name=name).count() and int(age)<12:

            raise ValidationError('已存在作者年龄小于12不能再添加')

        return self.cleaned_data

def addbook(request):

    if request.method=="POST":

        da=ReForm(request.POST)

        obj={}

        if da.is_valid():

            obj=da.cleaned_data #成功数据,是字典格式

        else:

            return JsonResponse({'code':400,'message':da.errors))

    Book.objects.create(**obj)

------------------

注:fields 字段说明

---------- 

Field

        required=True#请求不能为空

        widget=None#HTML插件

        label=None#用于生成lable标签或显示内容

        initial=None#初始值(第一次不验证)

        help_text=''#帮助信息(在标签旁边显示)

        error_messages=None#(错误信息{‘required’:'不能为空',‘invalid’:‘格式错误’})

        show_hidden_initial=False#是否在当前插件后面加一个隐藏的并且有默认值的插件(可用于检验两次输入是否一致)

        validators=[] #自定义验证规则

        localize=False#是否支持本地化

        disabled=False#是否可以编辑

        label_suffix=None#label内容后缀


CharField(Field)

    max_length=None,            最大长度

    min_length=None,            最小长度

    strip=True                  是否移除用户输入空白

IntegerField(Field)

    max_value=None,              最大值

    min_value=None,              最小值

FloatField(IntegerField)

    ...

DecimalField(IntegerField)

    max_value=None,              最大值

    min_value=None,              最小值

    max_digits=None,            总长度

    decimal_places=None,        小数位长度

BaseTemporalField(Field)

    input_formats=None          时间格式化 

DateField(BaseTemporalField)    格式:2015-09-01

TimeField(BaseTemporalField)    格式:11:12

DateTimeField(BaseTemporalField)格式:2015-09-01 11:12

DurationField(Field)            时间间隔:%d %H:%M:%S.%f

    ...

RegexField(CharField)

    regex="",                  自定义判断的正则表达式

    max_length=None,            最大长度

    min_length=None,            最小长度

    error_message=None,        忽略,错误信息使用 error_messages={'invalid': '...'}

EmailField(CharField)     

    ...

FileField(Field)

    allow_empty_file=False,    是否允许空文件

    verbose_name_plural="admin里的名字",

    upload_to="admin里上传的路径"

ImageField(FileField)     

    ...

    注:需要PIL模块,pip3 install Pillow

    以上两个字典使用时,需要注意两点:

        - form表单中 enctype="multipart/form-data"

        - view函数中 obj = MyForm(request.POST, request.FILES)

URLField(Field)

    ...

BooleanField(Field) 

    ...

NullBooleanField(BooleanField)

    ...

ChoiceField(Field)

    ...

    choices=(),                选项,如:choices = ((0,'上海'),(1,'北京'),)

    required=True,            是否必填

    widget=None,              插件,默认select插件

    label=None,                Label内容

    initial=None,              初始值

    help_text='',              帮助提示

ModelChoiceField(ChoiceField)

    ...                        django.forms.models.ModelChoiceField

    queryset,                  # 查询数据库中的数据

    empty_label="---------",  # 默认空显示内容

    to_field_name=None,        # HTML中value的值对应的字段

    limit_choices_to=None      # ModelForm中对queryset二次筛选

ModelMultipleChoiceField(ModelChoiceField)

    ...                        django.forms.models.ModelMultipleChoiceField

TypedChoiceField(ChoiceField)

    coerce= lambda x:int(x)    对选中的值进行一次转换

    empty_value= ''            空值的默认值

MultipleChoiceField(ChoiceField)

    ...

TypedMultipleChoiceField(MultipleChoiceField)

    coerce = lambda val: val  对选中的每一个值进行一次转换

    empty_value= ''            空值的默认值

ComboField(Field)

    fields=()                  使用多个验证,如下:即验证最大长度20,又验证邮箱格式

                              fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])

MultiValueField(Field)

    PS: 抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultiWidget使用

SplitDateTimeField(MultiValueField)

    input_date_formats=None,  格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y']

    input_time_formats=None    格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']

FilePathField(ChoiceField)    文件选项,目录下文件显示在页面中

    path,                      文件夹路径

    match=None,                正则匹配

    recursive=False,          递归下面的文件夹

    allow_files=True,          允许文件

    allow_folders=False,      允许文件夹

    required=True,

    widget=None,

    label=None,

    initial=None,

    help_text=''

GenericIPAddressField

    protocol='both',          both,ipv4,ipv6支持的IP格式

    unpack_ipv4=False          解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用

SlugField(CharField)          数字,字母,下划线,减号(连字符)

    ...

UUIDField(CharField)          uuid类型

    ...

-----------------------

#文件上传

--------

前端

---

<div>

    <input type="file" id="imgs"><button id="update">上传</button>

</div>

$('#update').click(function () {

    var file = document.getElementById('imgs').files[0];

    if (!file) {

        return alert('请选择文件 !');

    }

    var obj = new FormData();

    obj.append('imgs', file);

    $.ajax({

        type: "POST",

        url: "/blog/update",

        dataType: "json",

        processData: false,

        contentType: false,

        data: obj,

        success: function (msg) {

            console.log(msg);

        }

    });

});

后端

---

import os,uuid

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# BASE_DIR 路径是当前目录上两层

#form形式获取

#class ReForm(forms.Form):

#  imgs=fields.FileField()

def index(request):

    if request.method == 'POST':

        #form形式获取

        #obj=ReForm(request.POST,request.FILES)

        #if obj.is_valid():

        #    img=obj.cleaned_data['imgs']

        #正常获取

        img=request.FILES.get('imgs')

        #属性 img.name, img.size, img.content_type (image/png)

        if img.content_type.find('image') == -1:

            return HttpResponse("不是图片!")

        name=str(uuid.uuid4().hex)

        with open(os.path.join(BASE_DIR,'imgs',name+img.name),'wb') as f:

            # img.chunks() 为可迭代对象

            try:

                for line in img.chunks():

                    f.write(line)

            except:

                HttpResponse("失败")

            else:

                HttpResponse("成功")

    return HttpResponse("需要post请求")

-----------------

#cookies及session

--------

#cookies

def login(request):

    request.COOKIES.get('name') #获取

    ret=redirect('/index')

    ret.set_cookie('name','yes',max_age=10) #设置 max_age=10 10秒失效

    ret.delete_cookie('name') #删除

    return ret

#session 默认保存15天

--------------------

def login(request):

    # 获取、设置、删除Session中数据

    request.session['k1']

    request.session.get('k1',None)

    request.session['k1'] = 123

    request.session.setdefault('k1',123) # 存在则不设置

    del request.session['k1']

    # 所有 键、值、键值对

    request.session.keys()

    request.session.values()

    request.session.items()

    request.session.iterkeys()

    request.session.itervalues()

    request.session.iteritems()

    # 用户session的随机字符串

    request.session.session_key

    # 将所有Session失效日期小于当前日期的数据删除

    request.session.clear_expired()

    # 检查 用户session的随机字符串 在数据库中是否

    request.session.exists("session_key")

    # 删除当前用户的所有Session数据

    request.session.delete("session_key")

    request.session.clear() #只清空记录不删数据库数据

    request.session.flush() #删除session数据库里的记录(优化内存)

    request.session.set_expiry(value)

    * 如果value是个整数,session会在些秒数后失效。

    * 如果value是个datatime或timedelta,session就会在这个时间后失效。

    * 如果value是0,用户关闭浏览器session就会失效。

    * 如果value是None,session会依赖全局session失效策略。

Django默认支持Session,并且默认是将Session数据存储在数据库中,即:django_session 表中。

session 配置 settings.py

SESSION_ENGINE = 'django.contrib.sessions.backends.db'  # 引擎(默认)

SESSION_COOKIE_NAME = "sessionid"                      # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)

SESSION_COOKIE_PATH = "/"                              # Session的cookie保存的路径(默认)

SESSION_COOKIE_DOMAIN = None                            # Session的cookie保存的域名(默认)

SESSION_COOKIE_SECURE = False                            # 是否Https传输cookie(默认)

SESSION_COOKIE_HTTPONLY = True                          # 是否Session的cookie只支持http传输(默认)

SESSION_COOKIE_AGE = 1209600                            # Session的cookie失效日期(2周)(默认)

SESSION_EXPIRE_AT_BROWSER_CLOSE = False                  # 是否关闭浏览器使得Session过期(默认)

SESSION_SAVE_EVERY_REQUEST = False                      # 是否每次请求都保存Session,默认修改之后才保存(默认)

缓存Session

SESSION_ENGINE = 'django.contrib.sessions.backends.cache'# 引擎

SESSION_CACHE_ALIAS = 'default'                          # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置

# 登录实例 Views.py

from django.shortcuts import render,redirect,HttpResponse

from django.http import JsonResponse

def login(request):

    if request.method=='GET':

        return render(request,'login.html')

    elif request.method=="POST":

        user=request.POST.get('username')

        pwd=request.POST.get('password')

        if user=="root" and pwd=="123":

            if request.POST.get('box')=="1":  #checkbox被按下

                request.session.set_expiry(10)  #session认证时间为10s,10s之后session认证失效

            request.session['username']=user  #user的值发送给session里的username

            request.session['is_login']=True  #认证为真

            return redirect('/index')

        else:

            return redirect('/login')

    return render(request,'login.html')

def index(request):

    if request.session.get('is_login',None):  #若session认证为真

        return render(request,'index.html',{'username':request.session['username']})

    else:

        # 如果是列表需要加 JsonResponse([1,2,3],safe=False)

        return JsonResponse({'code':400,'data':'非法登录 !'})

def logout(request):              #撤销

    request.session.flush()        #删除session数据库里的记录(优化内存)

    return redirect('/login')

------

#django内置登录

--

from django.contrib.auth import authenticate,login,logout

#验证登录

def islogin(request):

    error_msg=""

    if request.method=="POST":

        username=request.POST.get("username")

        password=request.POST.get("password")

        #查询django生成的auth_user表里有没有数据,没有返回None

        user=authenticate(username=username,password=password)

        if user:

            login(request,user)

            return redirect(request.GET.get('next',"/"))

        else:

            error_msg='用户名密码错误 !'

            print(username,password,sep=": ")

    return render(request, 'login.html',{'error_msg':error_msg})

#退出登录

def acc_logout(request):

    logout(request)

    return render(request, 'login.html')

#验证是否登录

from django.contrib.auth.decorators import login_required

#装饰器过滤是否登录 没登录就会跳到登录页 seitings.py 里配置 LOGIN_URL="/login"

@login_required

def home(request):

    pass

-------------

# admin使用

-------

1.admin.py配置

from django.contrib import admin

from blog import models

class BookAdmin(admin.ModelAdmin):

    '''以下都是可选''

    list_display=('id','name','author','price','pub_data') #显示字段

    list_editable=('name','author','price') #可编辑字段

    list_per_page=2 #分页

    search_fields=('id','name') #加搜索 id,name

    list_filter=('author','price') #加过滤器

    ordering=('price') #排序 ('-price')降序

admin.site.register(models.Book,BookAdmin) # BookAdmin 配置显示字段

admin.site.register(models.Author) # 注册models里的表 Book,Author

2.创建用户名密码

python manage.py createsuperuser

设置中文 settings.py

LANGUAGE_CODE = 'zh-Hans'

-------------------------

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容