Django-查漏补缺(一)

本文主要为自己复习Django框架时所做的笔记,为个人迅速查询和复习所用

一. URL模块

1. 自定义PATH转换器

  • 定义:自定义reverse反转和传入视图中的转换效果
  • 步骤:
  1. from django.url.import register_converter

  2. 自定义转换类

    class MyConverter(object):
    	regex = r'正则表达式'
    	def to_python(self,value):#传递给视图时的格式
    		pass
    	def to_url(self,python):#reverse反转时的效果
    		pass
    
  3. 注册

    register_converter(MyConverter,'自定义的用于url中的标识符,如int')
    

二. 模板模块

1. verbatim标签使用详解

  • 定义:默认在DTL模板中是会去解析特殊字符的,比如{% %}以及{{ }}等,如果在某个代码片段中不想使用DTL的的解析引擎,那么可以使用verbatim标签关闭自动解析
  • 用法:
{% verbatim %}
	{{ if dying }}
		still alive
	{{endif}}
{% endverbatim %}

2. localtime标签

  • 将时间转换为设置好的时区时间
  • 注意导入{% load tz %}
  • 模板中可以省略该标签,Django会自动将时间渲染为时区时间

三. 数据库模块

1. Django使用原生SQL原句操作数据库

from django.db import connection  #connection会自动连接settings.py中设定好的数据库
def index(request):
    name = connection.cursor()
    name.execute('原生SQL语句')
    exclusion = cursor.fetchall()  #返回刚才语句查找到的所有结果
    #exclusion = cursor.fetchone()  返回刚才语句查找到的最新结果

2. 模型名限制

  • 字段名不能是Python保留字,因为这会导致Python语法错误。 比如:

    class Example(models.Model):
        pass = models.IntegerField()
    
  • 由于Django的查询查询语法的工作方式,字段名在一行中不能包含多个下划线。例如:

    class Example(models.Model):
        foo__bar = models.IntegerField()
    

3. 模型常用字段

  • BigAutoField:64位整型,存储有更大的数据范围。

  • BigIntergerField:更大的整数范围

  • NullBooleanField:可以使用null的布尔型。

  • BinaryField:存储原始二进制数据的字段,默认editableFalse

  • DateField:日期字段,类型为datetime.date ,以下为一些重要参数

    • auto_now:每次保存对象时自动将字段设置为now,多用于最后更新时间
    • auto_now_add:保存首次存储时间,多用于创建时间。注意此字段和defaultauto_now是互斥的,并且会影响blankeditable
  • DateTimeField:日期字段,类型为datetime.datetime,其他与DateField相同

  • TimeField:日期字段,类型为datetime.time,其他与DateField相同

  • DecimalField:固定精度的十进制字段,有两个必须的参数

    • max_digits:允许的最大位数,必须大于decimal_places
    • decimal_places:允许的小数位数
  • DurationField:用于存储时间周期的字段,不建议使用

  • FieldField:文件上传字段,注意无论何时都应对上传文件和类型进行验证以防止恶意攻击

    • upload_to:上传路径,支持时间格式/%Y/%m/%d/,也可以接收一个可调用函数
  • imageField:从FileField继承所有属性和方法,但会验证上传的对象是否是有效的图像,有两个额外的参数:

    • height_field: 每次保存模型实例时自动填充图像的高度。
    • width_field: 同上,但填充的是宽度
  • FilePathField:保存文件系统上某个目录中的文件的完整路径

    • path:必须参数,指定文件的绝对路径

      import os
      from django.conf import settings
      from django.db import models
      
      def images_path():
          return os.path.join(settings.LOCAL_FILE_DIR, 'images')
      
      class MyModel(models.Model):
          file = models.FilePathField(path=images_path)
      
    • match:使用正则表达式进行过滤,注意过滤的是最终的文件名而不是获得的路径

    • 其他参数

  • GenericIPAddressField:保存IPV4或IPV6地址

    • protocol:限制协议,IPV4IPV6both
    • unpack_ipv4:将ipv6解压缩到IPv4映射地址
  • slugField通常用于URL中的字段类型

  • SmallAutoField:限制值范围为1~32767

  • URLField:继承自CharField,但会通过URLValidator验证器进行验证

  • UUIDField:用于存储通用唯一标识符的字段。使用Python的UUID类

  • TextChoices:以枚举类的形式创建选择字段

    class Runner(models.Model):
        MedalType = models.TextChoices('MedalType', 'GOLD SILVER BRONZE')
        name = models.CharField(max_length=60)
        medal = models.CharField(blank=True, choices=MedalType.choices, max_length=10)
    
  • 模型字段属性:

    • related_name:用于从相关对象返回到此对象的关系的名称 ,如果需要禁止掉反向查询则可以将related_name设置为'+'或以‘+’结尾

      class Buyer(models.Model):
          name = models.CharField(verbose_name='买主名', max_length=10) 
          age = models.IntegerField(verbose_name='年龄',blank = True)
          
      class Fruit(models.Model): 
          buyer = models.ForeignKey(Buyer, related_name='buyer_fruit') 
          
      #正常查询
      buyer = Buyer.objects.filter(age = 100).first()
      fruits = buyer.fruit_set.all()
      
      #使用`related_name`
      buyer = Buyer.objects.filter(age = 100).first()
      fruits = buyer.buyer_fruit.all() 
      
    • related_query_name ,要用于目标模型的反向筛选器名称的名称,默认值为related_name的值

      class Tag(models.Model):
          article = models.ForeignKey(
              Article,
              on_delete=models.CASCADE,
              related_name="tags",
              related_query_name="tag",
          )
          name = models.CharField(max_length=255)
      
      #查询
      Article.objects.filter(tag__name="important")
      
    • get_choicesname_display():查询choices字段属性的展示

      class Person(models.Model):
          SHIRT_SIZES = (
              ('S', 'Small'),
              ('M', 'Medium'),
              ('L', 'Large'),
          )
          name = models.CharField(max_length=60)
          shirt_size = models.CharField(max_length=1, choices=SHIRT_SIZES)
      
      >>> p = Person(name="Fred Flintstone", shirt_size="L")
      >>> p.save()
      >>> p.shirt_size
      'L'
      >>> p.get_shirt_size_display()
      'Large'
      
    • help_text:与表单小部件一起显示的额外“帮助”文本。它对于文档非常有用,即使表单上没有使用字段。

    • db_column:设置列的名称,默认直接使用字段名

    • db_index:如果为真,将为此字段创建一个数据库索引

    • db_tablespace:如果该字段被索引,则为该字段的索引设置使用的数据库表空间的名称。 默认设置是项目settings中DEFAULT_INDEX_TABLESPACE值(若有),或者是模型设置的的db_tablespace(若有)。

    • default:设置默认值,注意可以是一个值或者是个可调用的对象,但不能是可变对象也不能是lambad函数。如果是个可调用对象,每次实例化模型时都会调用该对象

      def contact_default():
          return {"email": "to1@example.com"}
      
      contact_info = JSONField("ContactInfo", default=contact_default)
      
    • editable:默认为True,为False则该字段不会显示在admin或任何其他ModelForm

    • unique_for_date:设置了此属性的字段对于 DateField or DateTimeField类型的要求将是唯一的,比如

      title = model.CharField(unuque_for_date="pub_date")
      pub_date = DateTimeField('发表时间')
      

      这意味着将不允许输入具有相同titlepub_date的两条记录

    • unique_for_month:对月份进行限制

    • unique_for_year:对年份进行限制

    • validators:验证器

4. 模型查询条件

  • exact:精确查找

    article = Article.object.get(id__exact=1)
    
  • iexact:相当于原生SQL中的like

  • contains:包含,大小写敏感,相当于SQL中的like binary

    article = Article.object.filter(title__contains='hello')
    
  • icontains:包含,大小写不敏感

  • in:提取那些位于给定容器中(list、tuple、可迭代对象、QuerySet)的数据

    article = Article.object.get(id__in=[1,2,3])
    

    相当于

    select ... where id in (1,2,3)
    

    也可以执行跨表查询

    category = Categories.object.filter(article__id__in=[1,2,3])
    
  • startwith:判断是否以某个字段开始

    article.object.filter(title__(i)startwith='hello')
    
  • endwith:判断结尾

  • range:判断值是否处于给定的区间中

    start_date = datetime(year=2018)
    end_date = datetime(year=2019)
    article = Article.object.filter(created_time__range=(start_date.end_date))
    
  • isnull:判断是否为null

    article.object.filter(tag__isnull=True)
    
  • regex和iregex:正则表达式

    article.object.filter(title__REGEX=r'\d+')
    

5. 聚合函数

  • 使用前注意:聚合函数不能单独执行,需要放在一些支持聚合函数的方法下执行,比如aggregateannotate,而aggregateannotate可以在所有的QuerySet下使用,如objectsfilter

  • aggregate():返回单一字段;annotate():分组获得,相当于SQL中的group by

  • 平均Avg():

    from django.db.model import Avg
    
    result = Book.object.aggregate(price_avg=Avg('price'))
    
  • 计量Count():

    result = Book.object.aggregate(book_nums=Count('id')) #包含重复
    result = Book.object.aggregate(book_nums=Count('id',distinct=True))
    
  • 极值Max()和Min():

    result1 = Author.object.aggregate(max=Max('age'),min=Min('age'))
    
  • 总和Sum():

    result = Book.object.aggregate(totla=Sum('price')) #包含重复
    

6. QuerySet API

  • values:用来指定在提取数据时的字段(不指定时会将所以字段都提取出来),使用values方法后提取出的将不是模型而是在values方法中指定的字段和值形成的字典

    articles = Article.object.values('title','content')
    for article in articles:
        print(article)
    
    #查询出的结果将是以下形式
    {'title':'abc','content':'cba'}
    

    复杂用法:

    books = Book.object.values('id','name',author=F('author__name')) #使用F进行动态查询,给查询字段改名
    books = Book.object.values('id','name',order_nums=Count('bookorder')) #使用聚合函数添加新字段
    
  • values_list:与values用法相同,但返回的是元组而不是字典

  • defer:过滤掉不需要的字段,返回QuerySet模型

    books = Books.object.defer('name') #注意过滤掉后就尽量不要使用该字段了,否则查询性能下降
    
  • only:和defer效果相反,注意使用了only都还是会提取出ID字段

  • create、get_or_create、update、delete

  • bulk_create:一次性创建多个数据

    Tag.object.bult_create(
        [
            Tag(name='111'),
            Tag(name='222'),
        ])
    
  • exists:判断某个查询数据是否存在

  • distinct:去掉重复查询数据

    orders = Bookorder.objects.values('book_id').distinct()
    books = Book.object.filter(bookorder_price_gte=80).distinct()
    
  • QuerySet对象并不会马上转化为SQL去执行,只有在遇到遍历QuerySet对象、提供参数的切片、调用len方法、调用list方法、对其进行判断时会马上转为SQL语句进行执行

7. 自定义模型管理器object

模型最重要的属性是管理者。它是向Django模型提供数据库查询操作的接口,用于从数据库检索实例。如果没有定义自定义管理器,则默认名称为object。管理器只能通过模型类访问,而不能通过模型实例访问。

  • 自定义管理器Manager

    在语句Book.objects.all()中,objects是一个特殊的属性,通过它来查询数据库,它就是模型的一个Manager. 每个Django模型至少有一个manager,你可以创建自定义manager以定制数据库的访问. 这里有两个方法创建自定义manager:添加额外的manager;修改manager返回的初始Queryset.

    • 添加额外的Manager:增加额外的manager是为模块添加表级功能的首选办法.(至于行级功能,也就是只作用于模型实例对象的函数,则通过自定义模型方法实现). 例如,为Book模型添加一个title_count()manger方法,它接收一个keyword,并返回标题中包含keyword的书的数量.

      from django.db import models
      
      #自定义模型管理类
      class BookManager(models.Manager):
          #自定义模型管理器中的方法
          def title_count(self,kewword):
              return self.frlter(title_icountains=keyword).count()
          
      #模型
      class Book(model.Model):
          title = model.CharField(max_length=100)
          author = mode.ManaToManyFuekd(Author)
          #添加新的管理器
          objects = BookManager()
          
          def __str__(self):
              return self.title
      

      使用:

      Book.objects.title_count('us') #自定义的封装方法
      Book.objects.filter(title_icontains='us').count() #默认的查询方法依然可使用
      

      通过通过封装一些常用的查询语句到管理器中就可以不必写过多重复代码

    • 修改初始Manager Quertset:manager的基础Queryset返回系统中的所有对象.例如,Book.objects.all()返回book数据库中的所有书籍.你而已通过覆盖Manager.get_queryset()方法来重写manager的基础Queryset.get_queryset()应该按照你的需求返回一个Queryset.

      from django.db import models
      
      #定义一个Manager的字类
      class changeBookeManager(models.Manager):
          def get_queryset(self):
              return super(changeBookManager,self).get_querrset().filter(author='username')
          
      #模型
      class Booke(models.Model):
          title = model.CharField(max_length=100)
          author = mode.ManaToManyFuekd(Author)
          objects = models.Manager() #默认管理器
          change_objects = changeBookManager() #自定义管理器
      

      使用

      Book.objects.all() #返回所有书
      Book.change_objects.all() #返回满足作者要求的书
      Book.change_objects.filter(title='us').first() #可以继续使用Queryset方法
      

      也可以直接

      objects = changeBookManager()
      

      此时默认管理器将被覆盖,唯一可用的管理器为changeBookManager,但应尽量避免这种情况;另外Django将会把第一个Manager 定义为默认Manager

8. 修改模型方法

8.1 自定义模型方法:

  • 当自带的方法无法满足需求时,可以自定义一个模型方法.与Manager不同的是模型方法只对模型实例起作用

    from django.db import models
    
    class Person(models.Model):
        username = models.CharField(max_length=50)
        age = models.IntergerField()
        
        def get_birth_date(self):
            return '{0}'+'的年龄是:'+'{1}'.formate(self.username,self.age)
    

    调用

    >>>p = Person.object.get(username='张三')
    >>>p.get_birth_date()
    '张三的年龄是:18'
    

8.2 重写预定义的模型方法

  • 还有一组模型方法了封装了一些你可能想要自定义的数据库行为.特别是你可能想要修改save()delete()的工作方式.你可以自由的重写这些方法(以及其他的模型方法)来改变行为

  • 重写save方法:可以自定义在保存对象的同时的行为

    from django.db import models
    
    class Blog(models.Model):
        name = models.CharField(max_length=100)
        tagline = models.TextField()
    
        def save(self, *args, **kwargs):
            #在模型保存前需要做的事
            super(Blog, self).save(*args, **kwargs)    #Call the "real" save() method.
            #在模型保存后需要做的事
    

    或者对保存做一些限制:

    from django.db import models
    
    class Blog(models.Model):
        name = models.CharField(max_length=100)
        tagline = models.TextField()
    
        def save(self, *args, **kwargs):
            if self.name == 'zhangsan':
                return    #不保存到数据库
            else:
                super(Blog, self).save(*args, **kwargs)    #C正常保存
    
  • 重写clean方法:提供自定义的模型验证,以及修改模型的属性 。例如,你可以使用它来给一个字段自动提供值,或者用于多个字段需要一起验证的情形:

    import detetime
    from django.core.exceptions import ValidationError
    from django.db import models
    
    class Article(models.Model):
        ...
        def clean(self):
            #验证字段
            if self.status == 'draft' and self.pub_date is not done:
                raise ValidationEroor('验证错误')
            #设置默认值
            if self.status == 'published' and self.pub_date is None:
                self.pub_date = datetime.date.today()
    

9. 已有表生成模型

  • 第一步:inspectdb:直接将settings中配置好的数据库转化为模型并显示在终端

    python3 manage.py inspectdb #显示在终端并不保存
    
    python3 manage.py inspectdb > models.py #直接保存在模型文件中
    
  • 第二步:修改模型:将模型名、模型外键引用、模型所属app修改为自己所需的,切记不要修改表名;将Meta下的managed-False删掉,如果保留这个,那么以后这个模型的改动使用migrate都不会映射到数据库中;如果表中有多对多字段,应该将中间表模型注释掉,然后使用ManyToManyField来实现多对多,若使用ManytoManyField生成的中间表与数据库中已存在的中间表不一致,那么可以使用db_table指定表的名字(也可以更改数据库中的名字使其一致)

    tags = models.ManyToMany('Tag',db_table='article_tag',null=True,blank=True)
    
  • 第三步:执行命令

    python manage.py makemigrations
    python manage.py migrate --fake-initial #不使用fake-initial将会创建一个新映射(表)到数据库中
    

10. 模型继承

抽象基类

  • 当只需父类保存一些共有数据时而不是真正生成模型时,使用抽象基类

    class CommonInfo(models.Model):
        name = models.CharField(max_length=100)
        age = models.PositiveIntegerField()
    
        class Meta:
            abstract = True
    
    class Student(CommonInfo):
        home_group = models.CharField(max_length=5)
        #若有不需要字段的可以使用另一个值覆盖或直接使用None
    

    注意:使用抽象基类时尽量不要跨应用导入,否则会引起查询问题,具体描述及解决方法Meta inheritance

多表继承

  • 如果需要子类化一个现有模型(可能完全来自另一个应用),并且希望每个模型都有自己的数据库表,那么可以采用多表继承,继承关系在子模型和它的每一个父模型之间引入了链接(通过一个自动创建的一对一字段)

    class Place(models.Model):
        name = models.CharField(max_length=50)
        address = models.CharField(max_length=80)
    
    class Restaurant(Place):
        serves_hot_dogs = models.BooleanField(default=False)
        serves_pizza = models.BooleanField(default=False)
    

    place中的所有字段都能在restaurant中使用

    >>> Place.objects.filter(name="Bob's Cafe")
    >>> Restaurant.objects.filter(name="Bob's Cafe")
    

    如果一个place同时也是restaurant(在上例中即表现为没有改变nameaddress的值),那么还可以直接通过前者的对象获取后者,若不是则会引发DoesNotExist exception

    >>> p = Place.objects.get(id=12)
    # If p is a Restaurant object, this will give the child class:
    >>> p.restaurant#小写
    <Restaurant: ...>
    

    注意:

    • 字类也会继承父类的Meta,若不需要父类的值则可更改其为其他值或空值

    • 因为多表继承隐藏了一个一对一关系,所以若父类的子类还使用了一个外键链接到父类则可能会引起查询错误,所以应该使用related_name属性

      class Supplier(Place):
          customers = models.ManyToManyField(Place,related_name='provider')
      
    • 手动创建一对一父子类继承关系应使用parent_link=True属性

代理模型

  • 代理模型:为原始模型创建代理,您可以创建、删除和更新代理模型的实例,所有数据都将被保存与原始模型的表上,就像在使用原始模型一样。不同之处在于,您可以更改诸如代理中的默认模型排序或默认管理器之类的内容或增加模型方法等,而不需要更改原始模型中的内容。

    class Person(models.Model):
        first_name = models.CharField(max_length=30)
        last_name = models.CharField(max_length=30)
    
    class MyPerson(Person):
        class Meta:
            proxy = True
    
        def do_something(self):
            # ...
            pass
    

    两个模型的可以互相操作

    >>> p = Person.objects.create(first_name="foobar")
    >>> MyPerson.objects.get(first_name="foobar")
    <MyPerson: foobar>
    

    注意:

    • 论何时查询Person对象,都不可能让Django返回一个MyPerson对象,反之亦然。
    • 代理模型必须从一个非抽象模型类继承,不能从多个非抽象模型继承,因为代理模型不提供不同数据库表中的行之间的任何连接。代理模型可以继承任意数量的抽象模型类,前提是它们不定义任何模型字段。代理模型还可以继承任意数量的拥有公共非抽象父类的代理模型。

多重继承

  • 多重继承:继承多个模型

    class Article(models.Model):
        article_id = models.AutoField(primary_key=True)
        ...
    
    class Book(models.Model):
        book_id = models.AutoField(primary_key=True)
        ...
    
    class BookReview(Book, Article):
        pass
    

    注意:

    • 第一个出现的Meta将会是整个模型的Meta

    • 从具有公共id主键字段的多个模型继承会引发错误。要正确地使用多重继承,尽量在基本模型中定义一个显式的AutoField,当然也可以定义一个公共父类来保存主键,在从每个基本模型使用一对一关系链接到公共父类

      class Piece(models.Model):
          pass
      
      class Article(Piece):
          article_piece = models.OneToOneField(Piece, on_delete=models.CASCADE, parent_link=True)
          ...
      
      class Book(Piece):
          book_piece = models.OneToOneField(Piece, on_delete=models.CASCADE, parent_link=True)
          ...
      
      class BookReview(Book, Article):
          pass
      

11. 集中管理models文件

  • 如果您拥有多个app且每个app中都自带一个模型文件model.py,将它们集中起来管理是个不错的选择

    • 在某个app包下或集中管理app的文件包下创建一个model包,将所有的model.py文件都移动进去

    • __init__中进行注册

      #myapp/models/__init__.py
      from .organic import Person
      from .synthetic import Robot
      

      注意,为了代码可读性和代码分析攻击的正常使用尽量不要使用from .models import * 进行导入

三. 视图模块

1. Django限制请求method

  • from django.http.decorators.http import require_http_method
    @require_http_methods(['GET']) #接受一个方法列表
    def fun(request):
    
  • from django.views.decorators.http import require_GET
    @require_GET #接受GET方法
    def fun(request):
    
  • from django.views.decorators.http import require_POST
    @require_POST #接受POST方法
    def fun(request):
    
  • from django.views.decorators.http import require_safe
    @require_safe #只接受安全请求方法方法,如GET、HEAD
    def fun(request):
    

2. WSGIRequest对象

常用属性:

  • path:请求服务器的完整“路径”

  • method:当前请求的http方法

  • GET:包含了所有使用GET方法请求的信息

  • POST:包含了所有POST方法上传的信息

  • FILES:包含了所有上传的文件

  • COOKIES:包含所有的cookies信息,键值对形式

  • session:包含所有的session的信息

  • META:存储客户端发送上来的所有header信息

    • REMONT_ADDR:客户端的IP地址,如果服务器使用了nginx做反向代理或负载均衡,那么这个值永远都为127.0.0.1 ,这时候可以使用HTTP_X_FORWARDED_FOR来获取

      if request.META.has_key('HTTP_X_FORWARDED_FOR'):
          ip = request.META('HTTP_X_FORWARDED_FOR')
      else:
          ip = request.META('REMONT_ADDR')
      

常用方法:

  • request.get_full_path():请求的url,带查询参数,如:www.baidu.com/?print=True
  • request.get_raw_uri():请求的完整url,如:https://www.baidu.com/?print=True
  • request.get_host():返回服务器的域名,如果访问的时候带有端口号则会加上端口号
  • request.is_secure():判断是否采用https协议
  • request.is_ajax():判断是否采用ajax进行请求

3. QueryDict对象

  • 定义:request.GETrequest.POST都是QueryDict对象,这个对象继承自dict

  • get:获取键值对

    username = request.GET.get('username',default='') #没有值时返回None或默认值
    
  • getlist:获取同个字段下的多个值,返回值为一个列表

    username = request.POST.getlist('username',default='')
    

4. HttpResponse对象

  • 定义:Django服务器将客户端提交上来的数据封装成HttpRequest对象传给视图函数,视图函数在处理后将返回一个HttpResponse对象给客户端

5. JsonResponse对象

  • 定义:返回Json数据

    from django.http import HttpResonse,JsonResponse
    #一般方法
    def func(request):
        person = {
            'username':'zhangsan',
            'age':18
        }
        person_str = json.dumps(person)
        response = HttpResponse(person_str,content_tape='application/json')
        return response
    
    #JsonResponse方法
    def fund(request):
        person = {
            'username':'zhangsan',
            'age':18
        }
        response = JsonResponse(person)
        return response
    
  • 注意:默认情况下,JsonResponse只能对字典进行操作,如果要封装非字典的数据,那么需要传递一个safe=False参数

    def fune(request):
        persons = [
        {
            'username':'zhangsan',
            'age':18,
        },
            {
            'username':'lidi',
            'age':19,
            },
        ]
        response = JsonResponse(persons,safe=False)
        return response
    

6. 生成CSV文件

  • 简单用法:生成附件下载小csv文件

    from django.http import HttpResponse
    import csv
    def download(request):
        response = HttpResponse(content_type='text/csv')
        response['Content-Disposition'] = "attachment;filename='abc.csv'" #Content-Disposition表示对文件的描述;attachment指的是附件形式;filename表示文件名
        writer = csv.writer(response)
        writer.writeow(['username':'age'])
        writer.writeow(['zhiliao',18]) #可以使用模板简化操作:tempload终端loader和render方法
        return response
    
  • 复杂用法:生成响应大型CSV文件

    from django.http import HttpResponse,StringHttpResponse #流下载
    import csv
    def download(request):
        response = StringHttpResponse(content_type='text/csv')
        response['Content-Disposition'] = "attachment;filename='abc.csv'"
        rows = ("Row {},{}\n".format(row,row)for row in range(0,100000))
    	response.streaming_content = rows
        return response
    

7. 类视图

  • View视图:除了支持对getpost方法的响应,还支持对put、patch、delete、head、options、trace等方法的响应
  • http_method_not_allowed:当 客户端使用了当前View视图不支持的方法进行请求时,可以对该方法定义进行错误响应

四. 表单模块

1. 常用验证器

  • 定义:在验证某些字段时,可以传递一个validators参数来指定验证器,进一步对数据进行过滤(某些验证器已经封装在了一些Field中)(验证器也可定义在模型中)

  • MaxValueValidator:验证最大值

  • MinValueValidator:验证最小值

  • MinLengthValidator:验证最小长度

  • MaxLengthValidator:验证最大长度

  • EmailValidator:验证是否是邮箱格式

  • UrlValidator:验证是否是URL格式

  • RegexValidator:通过正则表达式进行更复杂的验证

    from django import forms
    from django.core import validators
    class MyForm(forms.Form):
        telephone = forms.CharField(validators=[validators.RegexValidator("1[345678]\d{9}",message='请输入正确格式的手机号码')])
        email = froms.CharField(validators=[validators.EmailValidator(message='请输入正确格式的邮箱')])
    

2. 自定义验证

  • 自定义clean_fieldname:

    from .model import User
    def clean_telephone(self):
        telephone = self.clean_data.get('telephone')
        exists = User.objects.filter(telephone=telephone).exists()
        if exists:
            raise forms.ValidationError(message='该手机号码已存在')
        return telephone
    
  • 自定义clean:说明之前表单的每一个字段都验证成功了,最后再进行总的验证

    def clean(self):
        cleaned_data = super().clean()
        pwd1 = cleaned_data.get('pwd1')
        pwd2 = cleaned_data.get('pwd2')
        if pwd1 != pwd2:
            raise forms.ValidationError(message='两次输入密码不一致')
        return cleaned_data
    

3. 提取错误信息

  • from.errors:这个属性获取到的错误信息是一个包含了html标签的错误信息

  • from.get_json_data:这个 属性获取到达错误信息属于字典类型

  • 自定义错误信息获取方法

    def get_error(self):
        errors = self.errors.get_json_data()
        new_errors = {}
        for key,message_dicts in errors.items():
            message = []
            for message_divt in message_dicts:
                message = message_dict['message']
                message.append(message)
            new_error[key] = messages
    	return new_errors
    

4. ModelForm

  • 自定义错误提示信息

    from django import forms
    from .model import Book
    class AddBookForm(forms.ModelForm):
        class Meta:
            model = Book
            exclude = ['price']
            #fields = ['title','content']
            error_messages = {
                'page':{
                    'required':'请传入参数',
                    'invalid':'请输入一个合法的参数',
                },
                'title':{
                    'max_length':'长度不能超过100个字符',
                },
            }
    
  • save()方法:表单数据验证后即可立即存储到数据库

    if form.is_valid():
        form.save()
    

5. 限制上传的文件类型

  • 使用限制器在模型中进行限制

    class Article(model.Model):
        title = model.CharField(max_length=100)
        content = model.TextField()
        thumbnial = model.FileField(upload_to='%Y%m%D',validators=[validators.FileExtensensionValidator(['txi','pdf'],message='文件必须为txt或pdf格式')])
    
  • 使用ImageField进行图片上传限制

    thumbnial = model.ImageField(upload_to='%Y%m%d')
    
posted @ 2020-04-21 11:41  言兴  阅读(95)  评论(0)    收藏  举报