Django知识补充

一、文件上传

1、三种方式

  • 通过form表单提交实现基本上传

  • 通过From类上传

  • ajax上传

from django.shortcuts import render,HttpResponse
from django import forms
from django.forms import fields


class UploadForm(forms.Form):
    user = fields.CharField()
    img = fields.FileField()

def upload(request):
    '''上传文件'''
    if request.method == 'GET':
        return render(request,'upload.html')
    else:
        '''
        # 基于Form也可以上传,这里还做了验证
        obj = UploadForm(request.POST,request.FILES)
        if obj.is_valid():
            user = obj.cleaned_data['user']
            img = obj.cleaned_data['img']
        '''
        #img是对象,封装了文件大小、名称、内容。。。
        img = request.FILES.get('img')
        print(img.name)
        print(img.size)
        #将上传文件写入本地
        f = open(img.name,'wb')
        #上传是一点一点的,所以不能一下子拿到全部,需要循环
        for line in img.chunks():
            f.write(line)
        f.close()
        return HttpResponse('上传成功')

二、Models补充

1、字段

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

2、字段参数

 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中是否可以编辑,直接隐藏了,form中是变灰色
    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'), ]
                            )

实例:

from django.db import models

class UserInfo(models.Model):
    username = models.CharField(
        null=True,  #可以为空
        db_column='user',   #表中显示的列名
        max_length=32,  #字符串字段必须有最大长度
        db_index=True,  #建立索引,只能加速查找
        unique=True,    #加速查找,限制列值唯一
        #primary_key=True,   #加速查找,限制列值唯一,不能为空
    )
    #生成下拉框
    user_type = models.IntegerField(
        choices = [
        (1,'普通用户'),
        (2,'超级用户'),
        (3,'VIP用户'),
        ]
    )
    part = models.ForeignKey(
        to = 'Part',
        to_field = 'id',
        on_delete = models.CASCADE,
        # related_name='part',
        limit_choices_to={'id__gt':1} #只显示ID大于1的
    )
    def __str__(self):
        return self.username

class Part(models.Model):
    caption = models.CharField(max_length=32)
    def __str__(self):
        return self.caption

3、多表关系以及参数

ForeignKey(ForeignObject) # ForeignObject(RelatedField)
        to,                         # 要进行关联的表名
        to_field=None,              # 要关联的表中的字段名称
        on_delete=None,             # 当删除关联表中的数据时,当前表与其关联的行的行为
                                        - 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(可执行对象)

                                                        def func():
                                                            return 10

                                                        class MyModel(models.Model):
                                                            user = models.ForeignKey(
                                                                to="User",
                                                                to_field="id"
                                                                on_delete=models.SET(func),)
        related_name=None,          # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()
        related_query_name=None,    # 反向操作时,使用的连接前缀,用于替换【表名】     如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
        limit_choices_to=None,      # 在Admin或ModelForm中显示关联数据时,提供的条件:
                                    # 如:
                                            - limit_choices_to={'nid__gt': 5}
                                            - limit_choices_to=lambda : {'nid__gt': 5}

                                            from django.db.models import Q
                                            - limit_choices_to=Q(nid__gt=10)
                                            - limit_choices_to=Q(nid=8) | Q(nid__gt=10)
                                            - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
        db_constraint=True          # 是否在数据库中创建外键约束
        parent_link=False           # 在Admin中是否显示关联数据


    OneToOneField(ForeignKey)
        to,                         # 要进行关联的表名
        to_field=None               # 要关联的表中的字段名称
        on_delete=None,             # 当删除关联表中的数据时,当前表与其关联的行的行为

                                    ###### 对于一对一 ######
                                    # 1. 一对一其实就是 一对多 + 唯一索引
                                    # 2.当两个类之间有继承关系时,默认会创建一个一对一字段
                                    # 如下会在A表中额外增加一个c_ptr_id列且唯一:
                                            class C(models.Model):
                                                nid = models.AutoField(primary_key=True)
                                                part = models.CharField(max_length=12)

                                            class A(C):
                                                id = models.AutoField(primary_key=True)
                                                code = models.CharField(max_length=1)

    ManyToManyField(RelatedField)
        to,                         # 要进行关联的表名
        related_name=None,          # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()
        related_query_name=None,    # 反向操作时,使用的连接前缀,用于替换【表名】     如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
        limit_choices_to=None,      # 在Admin或ModelForm中显示关联数据时,提供的条件:
                                    # 如:
                                            - limit_choices_to={'nid__gt': 5}
                                            - limit_choices_to=lambda : {'nid__gt': 5}

                                            from django.db.models import Q
                                            - limit_choices_to=Q(nid__gt=10)
                                            - limit_choices_to=Q(nid=8) | Q(nid__gt=10)
                                            - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
        symmetrical=None,           # 仅用于多对多自关联时,symmetrical用于指定内部是否创建反向操作的字段
                                    # 做如下操作时,不同的symmetrical会有不同的可选字段
                                        models.BB.objects.filter(...)

                                        # 可选字段有:code, id, m1
                                            class BB(models.Model):

                                            code = models.CharField(max_length=12)
                                            m1 = models.ManyToManyField('self',symmetrical=True)

                                        # 可选字段有: bb, code, id, m1
                                            class BB(models.Model):

                                            code = models.CharField(max_length=12)
                                            m1 = models.ManyToManyField('self',symmetrical=False)

        through=None,               # 自定义第三张表时,使用字段用于指定关系表
        through_fields=None,        # 自定义第三张表时,使用字段用于指定关系表中那些字段做多对多关系表
                                        from django.db import models

                                        class Person(models.Model):
                                            name = models.CharField(max_length=50)

                                        class Group(models.Model):
                                            name = models.CharField(max_length=128)
                                            members = models.ManyToManyField(
                                                Person,
                                                through='Membership',
                                                through_fields=('group', 'person'),
                                            )

                                        class Membership(models.Model):
                                            group = models.ForeignKey(Group, on_delete=models.CASCADE)
                                            person = models.ForeignKey(Person, on_delete=models.CASCADE)
                                            inviter = models.ForeignKey(
                                                Person,
                                                on_delete=models.CASCADE,
                                                related_name="membership_invites",
                                            )
                                            invite_reason = models.CharField(max_length=64)
        db_constraint=True,         # 是否在数据库中创建外键约束
        db_table=None,              # 默认创建第三张表时,数据库中表的名称

三、Django总结

1、Django的一个请求周期(请求和相应HTTP),请求和相应都是以字符串的形式
    -- a、发送HTTP请求;
    -- b、服务器接收,根据请求头中的URL在路由关系表中进行匹配(从上到下);
    -- c、匹配成功后,执行指定的views函数;
        写视图函数的两种方式:FBV  CBV
        URL--》对应一个函数--》这种模式叫FBV
            url(r'login/', views.login)
            def login(request)
        URL--》对应一个类--》这种模式叫CBV
        以POST方式发送请求,执行post方法,以GET方式发送请求,执行get方法;
        View类中有一个方法dispatch来根据请求方式判断执行什么方法,我们可以自定义这个方法
        http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
            from django.view import View
            class Cbv(View):
                def dispatch(self, request, *args, **kwargs):
                    print('dispatch....')
                    ret = super(Cbv,self).dispatch(self.request,*args,**kwargs)
                    return ret
                def get(self,request):
                    return render(request,'cbv.html')
                def post(self,request):
                    return HttpResponse('cbv.post')
            urls.py:
                url(r'cbv/', views.CBV.as_view())
            cbv.html:
                <body>
                    <form action="/cbv/" method="POST">
                        <input type="text"/>
                        <input type="submit"/>
                    </form>
                </body>
    -- d、业务处理
        -- 可以根据个人需求自定制
        -- 操作数据库
            - 原生SQL语句
            - Django ORM
        ==最后得到返回给用户的结果==
        -- 响应内容
            - 响应头
            - 响应体
            响应头没有内容,我们可以主动给它返回内容
            def post(self,request):
                ret = HttpResponse('cbv.post')
                ret['k1'] = 'v1'
                ret.set_cookie('k2','v2')
                '''
                头:k1=v1
                    cookies:k2=v2
                体:cbv.post
                '''
                return ret
2、创建Django项目的基本流程
    -- 创建新项目
    -- 创建APP
    -- 创建static文件夹,settings配置静态文件路径
    -- 注册APP   INSTALLED_APPS
    -- 创建templates文件夹,settings配置模板文件路径
        'DIRS': [os.path.join(BASE_DIR,'templates')],
3、ORM 多对多操作
    #多对多添加,书籍类中有authors = models.ManyToManyField('Author')
    #增
    book_obj = Book.objects.get(id=4)
    book_obj.authors.add(1)
    book_obj.authors.add(*[1,2,])
    #删
    book_obj = Book.objects.get(id=4)
    book_obj.authors.remove(1)
    book_obj.authors.remove([1,2,])
    book_obj.authors.clear()
    #重置,以设置的为准,已经有的不动,新内容里没有的就删除
    book_obj.authors.set([1,2,3])
    #查
    #所有书籍名称和对应的作者名
    book_list = Book.objects.all().values('name','authors__name')
    #列举ID=1的书籍的所有作者
    #方式一
    book_obj = Book.objects.get(id=1)
    aut_obj = book_obj.authors.all()
    #方式二
    Book.objects.filter(id=1).values('authors__name')
    #列举作者charlie的所有书籍
    Book.objects.filter(authors__name="charlie")

4、跨多张表查询
    class Book(models.Model):
        '''书籍'''
        name = models.CharField(max_length=20)
        price = models.IntegerField()
        pub_data = models.DateField()
        authors = models.ForeignKey('Author',on_delete=models.CASCADE)
    class Author(models.Model):
        '''作者'''
        name = models.CharField(max_length=20)
        age = models.IntegerField(default=20)
        country = models.ForeignKey('Country',on_delete=models.CASCADE)
    class Country(models.Model):
        '''国家'''
        name = models.CharField(max_length=20)
    #所有中国籍作者出的所有书籍
    Book.objects.filter(authors__country__name='China')
    #正向查找:Book.objects.filter(authors__name='charlie')
    #反向查找:
        obj = Authors.objects.filter(name='charlie').first()
        obj.book_set.all()
    #没有外键的表里其实隐藏了一个字段:类名_set,也可以修改这个字段名
    class Book(models.Model):
        authors = models.ForeignKey('Author',on_delete=models.CASCADE,related_name='book')
    obj = Authors.objects.filter(name='charlie').first()
    book_list = obj.book.all()#作者对应的所有书籍对象查询集[obj(name,price,..),obj(name,price,..),]

5、QuerySet内部有三种数据类型:
    -- 字典:values()得到,用['name']取值
    -- 元组:value_list得到
    -- 对象:all\filter得到,用点取值

6、-- 类代表数据库表
   -- 类的对象代指数据库的一行记录
   -- ForeignKey字段代指关联表中的一行数据(关联类的对象)
   -- 正向:fk字段
   -- 反向:小写类名_set(默认),自定义ForeignKey(related_name='book')
        一般不做反向查找,进行两次SQL操作,效率低;

7、一对多:这两种操作相当于left join 连表操作,以查询的表为主表,会显示所有主表内容
    Students.objects.all().values('name','classes__name')
    显示所有的学生信息,没有学生的班级不显示
    Classes.objects.all().values('name','students_set__name')
    显示所有的班级信息,没有学生的班级显示None

8、select 标签
    - 单选
        $().val()
        $().val(2)
    - 多选
        $().val([1,2,3])

9、静态文件夹模板
    - js(js文件)
    - css(css文件)
    - plugins(bootstrap,font-awesome等插件)

10、JavaScript中把
    对象转换成字符串 -- str = JSON.stringify({'k':'v'})
    字符串转换成对象 -- dict = JSON.parse(str)

    $.ajax({
        url:'/del_student/',
        type:'GET',
        data:{nid:rowId},
        datatype:'JSON',//ajax内部会自动转换
        success:function (arg) {
            //arg已经是对象了
        }
    })
11、jQuery事件委托
        -- .on和.delegate()效果一样,不过delegate前两个参数要调换位置
        $('要绑定标签的上级标签').on('click','要绑定的标签',function(){})
12、总结
    新URL方式(点击跳转到新的页面):
        -- 独立的页面
        -- 数据量大或条目多时,使用这个方便
    对话框方式(ajax偷偷发送):
        -- 数据量小或条目少时使用
        -- 此时添加数据,需要考虑当前页、td中的自定义属性
        -- 数据量大时,工作量很大

    如果不是强制要求使用对话框方式,建议使用新URL方式;
    如果是删除操作,建议用ajax方式;

13、ajax发送checkbox数据,就是列表,
    var values = [1,2,3,4]
    $.ajax({
        url:'/edit_student/',
        type:'POST',
        data:{'k':values},
        traditional:true,
        success:function (arg){}
    })
	error:function(){}//出错自动触发
    views函数获取数据方式:
        v = request.POST.getlist('k')

    注意:data字典里不能嵌套字典直接发送过去,如果非要发送需要JSON转换一下

14、使用serialize就可以获取整个form表单里的所有数据,也是字典格式
    $.ajax({
        data:$('#fm').serialize(),
    })

15、XSS攻击:跨站脚本攻击,其实就是用户写了一段js代码,让其他人访问时执行这个脚本;
	如果有人在博客下面评论输入一下代码,会直接影响其他用户浏览这篇博客,
	大家都陷入一个死循环
	<script>
	for(var i=0;i<9999;i++){
		alert(i);
	}
	</script>
	攻击方式二:
	<script>
	    获取本地cookie,发送到另外一个网站或程序
	</script>
16、null=True,数据库表中是否可以为空
blank=True,用户输入是否可以为空

 

猜你喜欢

转载自www.cnblogs.com/charliedaifu/p/10215925.html