Django基础第三篇

一、ORM操作

1.常用字段和参数

  Autofied

  自增的整形字段,必填参数primary_key=True,  则成为数据库的主键,如无该字段,django自动创建

  IntegerField 

  一个整形类型,数值范围-2147483648 ~ 2147483647

  CharField

  字符类型,必须提供max_length参数。max_length表示字符的长度

  BooleanField  布尔

  DecimalField   小数

  FileField:文件路径

  DateTimeeField

  日期类型,日期格式YYYY-MM-DD

  参数:

    auto_now: 每次修改时修改为当前 日期时间                  ps: 修改是当前时间也会变

    auto_now_add: 新创建对象时自动添加当前日期时间     ps:新增是保持,修改是不会变

  ps: auto_now_add auto_now 和default 是互斥的 同一时间只能选择一个

  

class Person(models.Model):
    pid = models.AutoField(primary_key=True)                 修改主键 
    name = models.CharField(max_length=32)                 
    age = models.IntegerField()
    birth = models.DateTimeField(auto_now_add=True)

 

所有这段类型

 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

    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)
        - 二进制类型
View Code

 

常用参数:

  null : 数据库可为空

  blank :数据校验时可为空

  default : 默认值

  unique : 唯一约束

  verbose_name : 中文提示

  choices : 可选择的数据

from django.db import models

# Create your models here.

class Person(models.Model):
    pid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32,db_column="username",unique=True,verbose_name="姓名")
    age = models.IntegerField(null=True,blank=True,verbose_name="年龄")
    birth = models.DateTimeField(auto_now_add=True)
    gender = models.IntegerField(choices=[(0,""),(1,"")],default=0) choices里面需要放一个可迭代对象,第一个是数据库存放的数据 第二个是admin界面显示

 

字段参数

 null                数据库中字段是否可以为空
    db_column           数据库中字段的列名
    default             数据库中字段的默认值
    primary_key         数据库中字段是否为主键
    db_index            数据库中字段是否可以建立索引
    unique              数据库中字段是否可以建立唯一索引
    unique_for_date     数据库中字段【日期】部分是否可以建立唯一索引
    unique_for_month    数据库中字段【月】部分是否可以建立唯一索引
    unique_for_year     数据库中字段【年】部分是否可以建立唯一索引
 
    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'), ]
                            )
View Code

 

注册django自带的admin管理控制台

在app01下的admin里面写注册

from django.contrib import admin
from app01 import models
# Register your models here.
admin.site.register(models.Person)

启动项目
创建超级用户
python manage.py createsuperuser

 

Model Meta给表做上相应的参数

不是很常用
class UserInfo(models.Model):
    nid = models.AutoField(primary_key=True)
    username = models.CharField(max_length=32)
 
    class Meta:
        # 数据库中生成的表名称 默认 app名称 + 下划线 + 类名
        db_table = "table_name"
 
        # admin中显示的表名称
        verbose_name = '个人信息'
 
        # verbose_name加s
        verbose_name_plural = '所有用户信息'
 
        # 联合索引 
        index_together = [
            ("pub_date", "deadline"),   # 应为两个存在的字段
        ]
 
        # 联合唯一索引
        unique_together = (("driver", "restaurant"),)   # 应为两个存在的字段

 

2.必知必会13条

import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day16.settings")
import django
django.setup()

from app01 import models

#all() 查询所有数据 [对象]  对象列表 queryset
ret = models.Person.objects.all()
#filter()查询满足条件的对象
ret = models.Person.objects.filter(name='ivy')

#get 获取一个满足条件的对象,查不到会报错 查到大于1个的结果也会报错
# ret = models.Person.objects.get(name='ivy')

#exclude 查询不满足条件的所有对象
ret = models.Person.objects.exclude(age=18)

#不填字段名values 获取对象的字段名和值 [{}] queryset
#填字段名 获取对象指定字段名和值
ret = models.Person.objects.all().values('pid','name')

#不填字段名values 获取对象的字段名和值 [()] queryset
#填字段名 获取对象指定字段名和值
ret = models.Person.objects.all().values_list('pid','name')

#排序 order_by [对象] queryset 默认升序  -j降序
ret = models.Person.objects.all().order_by('pid','-age')

#reverse 对已经排序的结果进行倒序
ret = models.Person.objects.all().order_by('pid').reverse()

#distince 不能针对字段名去重,除非两条数据完全一致
ret = models.Person.objects.values('age').distinct()

#查询结果的数据  是.all
ret = models.Person.objects.count()

#first 获取查询结果中的第一个对象
ret = models.Person.objects.first()

#last() 获取结果中的最后一个对象 没有就返回none
ret = models.Person.objects.last()

#查看是否存在
ret = models.Person.objects.filter(name='ivy').exists()
print(ret)

#返回是对象列表
all()
filter()
exclude()
values()
values_list()
order_by()
reverse()
distinct()

返回对象
get()
first()
last()

返回数字的
count

返回布尔值
exists()

 

知识点补充:类中打印对象的时候会调用__str__和__repr方法,如果没有str就调用repr

 

脚本的方式执行orm的操作

加载项目中所有环境
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day16.settings")
import django
django.setup()

 

3.单标双下划线

import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day16.settings")
import django
django.setup()

from app01 import models
#查询大于1
ret = models.Person.objects.filter(pid__gt=1)
#查询小于1
ret = models.Person.objects.filter(pid__gt=1)
#查询大于等于1
ret = models.Person.objects.filter(pid__gte=1)
#查询小于等于1
ret = models.Person.objects.filter(pid__lte=1)
#查询1或3
ret = models.Person.objects.filter(pid__in=[1,3])
#查询大于等于1 小于等于3
ret = models.Person.objects.filter(pid__range=[1,3])
#模糊查询不忽略
ret = models.Person.objects.filter(name__contains='ivy')
#忽略大小写
ret = models.Person.objects.filter(name__contains='ivy')
#以什么开头
ret = models.Person.objects.filter(name__startswith='ivy')
#以什么结尾
ret = models.Person.objects.filter(name__endswith='ivy')

#打印age字段为空的数据,False表示不为空的数据
ret = models.Person.objects.filter(age__isnull=True)

#打印年份是2019的数据
ret = models.Person.objects.filter(birth__year=2019)


ret = models.Person.objects.filter(birth__contains='2019-07')
print(ret)

 

4.外键的查询

正向查询
根据外键查piblisher

创建表的数据
class Publisher(models.Model):
    name = models.CharField(max_length=32)

    def __str__(self):
        return self.name

class Book(models.Model):
    name = models.CharField(max_length=32)
    pub = models.ForeignKey(Publisher,on_delete=models.CASCADE)

    def __str__(self):
        return self.name

查询语句
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day16.settings")
import django
django.setup()

from app01 import models
#基于对象的查询
book_obj = models.Book.objects.all()
print(book_obj.pub)
#反向查询
#关系型管理对象
#从少的那边查多的通过关系型管理对象 小写表名_set
pub_obj = models.Publisher.objects.first()
print(pub_obj.book_set.all())

 

#基于字段查询
#这里的__表示跨表
ret = models.Book.objects.filter(pub__name='沙河出版社1')
ret = models.Publisher.objects.filter(book__name="沙河小王子")
print(ret)
创建表是添加related_name 属性 查询的时候 表名_set 直接换成related_name定义的值
class Publisher(models.Model):
    name = models.CharField(max_length=32)

    def __str__(self):
        return self.name

class Book(models.Model):
    name = models.CharField(max_length=32)
    pub = models.ForeignKey(Publisher,on_delete=models.CASCADE,related_name="books")

    def __str__(self):
        return self.name

#反向查询
#关系型管理对象
pub_obj = models.Publisher.objects.first()
# print(pub_obj.books.all())

#基于字段查询
#这里的__表示跨表
ret = models.Publisher.objects.filter(books__name="沙河小王子")
print(ret)
创建表是指定related_query_name 查询的时候需要使用指定的这个值
class Publisher(models.Model):
    name = models.CharField(max_length=32)

    def __str__(self):
        return self.name

class Book(models.Model):
    name = models.CharField(max_length=32)
    pub = models.ForeignKey(Publisher,on_delete=models.CASCADE,related_name="books",related_query_name="xx")

    def __str__(self):
        return self.name

查询
ret = models.Publisher.objects.filter(xx__name="沙河小王子")
print(ret)

 

知识点补充:配置多数据库

直接添加对应的数据库连接信息
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'day16',
        'HOST':"127.0.0.1",
        "PORT":3306,
        "USER":'root',
        "PASSWORD":'wang',
    },
    'db2': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'day16',
        'HOST': "127.0.0.1",
        "PORT": 3306,
        "USER": 'root',
        "PASSWORD": 'wang',
    }
}

区分使用哪个表
ret = models.Person.objects.using('db2').filter(birth__contains='2019-07')
使用using('表名'
View Code

 

5.多对多的操作

创建book和author表多对多的关系

class Book(models.Model):
    name = models.CharField(max_length=32)
    pub = models.ForeignKey(Publisher,on_delete=models.CASCADE,related_name="books",related_query_name="xx")

    def __str__(self):
        return self.name

class Author(models.Model):
    name = models.CharField(max_length=32)
    books = models.ManyToManyField('Book')   #写上这个字段  django会自动创建第三张表来描述author和book之间的关系
#多对多查询
#查询某个作者出的书

import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day16.settings")
import django
django.setup()

from app01 import models
author_obj = models.Author.objects.first()
print(author_obj)
print(author_obj.name)
print(author_obj.books.all())

通过book查作者
book_obj = models.Book.objects.first()
print(book_obj.author_set.all())

通过字段查找
ret = models.Author.objects.filter(books__name="沙河小王子")
print(ret)

 

多对多常见方法
#set()设置多对多关系
#如果数据库有数据相当于重置
#设置1,2表示这两本书和作者的关系 可以写[id] [对象]
author_obj.books.set([1,2])
author_obj.books.set(models.Book.objects.filter(id__in=[1,3,5]))

#add()添加多对多的关系 [id] [对象]
author_obj.books.add(2)
#拿到的是一个queryset 需要用*号打散
author_obj.books.add(*models.Book.objects.filter(id=4))

#remove()删除 操作跟add一样
author_obj.books.remove(*models.Book.objects.filter(id=4))

#clear()删除所有多对多的关系
author_obj.books.clear()

#create 通过作者创建一本书,然后在把书和作者之间关联起来
author_obj.books.create(name="hongloumeng",pub_id=1)

知识点补充:外键也有以上这些方法 but 外键不能使用id  以及使用clear的使用外键关系那里必须设置null=True

 

6.聚合和分组

分组和聚合
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day16.settings")
import django
django.setup()

#聚合aggragate
from app01 import models from django.db.models import Max,Min,Sum,Avg,Count ret = models.Book.objects.all().aggregate(Sum('price')) ret = models.Book.objects.all().aggregate(sum=Sum('price')) #分组annotate #统计每一本书的作者个数 ret = models.Book.objects.annotate(Count('author')).values() #统计出每个出版社卖的最便宜的数的价格 #方法一 ret = models.Publisher.objects.annotate(Min('xx__price')).values() #方法二 annotate前的values中的字段就是条件分组 annotate后不再用values ret = models.Book.objects.values('pub__name').annotate(Min('price')) #统计不止一个作者的图书 models.Book.objects.annotate(count=Count('author')).filter(count__gt=1) #查询各个作者出的书的总价格 ret = models.Author.objects.annotate(Sum('books__price')).values() print(ret)

 

7. F、Q、事件

  Django 提供 F()对两个字段的值做比较 

import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day16.settings")
import django
django.setup()

from app01 import models
from django.db.models import F
ret =models.Book.objects.filter(sale__gt=F('store')).values()

#使用update来更新
obj = models.Book.objects.update(sale=F('sale')*2+13)

 

  filter() 等方法中的关键字参数查询都是一起进行“AND” 的。 如果你需要执行更复杂的查询(例如OR语句),你可以使用Q对象

与或非的使用需要导入Q

import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day16.settings")
import django
django.setup()

from app01 import models
from django.db.models import F,Q

# |表示并且的关系 & 与 ~ 非 默认逗号表示与
ret = models.Book.objects.filter(Q(id__gt=4)| Q(id__it=2))
print(ret)

知识点补充:事务操作

import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day16.settings")
import django
django.setup()

from app01 import models
from django.db import transaction
try:
    with transaction.atomic():
        #写具体的操作
        models.Publisher.objects.create(name='xxxx')

except Exception as e:
    print(e)

 

知识点补充django终端打印sql配置,在settings中加入以下配置

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console':{
            'level':'DEBUG',
            'class':'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level':'DEBUG',
        },
    }
}
View Code

 

二、cookie和session

  cookie是保存在浏览器上的一组组键值对,由服务器让浏览器进行设置,下次自动携带相应

的cookie去访问服务器

  cookie的工作原理是:由服务器产生内容,浏览器收到请求后保存在本地;当浏览器再次访问时,浏览器会自动带上Cookie,这样服务器就能通过Cookie的内容来判断这个是“谁”了。

 

参数:

  • key, 键
  • value='', 值
  • max_age=None, 超时时间
  • expires=None, 超时时间(IE requires expires, so set it if hasn't been already.)
  • path='/', Cookie生效的路径,/ 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问
  • domain=None, Cookie生效的域名
  • secure=False, https传输
  • httponly=False 只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)

 设置cookie方法一

from django.shortcuts import render,HttpResponse,redirect

# Create your views here.
def login(request):
    print(request.method)
    if request.method == "POST":

        username = request.POST.get("username")
        password = request.POST.get("password")
        if username == 'ivy' and password == '123':
            #登录成功设置cookie
            ret = redirect('/index/')
            ret.set_cookie('is_login','1')
            return ret
    return render(request,'login.html')

def index(request):
    is_login = request.COOKIES.get('is_login')
    if is_login != "1":
        return redirect('/login/')
    return HttpResponse("登录ok")
View Code

通过装饰器获取cookie完整版

from django.shortcuts import render,HttpResponse,redirect

# Create your views here.
def login_required(func):
    def inner(request,*args,**kwargs):
        is_login = request.COOKIES.get('is_login')
        if is_login != "1":
            return_url = request.path_info
            return redirect('/login/?return_url'.format(return_url))
        #登录成功
        ret = func(request,*args,**kwargs)
        return ret
    return inner

def login(request):
    print(request.method)
    if request.method == "POST":

        username = request.POST.get("username")
        password = request.POST.get("password")
        if username == 'ivy' and password == '123':
            #登录成功设置cookie
            return_url = request.GET.get('return_url')
            if return_url:
                ret = redirect(return_url)
            else:
                ret = redirect('/index/')
            ret.set_cookie('is_login','1')
            return ret
    return render(request,'login.html')

@login_required
def index(request):
    return HttpResponse("登录ok")
View Code

删除cookie

def logout(request):
    ret =  redirect('/login/')
    ret.delete_cookie('is_login')
    return ret
View Code

通过get_signed_cookie加盐设置cookie

from django.shortcuts import render,HttpResponse,redirect

# Create your views here.
def login_required(func):
    def inner(request,*args,**kwargs):
        # is_login = request.COOKIES.get('is_login')
        is_login = request.get_signed_cookie('islogin',default='',salt='s26')
        if is_login != "1":
            return_url = request.path_info
            return redirect('/login/?return_url'.format(return_url))
        #登录成功
        ret = func(request,*args,**kwargs)
        return ret
    return inner

def login(request):
    print(request.method)
    if request.method == "POST":

        username = request.POST.get("username")
        password = request.POST.get("password")
        if username == 'ivy' and password == '123':
            #登录成功设置cookie
            return_url = request.GET.get('return_url')
            if return_url:
                ret = redirect(return_url)
            else:
                ret = redirect('/index/')
            # ret.set_cookie('is_login','1')
            ret.set_signed_cookie('islogin','1','s26')
            return ret
    return render(request,'login.html')

@login_required
def index(request):
    return HttpResponse("登录ok")

def logout(request):
    ret =  redirect('/login/')
    ret.delete_cookie('is_login')
    return ret
View Code

get_signed_cookie方法的参数:

  • default: 默认值
  • salt: 加密盐
  • max_age: 后台控制过期时间

 

session

  保存在服务器上的一组组键值对,必须依赖cookie

  工作原理:浏览器第一次登陆的时候没有cookie 走到服务器登陆成功以后服务器会找一个地方存放cookie信息,然后生成一个唯一的表示区分是哪个用户的,再把标识发送给浏览器下次浏览器会带上标识去服务器,如果服务器有对应信息才能访问。

设置session

from django.shortcuts import render,HttpResponse,redirect

# Create your views here.
def login_required(func):
    def inner(request,*args,**kwargs):
        # is_login = request.COOKIES.get('is_login')
        # is_login = request.get_signed_cookie('islogin',default='',salt='s26')
        is_login = request.session.get('is_login')
        if is_login != "1":
            return_url = request.path_info
            return redirect('/login/?return_url'.format(return_url))
        #登录成功
        ret = func(request,*args,**kwargs)
        return ret
    return inner

def login(request):
    print(request.method)
    if request.method == "POST":

        username = request.POST.get("username")
        password = request.POST.get("password")
        if username == 'ivy' and password == '123':
            #登录成功设置cookie
            return_url = request.GET.get('return_url')
            if return_url:
                ret = redirect(return_url)
            else:
                ret = redirect('/index/')
            # ret.set_cookie('is_login','1')
            # ret.set_signed_cookie('islogin','1','s26')
            request.session['is_login'] = '1'
            return ret
    return render(request,'login.html')

@login_required
def index(request):
    return HttpResponse("登录ok")

def logout(request):
    ret =  redirect('/login/')
    # ret.delete_cookie('is_login')
    #方法一
    request.session.pop('is_login')
    #方法二
    request.session.delete() #删除整个session数据 不删除cookie
    #方法三
    request.session.flush()  #删除数据库里面保存的以及cookit
    return ret

from django.conf import global_settings
View Code

 

posted @ 2019-07-30 17:53  ivy_wang  阅读(244)  评论(0编辑  收藏  举报