zoukankan      html  css  js  c++  java
  • django进阶

    1.模板内容复习

    2.FBV及CBV及上传文件

    3.ORM复习

    4.ORM拓展

    5.cookie和session

    6.csrf详情

    7.django分页

    django预备知识:https://www.cnblogs.com/wyb666/p/9444150.html

    django基础:https://www.cnblogs.com/wyb666/p/9464983.html

    1.模板内容复习

    (1)母版和继承

    1 什么时候用母版?
    2 html页面有重复的代码,把它们提取出来放到一个单独的html文件(比如:导航条和左侧菜单)
    3 
    4 子页面如何使用母版?
    5 {% extends 'base.html' %} --> 必须要放在子页面的第一行
    6 母版里面定义block(块),子页面使用block(块)去替换母版中同名的块

    (2)组件

    1 什么时候用组件?
    2 重复的代码,包装成一个独立的小html文件。
    3 
    4 如何使用?
    5 {% include 'nav.html' %}

    (3)Django模板语言中关于静态文件路径的灵活写法

    1 利用Django模板语言内置的static方法帮我拼接静态文件的路径:
    2 {% load static %}
    3 <link href="{% static 'bootstrap/css/bootstrap.min.css' %}" rel="stylesheet">
    4 
    5 利用内置的get_static_prefix获取静态文件路径的别名,我们自行拼接路径:
    6 {% load static %}
    7 <link href="{% get_static_prefix %}bootstrap/css/bootstrap.min.css" rel=stylesheet>

    (4)自定义simple_tag和自定义inclusion_tag

    1 自定义的simple_tag:
    2     比filter高级一点点,返回一段文本
    3     它可以接受的参数个数大于2
    4 
    5 自定义的inclusion_tag:
    6     用来返回一段html代码(示例:返回ul标签)

    py文件(放在在app下面新建的templatetags 文件夹(包)):

    HTML:

     

    2.FBV及CBV及上传文件

    (1)什么是FBV及CBV

    视图:接收请求返回响应那部分

    FBV:function base view  基于函数的视图

    CBV:class base view  基于类的视图

    (2)CBV实例

    views.py:

     1 # CBV实例 - 添加新的出版社
     2 class AddPublisher(View):
     3     def get(self, request):
     4         return redirect("/book/publisher_list/")
     5 
     6     def post(self, request):
     7         new_name = request.POST.get("publisher_name", None)
     8         if new_name:
     9             # 通过ORM去数据库里新建一条记录
    10             models.Publisher.objects.create(name=new_name)
    11         return redirect("/book/publisher_list/")

    urls.py:

    1 url(r'^add_publisher/', views.AddPublisher.as_view()),

    (3)上传文件

    上传文件要使用到request的以下参数:

    request.FILES: 包含所有上传文件的类字典对象;FILES中的每一个Key都是<input type="file" name="" />标签中name属性的值,FILES中的每一个value同时也是一个标准的python字典对象,包含下面三个Keys:

    • filename: 上传文件名,用字符串表示
    • content_type: 上传文件的Content Type
    • content: 上传文件的原始内容

    前端HTML:

    1 <form action="" method="post" enctype="multipart/form-data">
    2     <input type="file" name="upload-file">
    3     <input type="submit" value="上传文件">
    4 </form>
    5 
    6 注意:
    7     上传文件时表单中的enctype="multipart/form-data"必须要写
    8     input(file)必须要有name

    views.py:

     1 def upload(request):
     2     if request.method == "POST":
     3         filename = request.FILES["upload-file"].name
     4         # 在项目目录下新建一个文件 -> 项目根目录
     5         with open(filename, "wb") as f:
     6             # 从上传的文件对象中一点一点读
     7             for chunk in request.FILES["upload-file"].chunks():
     8                 # 写入本地文件
     9                 f.write(chunk)
    10         return HttpResponse("上传OK")
    11     return render(request, "test/test_upload.html")

    3.ORM复习

    (1)django ORM增删改查

     1 DjangoORM基本增删查改:
     2 # 创建:
     3     # (1)
     4     # models.UserInfo.objects.create(username='root', pwd='666888999')
     5     # (2)
     6     # dict = {'username': 'alex', 'pwd': '333'}
     7     # models.UserInfo.objects.create(**dict)
     8     # (3)
     9     # obj = models.UserInfo.objects.create(username='root', pwd='666888999')
    10     # obj.save()
    11 
    12 # 查:
    13     # (1)全部:
    14     # result = models.UserInfo.objects.all()
    15     # (2)按条件查找:
    16     # result = models.UserInfo.objects.filter(username='root')
    17     # first = models.UserInfo.objects.filter(username='root').first()
    18     # count = models.UserInfo.objects.filter(username='root').count()
    19     # result = models.UserInfo.objects.filter(username='root', pwd='123456')
    20 
    21     # 查找的结果的数据结构:
    22     # result, QuerySet -> Django -> []
    23     # [obj(id, username, pwd),obj(id, username, pwd),obj(id, username, pwd)]
    24     # 输出查找的结果:
    25     # for row in result:
    26     #     print(row.id, row.username, row.pwd)
    27 
    28 # 删:
    29     # 删除id为4的数据
    30     # models.UserInfo.objects.filter(id=4).delete()
    31     # 删除username为alex的数据
    32     # models.UserInfo.objects.filter(username="alex").delete()
    33 
    34 # 更新:
    35     # 全部更新:
    36     # models.UserInfo.objects.all().update(pwd='666')
    37     # 条件更新:
    38     # models.UserInfo.objects.filter(id=3).update(pwd='69')

    (2)ORM字段

    常用字段:

    • AutoField -->  int自增列 必须填入参数primary_key=True
    • CharField -->  字符类型 varchar(xx) 必须提供max_length参数
    • TextField  -->  文本类型
    • ForeignKey --> 外键
    • ManyToManyField --> 多对多关联
    • DateField  -->  日期字段  YYYY-MM-DD 相当于python的datetime.date()实例
    • DateTimeField  -->  日期时间字段 YYYY-MM-DD HH:MM 相当于python的datetime.datetime()实例
    • IntegerField  -->  整数类型

    常用的字段参数:

    • null 表示某个字段可以为空
    • default 为字段设置默认值
    • unique 表示该字段在此表中唯一
    • db_index 为此字段设置索引


    DateField和DateTimeField才有的参数:

    • auto_now_add=True --> 创建数据的时候自动把当前时间赋值
    • auto_add=True --> 每次更新数据的时候更新当前时间
    • 注意: 上述两个不能同时设置!!!

    (3)关系字段

    • ForeignKey:外键类型在ORM中用来表示外键关联关系,一般把ForeignKey字段设置在 '一对多'中'多'的一方
    • OneToOneField:一对一字段  通常一对一字段用来扩展已有字段
    • ManyToManyField: 用于表示多对多的关联关系。在数据库中通过第三张表来建立关联关系

    eg:

    • ForeignKey(to="类名",related_name=“xx”)   -->  1对多,外键通常设置在多的那一边
    • ManyToMany(to="类名",related_name="xx")  -->   多对多,通常设置在正向查询多的那一边
    • OneToOneField(to="类名")  --> 1对1,把不怎么常用的字段 单独拿出来做成一张表 然后用过一对一关联起来

    关于多对多:

     1 # 多对多的方式:
     2 # 1. ORM ManyToManyField()自动帮我创建第三张表  -->  关系表中没有额外字段、ORM封装了很多方法可以使用: add() remove() set() clear()
     3 
     4 # 2. 自己创建第三张表, 利用外键分别关联作者和书  这种方法关联查询比较麻烦,因为没办法使用ORM提供的便利方法
     5     
     6 # 3. 自己创建第三张表,用ORM的ManyToManyField()的through指定表名(自建的关系表) --> 可向关系表中添加额外字段, 使用此种方式没有ORM封装的方法可使用  注: through_fields = (field1, field2) field1是关系表通过哪个属性可以找到这张表
     7      
     8 
     9 # 我们应该用哪种?  看情况:
    10 # 如果你第三张表没有额外的字段,就用第一种
    11 # 如果你第三张表有额外的字段,就用第三种或第一种
    12 
    13 # 有额外字段的实际情况:
    14 """
    15 相亲网站:
    16     Boy
    17         girl = ManyToManyField(to=“Girl")
    18     
    19     Girl
    20     
    21     约会记录:多对多
    22         id  boy_id  girl_id  date
    23 """

    实例:

     1 # 一对多:
     2 class Publisher(models.Model):
     3     id = models.AutoField(primary_key=True)
     4     name = models.CharField(max_length=64, null=False, unique=True)
     5 
     6 class Book(models.Model):
     7     id = models.AutoField(primary_key=True)
     8     title = models.CharField(max_length=64, null=False, unique=True)
     9     # 和出版社关联的外键字段:
    10     publisher = models.ForeignKey(to="Publisher")
    11     # 数据库中没有publisher这个字段 这有publisher_id这个字段
    12 
    13 # 一对一:
    14 class Author(models.Model):
    15   name = models.CharField(max_length=32)
    16   info = models.OneToOneField(to='AuthorInfo')
    17 
    18 class AuthorInfo(models.Model):
    19   phone = models.CharField(max_length=11)
    20   email = models.EmailField()
    21 
    22 # 多对多1(系统自动生成第三张表 or 自己建第张方表):
    23 class Book(models.Model):
    24     id = models.AutoField(primary_key=True)
    25     title = models.CharField(max_length=64, null=False, unique=True)
    26 
    27 class Author(models.Model):
    28     id = models.AutoField(primary_key=True)
    29     name = models.CharField(max_length=32, null=False, unique=True)
    30     book = models.ManyToManyField(to="Book")    # 告诉ORM Author和Book是多对多关系 系统自动生成第三张表
    31 
    32 # 多对多2(自己建第三张表 利用外键关联)
    33 class Author2Book(models.Model):
    34     id = models.AutoField(primary_key=True)
    35     author = models.ForeignKey(to="Author")  # 作者id
    36     book = models.ForeignKey(to="Book")       # 图书id
    37     # 自己建表还可以新建字段
    38     publish_date = models.DateField(auto_now_add=True)

    多对多第三种方式:

    (4)单表查询的双下划线用法

    1 models.Book.objects.filter(id__gt=1)
    2 models.Book.objects.filter(id__in=[1,2,3])
    3 models.Book.objects.filter(id__range=[1,5])
    4 models.Book.objects.filter(title__contains="python")
    5 models.Book.objects.filter(title__icontains="python")
    6 models.Book.objects.filter(title__startswith="python")
    7 models.Book.objects.filter(title__endswith="python")
    8 models.Book.objects.filter(publish_date__year=2017)
    9 models.Book.objects.filter(publish_date__month=2)

    4.ORM拓展

    ORM详细内容:https://www.cnblogs.com/liwenzhou/p/8660826.html

    (1)ORM查询 

    返回QuerySet对象:

    • all(): 查询所有结果
    • filter(**kwargs): 它包含了与所给筛选条件相匹配的对象
    • exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象
    • order_by(*field): 对查询结果排序
    • reverse(): 对查询结果反向排序,请注意reverse()通常只能在具有已定义顺序的QuerySet上调用(在model类的Meta中指定ordering或调用order_by()方法
    • distinct(): 从返回结果中剔除重复纪录(如果你查询跨越多个表,可能在计算QuerySet时得到重复的结果。此时可以使用distinct(),注意只有在PostgreSQL中支持按字段去重

    返回一个特殊的QuerySet对象:

    • values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典序列
    • values_list(*field): 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列

    返回一个具体对象:

    • first(): 返回第一条记录
    • last(): 返回最后一条记录
    • get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误

    返回布尔值:

    exists(): 如果QuerySet包含数据,就返回True,否则返回False

    返回数字:

    count(): 返回数据库中匹配查询(QuerySet)的对象数量

    多对多查询拓展: 

     1 def select_related(self, *fields)
     2     # 性能相关:表之间进行join连表操作,一次性获取关联的数据。
     3 
     4     总结:
     5     1. select_related主要针一对一和多对一关系进行优化。
     6     2. select_related使用SQL的JOIN语句进行优化,通过减少SQL查询的次数来进行优化、提高性能。
     7 
     8 def prefetch_related(self, *lookups)
     9     # 性能相关:多表连表操作时速度会慢,使用其执行多次SQL查询在Python代码中实现连表操作。
    10 
    11     总结:
    12     1. 对于多对多字段(ManyToManyField)和一对多字段,可以使用prefetch_related()来进行优化。
    13     2. prefetch_related()的优化方式是分别查询每个表,然后用Python处理他们之间的关系。

    (2)外键的查询操作

     1 # 正向查询:
     2 # 查询第一本书的出版社
     3 book_obj = models.Book.objects.all().first()
     4 ret = book_obj.publisher
     5 res = book_obj.publisher.name
     6 print(ret, res)
     7 # 查询id是7的书的出版社的名称
     8 # 利用双下划线 跨表查询 双下划线就表示跨了一张表
     9 ret = models.Book.objects.filter(id=7).values_list("publisher__name")
    10 print(ret)
    11 
    12 # 反向查询:
    13 # 1. 基于对象查询
    14 publisher_obj = models.Publisher.objects.get(id=1)  # 得到一个具体的对象
    15 # ret = publisher_obj.book_set.all()
    16 # 在外键字段中加上related_name="books",之后就要使用下面的方法查询:
    17 ret = publisher_obj.books.all()
    18 print(ret)
    19 # 2. 基于双下划线
    20 ret = models.Publisher.objects.filter(id=1).values_list("books__title")
    21 print(ret)

    注意:

    (3)多对多操作

    查询: 

    1 # 查询第一个作者:
    2 author_obj = models.Author.objects.first()
    3 print(author_obj.name)
    4 # 查询写过的书:
    5 ret = author_obj.book.all()
    6 print(author_obj.book, type(author_obj.book))
    7 print(ret)

    增删改查操作:

     1 # 1. create
     2 # 通过作者创建一本书,会自动保存
     3 # 做了两件事:1. 在book表里面创建一本新书,2. 在作者和书的关系表中添加关联记录
     4 author_obj = models.Author.objects.first()
     5 author_obj.book.create(title="wyb自传", publisher_id=1)
     6 
     7 # 2. add
     8 # 在wyb关联的书里面,再加一本id是8的书
     9 book_obj = models.Book.objects.get(id=8)
    10 author_obj.book.add(book_obj)
    11 # 添加多个
    12 book_objs = models.Book.objects.filter(id__gt=5)
    13 author_obj.book.add(*book_objs)  # 要把列表打散再传进去
    14 # 直接添加id
    15 author_obj.book.add(9)
    16 
    17 # 3.remove
    18 book_obj = models.Book.objects.get(title="跟Alex学泡妞")
    19 author_obj.book.remove(book_obj)
    20 # 把 id是8的记录 删掉
    21 author_obj.book.remove(8)
    22 
    23 # 4.clear
    24 # 清空
    25 jing_obj = models.Author.objects.get(id=2)
    26 jing_obj.book.clear()

    注意:

    对于ForeignKey对象,clear()和remove()方法仅在null=True时存在

    (4)分组和聚合查询

    聚合查询:

    aggregate()QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。

    键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的

    用到的内置函数:

    1 from django.db.models import Avg, Sum, Max, Min, Count

    实例如下:

    1 from django.db.models import Avg, Sum, Max, Min, Count
    2 res = models.Book.objects.all().aggregate(price_avg=Avg("price"), price_max=Max("price"), price_min=Min("price"))
    3 print(res)
    4 print(res.get("price_avg"), res.get("price_max"), res.get("price_min"))
    5 print(type(res.get("price_max")))  # <class 'decimal.Decimal'>

    分组查询:

     1 # 查询每一本书的作者个数
     2 from django.db.models import Avg, Sum, Max, Min, Count
     3 ret = models.Book.objects.all().annotate(author_num=Count("author"))
     4 print(ret)
     5 for book in ret:
     6     print("书名:{},作者数量:{}".format(book.title, book.author_num))
     7 
     8 # 查询作者数量大于1的书
     9 ret = models.Book.objects.all().annotate(author_num=Count("author")).filter(author_num__gt=1)
    10 print(ret)
    11 
    12 # 查询各个作者出的书的总价格13 ret = models.Author.objects.all().annotate(price_sum=Sum("book__price"))
    14 print(ret)
    15 for i in ret:
    16     print(i, i.name, i.price_sum)
    17 print(ret.values_list("id", "name", "price_sum"))

    (5)F查询和Q查询

    F查询:

    在上面所有的例子中,我们构造的过滤器都只是将字段值与某个常量做比较。如果我们要对两个字段的值做比较,那该怎么做呢?

    Django 提供 F() 来做这样的比较。F() 的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值

    F查询实例:

     1 from django.db.models import F
     2 
     3 # 查询评论数大于收藏数的书籍
     4 models.Book.objects.filter(comment_num__gt=F('keep_num'))
     5 
     6 # 修改操作也可以使用F函数,比如将每一本书的价格提高30元
     7 models.Book.objects.all().update(price=F("price")+30)
     8 
     9 # 修改字段:
    10 from django.db.models.functions import Concat
    11 from django.db.models import Value
    12 models.Book.objects.all().update(title=Concat(F("title"), Value("("), Value("第一版"), Value(")")))

    Q查询:

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

    Q查询实例:

     1 from django.db.models import Q
     2 # 查询 卖出数大于1000,并且 价格小于100的所有书
     3 ret = models.Book.objects.filter(maichu__gt=1000, price__lt=100)
     4 print(ret)
     5 
     6 # 查询 卖出数大于1000,或者 价格小于100的所有书
     7 ret = models.Book.objects.filter(Q(maichu__gt=1000) | Q(price__lt=100))
     8 print(ret)
     9 
    10 # Q查询和字段查询同时存在时, 字段查询要放在Q查询的后面
    11 ret = models.Book.objects.filter(Q(maichu__gt=1000) | Q(price__lt=100), title__contains="金老板")
    12 print(ret)

    ORM拓展内容总结:

     1 #分组和聚合
     2 # 聚合:
     3 from django.db.models import Avg, Sum, Max, Min, Count
     4 models.Book.objects.all().aggregate(Avg("price"))
     5 
     6 # 分组:
     7 book_list = models.Book.objects.all().annotate(author_num=Count("author"))
     8 
     9 # F和Q
    10 # 当需要字段和字段作比较的时候用F查询
    11 # 当查询条件是 或 的时候 用Q查询,因为默认的filter参数都是且的关系
      1 ##################################################################
      2 # PUBLIC METHODS THAT ALTER ATTRIBUTES AND RETURN A NEW QUERYSET #
      3 ##################################################################
      4 
      5 def all(self)
      6     # 获取所有的数据对象
      7 
      8 def filter(self, *args, **kwargs)
      9     # 条件查询
     10     # 条件可以是:参数,字典,Q
     11 
     12 def exclude(self, *args, **kwargs)
     13     # 条件查询
     14     # 条件可以是:参数,字典,Q
     15 
     16 def select_related(self, *fields)
     17     性能相关:表之间进行join连表操作,一次性获取关联的数据。
     18 
     19     总结:
     20     1. select_related主要针一对一和多对一关系进行优化。
     21     2. select_related使用SQL的JOIN语句进行优化,通过减少SQL查询的次数来进行优化、提高性能。
     22 
     23 def prefetch_related(self, *lookups)
     24     性能相关:多表连表操作时速度会慢,使用其执行多次SQL查询在Python代码中实现连表操作。
     25 
     26     总结:
     27     1. 对于多对多字段(ManyToManyField)和一对多字段,可以使用prefetch_related()来进行优化。
     28     2. prefetch_related()的优化方式是分别查询每个表,然后用Python处理他们之间的关系。
     29 
     30 def annotate(self, *args, **kwargs)
     31     # 用于实现聚合group by查询
     32 
     33     from django.db.models import Count, Avg, Max, Min, Sum
     34 
     35     v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id'))
     36     # SELECT u_id, COUNT(ui) AS `uid` FROM UserInfo GROUP BY u_id
     37 
     38     v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id')).filter(uid__gt=1)
     39     # SELECT u_id, COUNT(ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1
     40 
     41     v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id',distinct=True)).filter(uid__gt=1)
     42     # SELECT u_id, COUNT( DISTINCT ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1
     43 
     44 def distinct(self, *field_names)
     45     # 用于distinct去重
     46     models.UserInfo.objects.values('nid').distinct()
     47     # select distinct nid from userinfo
     48 
     49     注:只有在PostgreSQL中才能使用distinct进行去重
     50 
     51 def order_by(self, *field_names)
     52     # 用于排序
     53     models.UserInfo.objects.all().order_by('-id','age')
     54 
     55 def extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
     56     # 构造额外的查询条件或者映射,如:子查询
     57 
     58     Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,))
     59     Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
     60     Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
     61     Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])
     62 
     63  def reverse(self):
     64     # 倒序
     65     models.UserInfo.objects.all().order_by('-nid').reverse()
     66     # 注:如果存在order_by,reverse则是倒序,如果多个排序则一一倒序
     67 
     68 
     69  def defer(self, *fields):
     70     models.UserInfo.objects.defer('username','id')
     71  72     models.UserInfo.objects.filter(...).defer('username','id')
     73     #映射中排除某列数据
     74 
     75  def only(self, *fields):
     76     #仅取某个表中的数据
     77      models.UserInfo.objects.only('username','id')
     78  79      models.UserInfo.objects.filter(...).only('username','id')
     80 
     81  def using(self, alias):
     82      指定使用的数据库,参数为别名(setting中的设置)
     83 
     84 
     85 ##################################################
     86 # PUBLIC METHODS THAT RETURN A QUERYSET SUBCLASS #
     87 ##################################################
     88 
     89 def raw(self, raw_query, params=None, translations=None, using=None):
     90     # 执行原生SQL
     91     models.UserInfo.objects.raw('select * from userinfo')
     92 
     93     # 如果SQL是其他表时,必须将名字设置为当前UserInfo对象的主键列名
     94     models.UserInfo.objects.raw('select id as nid from 其他表')
     95 
     96     # 为原生SQL设置参数
     97     models.UserInfo.objects.raw('select id as nid from userinfo where nid>%s', params=[12,])
     98 
     99     # 将获取的到列名转换为指定列名
    100     name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'}
    101     Person.objects.raw('SELECT * FROM some_other_table', translations=name_map)
    102 
    103     # 指定数据库
    104     models.UserInfo.objects.raw('select * from userinfo', using="default")
    105 
    106     ################### 原生SQL ###################
    107     from django.db import connection, connections
    108     cursor = connection.cursor()  # cursor = connections['default'].cursor()
    109     cursor.execute("""SELECT * from auth_user where id = %s""", [1])
    110     row = cursor.fetchone() # fetchall()/fetchmany(..)
    111 
    112 
    113 def values(self, *fields):
    114     # 获取每行数据为字典格式
    115 
    116 def values_list(self, *fields, **kwargs):
    117     # 获取每行数据为元祖
    118 
    119 def dates(self, field_name, kind, order='ASC'):
    120     # 根据时间进行某一部分进行去重查找并截取指定内容
    121     # kind只能是:"year"(年), "month"(年-月), "day"(年-月-日)
    122     # order只能是:"ASC"  "DESC"
    123     # 并获取转换后的时间
    124         - year : 年-01-01
    125         - month: 年-月-01
    126         - day  : 年-月-127 
    128     models.DatePlus.objects.dates('ctime','day','DESC')
    129 
    130 def datetimes(self, field_name, kind, order='ASC', tzinfo=None):
    131     # 根据时间进行某一部分进行去重查找并截取指定内容,将时间转换为指定时区时间
    132     # kind只能是 "year", "month", "day", "hour", "minute", "second"
    133     # order只能是:"ASC"  "DESC"
    134     # tzinfo时区对象
    135     models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.UTC)
    136     models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.timezone('Asia/Shanghai'))
    137 
    138     """
    139     pip3 install pytz
    140     import pytz
    141     pytz.all_timezones
    142     pytz.timezone(‘Asia/Shanghai’)
    143     """
    144 
    145 def none(self):
    146     # 空QuerySet对象
    147 
    148 
    149 ####################################
    150 # METHODS THAT DO DATABASE QUERIES #
    151 ####################################
    152 
    153 def aggregate(self, *args, **kwargs):
    154    # 聚合函数,获取字典类型聚合结果
    155    from django.db.models import Count, Avg, Max, Min, Sum
    156    result = models.UserInfo.objects.aggregate(k=Count('u_id', distinct=True), n=Count('nid'))
    157    ===> {'k': 3, 'n': 4}
    158 
    159 def count(self):
    160    # 获取个数
    161 
    162 def get(self, *args, **kwargs):
    163    # 获取单个对象
    164 
    165 def create(self, **kwargs):
    166    # 创建对象
    167 
    168 def bulk_create(self, objs, batch_size=None):
    169     # 批量插入
    170     # batch_size表示一次插入的个数
    171     objs = [
    172         models.DDD(name='r11'),
    173         models.DDD(name='r22')
    174     ]
    175     models.DDD.objects.bulk_create(objs, 10)
    176 
    177 def get_or_create(self, defaults=None, **kwargs):
    178     # 如果存在,则获取,否则,创建
    179     # defaults 指定创建时,其他字段的值
    180     obj, created = models.UserInfo.objects.get_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 2})
    181 
    182 def update_or_create(self, defaults=None, **kwargs):
    183     # 如果存在,则更新,否则,创建
    184     # defaults 指定创建时或更新时的其他字段
    185     obj, created = models.UserInfo.objects.update_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 1})
    186 
    187 def first(self):
    188    # 获取第一个
    189 
    190 def last(self):
    191    # 获取最后一个
    192 
    193 def in_bulk(self, id_list=None):
    194    # 根据主键ID进行查找
    195    id_list = [11,21,31]
    196    models.DDD.objects.in_bulk(id_list)
    197 
    198 def delete(self):
    199    # 删除
    200 
    201 def update(self, **kwargs):
    202     # 更新
    203 
    204 def exists(self):
    205    # 是否有结果
    206 
    207 QuerySet方法大全
    QuerySet方法大全

    5.cookie和session

    详细内容:https://www.cnblogs.com/wyb666/p/9068853.html

    6.csrf详情

    (1)什么是csrf

    csrf:跨站请求伪造

    百度解释:CSRF(Cross-site request forgery)跨站请求伪造,也被称为“One Click Attack”或者Session Riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。尽管听起来像跨站脚本(XSS),但它与XSS非常不同,XSS利用站点内的信任用户,而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站。与XSS攻击相比,CSRF攻击往往不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被认为比XSS更具危险性

    一句话解释:CSRG是指通过通过伪造页面来欺骗用户,让用户在钓鱼网址上输入关键信息,然后修改部分数据提交给真正的服务端程序

    (2)csrf实例

    钓鱼网站的页面和正经网站的页面对浏览器来说有什么区别? (页面是怎么来的?)

    • 钓鱼网站的页面是由 钓鱼网站的服务端给你返回的
    • 正经网站的网页是由 正经网站的服务端给你返回的

    钓鱼网站如何实现钓鱼:前端页面一模一样,但是在表单中隐藏了某些关键的input然后这些input写成无用的input显示在页面上,这些隐藏的input的value是固定值,无论你在那些无用的input上输入什么值,最后提交给服务端的值都是确定的

    详情见下面实例:

    真正的网站前端代码:

     1 <!--__author__ = "wyb"-->
     2 <!DOCTYPE html>
     3 <html lang="en">
     4 <head>
     5     <meta charset="UTF-8">
     6     <title>转账</title>
     7 </head>
     8 <body>
     9 
    10 <h1>真正的网站</h1>
    11 <form action="" method="post">
    12     <p>
    13         转出:
    14         <input type="text" name="from">
    15     </p>
    16     <p>
    17         转入:
    18         <input type="text" name="to">
    19     </p>
    20     <p>
    21         金额:
    22         <input type="text" name="money">
    23     </p>
    24     <p>
    25         <input type="submit" value="转账">
    26     </p>
    27 
    28 </form>
    29 
    30 </body>
    31 </html>

    真正的网站后端代码:

    1 # 真正网站的服务端:
    2 def transfer(request):
    3     if request.method == "GET":
    4         return render(request, "test/transfer_test.html")
    5     from_ = request.POST.get("from")
    6     to_ = request.POST.get("to")
    7     money = request.POST.get("money")
    8     print("{} 给 {} 转了 {}钱".format(from_, to_, money))
    9     return HttpResponse("转账成功!")

    钓鱼网站前端代码:

     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>转账</title>
     6 </head>
     7 <body>
     8 
     9 <h1>钓鱼的网站</h1>
    10 <form action="http://127.0.0.1:8000/basic/transfer/" method="post">
    11     <p>
    12         转出:
    13         <input type="text" name="from">
    14     </p>
    15 
    16     <p>
    17         转入:
    18         <input type="text" name="">
    19         <input type="text" name="to" style="display: none" value="黑客">
    20     </p>
    21     <p>
    22         金额:
    23         <input type="text" name="money">
    24     </p>
    25     <p>
    26         <input type="submit" value="转账">
    27     </p>
    28 </form>
    29 </body>
    30 </html>

    钓鱼网站后端代码:

    1 def transfer(request):
    2     return render(request, "transfer.html")

    两者页面如下:

    注:页面中的标题只是为了便于区分,正真的钓鱼网站可以说和原网站几乎一模一样,可以以假乱真

    两个网站转账的数据相同时转账效果:

    钓鱼网站通过隐藏的input框修改了转账的转入方,在钓鱼网站上的转入方无论你填什么最后转入方都是黑客

    (3)Django内置的处理csrf问题的中间件

    django中内置的处理csrf问题的中间件是:django.middleware.csrf.CsrfViewMiddleware

    这个中间件做的事情:

    • 在render返回页面的时候,在页面中塞了一个隐藏的input标签(eg: <input type="hidden" name="csrfmiddlewaretoken" value="8gthvLKulM7pqulNl2q3u46v1oEbKG7BSwg6qsHBv4zf0zj0UcbQmpbAdijqyhfE">)
    • 当你提交POST数据的时候,它帮你做校验,如果校验不通过就拒绝这次请求

    (4)django内置csrf中间件用法
    在页面上 form表单 里面 写上 {% csrf_token %}就行了然后在settings.py中去掉csrf的注释,之后再用上面的实例测试效果如下:
    钓鱼网站:

    真正网站:

    (5)csrf补充 - CSRF Token相关装饰器

    CSRF Token相关装饰器在CBV只能加到dispatch方法上,或者加在视图类上然后name参数指定为dispatch方法。

    • csrf_protect:为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件
    • csrf_exempt:取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件

    CBV写法:

     1 from django.views.decorators.csrf import csrf_exempt, csrf_protect
     2 from django.utils.decorators import method_decorator
     3 
     4 class HomeView(View):
     5     @method_decorator(csrf_exempt)
     6     def dispatch(self, request, *args, **kwargs):
     7         return super(HomeView, self).dispatch(request, *args, **kwargs)
     8 
     9     def get(self, request):
    10         return render(request, "home.html")
    11 
    12     def post(self, request):
    13         print("Home View POST method...")
    14         return redirect("/index/")
    15 
    16 
    17 # 或者这样写:
    18 @method_decorator(csrf_exempt, name='dispatch')
    19 class HomeView(View):
    20    
    21     def dispatch(self, request, *args, **kwargs):
    22         return super(HomeView, self).dispatch(request, *args, **kwargs)
    23 
    24     def get(self, request):
    25         return render(request, "home.html")
    26 
    27     def post(self, request):
    28         print("Home View POST method...")
    29         return redirect("/index/")

    FBV写法:

    1 from django.views.decorators.csrf import csrf_exempt, csrf_protect
    2 
    3 @csrf_exempt
    4 def login(request):
    5     xxx

    7.django分页

    (1)分页基本逻辑

    books/?page=n  --> n是整数,表示第几页

    • page=1:  第一条到第十条数据
    • page=2:  第十一条到第二十条数据
    • page=3:  第二十一条到第三十条数据
    • 以后依次类推
    1 # 第一页: all_book = models.Book.objects.all()[0:10]        # 1到10
    2 # 第二页: all_book = models.Book.objects.all()[10:20]       # 11到20
    3 # 第三页: all_book = models.Book.objects.all()[20:30]       # 21到30
    4 # 第n页:                                 n -> [(n-1)*10, n*10]

    从request.GET中取出page对应的数,然后取出对应的数据传给前端即可,page对应的数默认设为1

    (2)自定义分页

    views.py:

     1 # 原生分页
     2 def books(request):
     3     # 第一页: all_book = models.Book.objects.all()[0:10]        # 1到10
     4     # 第二页: all_book = models.Book.objects.all()[10:20]       # 11到20
     5     # 第三页: all_book = models.Book.objects.all()[20:30]       # 21到30
     6     # 第n页:                                 n -> [(n-1)*10, n*10]
     7 
     8     # 总数据是多少
     9     data_count = models.Book.objects.all().count()
    10     # 每一页显示多少条数据
    11     per_page = 10
    12     # 总共需要多少页码来展示
    13     total_page, m = divmod(data_count, per_page)
    14     if m:
    15         total_page = total_page + 1
    16 
    17     # 从URL中取参数:
    18     page_num = request.GET.get("page", "1")
    19     try:
    20         page_num = int(page_num)
    21     except Exception as e:
    22         # 当输入页码不是正常数字时 默认返回1
    23         page_num = 1
    24     # 如果输入的数字大于total_page时 默认返回最大
    25     if page_num > total_page:
    26         page_num = total_page
    27 
    28     # data_start和data_end分别保存数据的起始
    29     data_start = (page_num - 1) * per_page
    30     data_end = page_num * per_page
    31     # 页面上总共展示多少页码(最多)
    32     max_page = 10
    33     if total_page < max_page:
    34         max_page = total_page
    35     half_max_page = max_page//2
    36     # 页码开始和结束
    37     page_start = page_num - half_max_page
    38     page_end = page_num + half_max_page
    39     if page_start <= 1:
    40         page_start = 1
    41         page_end = max_page + 1
    42     if page_end > total_page:
    43         page_start = total_page - max_page
    44         page_end = total_page + 1
    45 
    46     all_book = models.Book.objects.all()[data_start:data_end]
    47 
    48     # 拼接HTML:
    49     html_str_list = []
    50     # 加上上一页
    51     # 判断 如果是第一页 就没有上一页
    52     if page_num <= 1:
    53         html_str_list.append('<li class="disabled"><a href="#" aria-label="Previous"><span aria-hidden="true">&laquo;</span></a></li>'.format(page_num-1))
    54     else:
    55         html_str_list.append('<li><a href="/books/?page={}" aria-label="Previous"><span aria-hidden="true">&laquo;</span></a></li>'.format(page_num-1))
    56     # 加上第一页 -> 写死
    57     html_str_list.append('<li><a href="/books/?page=1">首页</a></li>')
    58     for i in range(page_start, page_end):
    59         # 如果是当前页就加上active类
    60         if i == page_num:
    61             tmp = '<li class="active"><a href="/books/?page={0}">{0}</a></li>'.format(i)
    62         else:
    63             tmp = '<li><a href="/books/?page={0}">{0}</a></li>'.format(i)
    64         html_str_list.append(tmp)
    65     # 加上最后一页
    66     html_str_list.append('<li><a href="/books/?page={}">尾页</a></li>'.format(total_page))
    67     # 加上下一页
    68     # 判断 如果是最后一页 就没有下一页
    69     if page_num >= total_page:
    70         html_str_list.append('<li class="disabled"><a href="#" aria-label="Next"><span aria-hidden="true">&raquo;</span></a></li>'.format(page_num+1))
    71     else:
    72         html_str_list.append('<li><a href="/books/?page={}" aria-label="Next"><span aria-hidden="true">&raquo;</span></a></li>'.format(page_num+1))
    73     page_html = "".join(html_str_list)
    74 
    75     return render(request, "books.html", {"books": all_book, "page_html": page_html})
    View Code

    HTML:

     1 <!--__author__ = "wyb"-->
     2 <!DOCTYPE html>
     3 <html lang="en">
     4 <head>
     5     <meta charset="UTF-8">
     6     <title>书籍列表</title>
     7     <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"
     8       integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
     9 </head>
    10 <body>
    11 
    12 <div class="container">
    13     <table class="table table-bordered table-striped">
    14         <thead>
    15             <tr>
    16                 <th>序号</th>
    17                 <th>id</th>
    18                 <th>书名</th>
    19             </tr>
    20         </thead>
    21         <tbody>
    22         {% for book in books %}
    23             <tr>
    24                 <td>{{ forloop.counter }}</td>
    25                 <td>{{ book.id }}</td>
    26                 <td>{{ book.title }}</td>
    27             </tr>
    28         {% endfor %}
    29         </tbody>
    30     </table>
    31 
    32     <nav aria-label="Page navigation">
    33       <ul class="pagination">
    34         {{ page_html|safe }}
    35       </ul>
    36     </nav>
    37 
    38 </div>
    39 
    40 
    41 </body>
    42 </html>
    View Code

    封装之后的分页:

     1 # 分页封装保存版
     2 class Pagination(object):
     3     def __init__(self, current_page, total_count, base_url, per_page=10, max_show=10):
     4         """
     5         :param current_page: 当前页
     6         :param total_count: 数据库中数据总数
     7         :param base_url: url前缀
     8         :param per_page: 每页显示多少条数据
     9         :param max_show: 最多显示多少页
    10         """
    11         try:
    12             current_page = int(current_page)
    13         except Exception as e:
    14             current_page = 1
    15 
    16         self.current_page = current_page
    17         self.total_count = total_count
    18         self.base_url = base_url
    19         self.per_page = per_page
    20         self.max_show = max_show
    21 
    22         # 总页码
    23         total_page, more = divmod(total_count, per_page)
    24         if more:
    25             total_page += 1
    26         self.total_page = total_page
    27 
    28         # 左边间隔的页码和右边间隔的页码
    29         # 10 -> 4和5     11 -> 5和5
    30         if max_show % 2 == 0:
    31             self.left_show = max_show // 2 - 1
    32             self.right_show = max_show // 2
    33         else:
    34             self.left_show = self.right_show = max_show // 2
    35 
    36     @property
    37     def start(self):
    38         return (self.current_page - 1) * self.per_page
    39 
    40     @property
    41     def end(self):
    42         return self.current_page * self.per_page
    43 
    44     def page_html(self):
    45 
    46         if self.current_page <= self.left_show:
    47             show_start = 1
    48             show_end = self.max_show
    49         else:
    50             if self.current_page + self.right_show >= self.total_page:
    51                 show_start = self.total_page - self.max_show + 1
    52                 show_end = self.total_page
    53             else:
    54                 show_start = self.current_page - self.left_show
    55                 show_end = self.current_page + self.right_show
    56 
    57         # 存html的列表
    58         page_html_list = []
    59 
    60         # 加首页
    61         first_li = '<li><a href="{}?page=1">首页</a></li>'.format(self.base_url)
    62         page_html_list.append(first_li)
    63         # 加上一页
    64         if self.current_page == 1:
    65             prev_li = '<li><a href="#">上一页</a></li>'
    66         else:
    67             prev_li = '<li><a href="{0}?page={1}">上一页</a></li>'.format(self.base_url, self.current_page - 1)
    68         page_html_list.append(prev_li)
    69 
    70         # 生成页面上显示的页码
    71         for i in range(show_start, show_end + 1):
    72             if i == self.current_page:
    73                 li_tag = '<li class="active"><a href="{0}?page={1}">{1}</a></li>'.format(self.base_url, i)
    74             else:
    75                 li_tag = '<li><a href="{0}?page={1}">{1}</a></li>'.format(self.base_url, i)
    76             page_html_list.append(li_tag)
    77 
    78         # 加下一页
    79         if self.current_page == self.total_page:
    80             next_li = '<li><a href="#">下一页</a></li>'
    81         else:
    82             next_li = '<li><a href="{0}?page={1}">下一页</a></li>'.format(self.base_url, self.current_page + 1)
    83         page_html_list.append(next_li)
    84         # 加尾页
    85         page_end_li = '<li><a href="{0}?page={1}">尾页</a></li>'.format(self.base_url, self.total_page)
    86         page_html_list.append(page_end_li)
    87 
    88         return "".join(page_html_list)

    封装的分页的使用方法:

    1 # 使用封装的分页
    2 def books2(request):
    3     data = models.Book.objects.all()
    4     pager = Pagination(request.GET.get("page"), len(data), request.path_info)
    5     book_list = data[pager.start:pager.end]
    6     page_html = pager.page_html()
    7     return render(request, "books.html", {"books": book_list, "page_html": page_html})

    注:books.html见上面的HTML

    (3)django内置分页

     1 from django.shortcuts import render
     2 from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
     3 
     4 L = []
     5 for i in range(999):
     6     L.append(i)
     7 
     8 def index(request):
     9     current_page = request.GET.get('p')
    10 
    11     paginator = Paginator(L, 10)
    12     # per_page: 每页显示条目数量
    13     # count:    数据总个数
    14     # num_pages:总页数
    15     # page_range:总页数的索引范围,如: (1,10),(1,200)
    16     # page:     page对象
    17     try:
    18         posts = paginator.page(current_page)
    19         # has_next              是否有下一页
    20         # next_page_number      下一页页码
    21         # has_previous          是否有上一页
    22         # previous_page_number  上一页页码
    23         # object_list           分页之后的数据列表
    24         # number                当前页
    25         # paginator             paginator对象
    26     except PageNotAnInteger:
    27         posts = paginator.page(1)
    28     except EmptyPage:
    29         posts = paginator.page(paginator.num_pages)
    30     return render(request, 'index.html', {'posts': posts})
    内置分页view部分
     1 <!DOCTYPE html>
     2 <html>
     3 <head lang="en">
     4     <meta charset="UTF-8">
     5     <title></title>
     6 </head>
     7 <body>
     8 <ul>
     9     {% for item in posts %}
    10         <li>{{ item }}</li>
    11     {% endfor %}
    12 </ul>
    13 
    14 <div class="pagination">
    15       <span class="step-links">
    16         {% if posts.has_previous %}
    17             <a href="?p={{ posts.previous_page_number }}">Previous</a>
    18         {% endif %}
    19           <span class="current">
    20             Page {{ posts.number }} of {{ posts.paginator.num_pages }}.
    21           </span>
    22           {% if posts.has_next %}
    23               <a href="?p={{ posts.next_page_number }}">Next</a>
    24           {% endif %}
    25       </span>
    26 
    27 </div>
    28 </body>
    29 </html>
    内置分页HTML部分
  • 相关阅读:
    LeetCode 225 Implement Stack using Queues 用队列实现栈
    LeetCode 232 Implement Queue using Stacks 两个栈实现队列
    LeetCode 583 Delete Operation for Two Strings 删除两个字符串的不同部分使两个字符串相同,求删除的步数
    LeetCode 230 Kth Smallest Element in a BST 二叉搜索树中的第K个元素
    LeetCode 236 Lowest Common Ancestor of a Binary Tree 二叉树两个子节点的最低公共父节点
    LeetCode 148 Sort List 链表上的归并排序和快速排序
    LeetCode 069 Sqrt(x) 求平方根
    webpack新版本4.12应用九(配置文件之模块(module))
    webpack新版本4.12应用九(配置文件之输出(output))
    webpack新版本4.12应用九(配置文件之入口和上下文(entry and context))
  • 原文地址:https://www.cnblogs.com/wyb666/p/9573807.html
Copyright © 2011-2022 走看看