Django——回顾

Django 复习
一、如何建立配置Django
1.创建django项目

djangoadmin startproject mysite

目录介绍

mysite/
├── manage.py # 管理文件
└── mysite # 项目目录
├── init.py
├── settings.py # 配置
├── urls.py # 路由 --> URL和函数的对应关系
└── wsgi.py # runserver命令就使用wsgiref模块做简单的web server
2.运行Django项目

python3 manage.py runserver
3.模板文件配置

TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, "template")], # template文件夹位置
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},]
4.静态文件配置

STATIC_URL = '/static/' # HTML中使用的静态文件夹前缀
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static"), # 静态文件存放位置]
二、Django基础必备的三板斧

  1. 导入文件

from django.shortcuts import HttpResponse, render, redirect
2.三板斧
2.1 HttpResponse : 内部传入字符串参数,返回给浏览器

def index(request):
# 业务逻辑代码
return HttpResponse("OK")
2.2 render : 除request参数外还接受一个待渲染的模板文件和一个保存具体数据的字典参数。将数据填充进模板文件,最后把结果返回给浏览器。

def index(request):
# 业务逻辑代码
return render(request, "index.html", {"name": "alex", "hobby": ["烫头", "泡吧"]})
2.3 redirect : 接受一个URL参数,表示跳转到指定的URL。

def index(request):
# 业务逻辑代码
return redirect("/home/")
三、路由层

  1. URLconf配置

Django 1.0

from django.conf.urls import url

urlpatterns = [
url(正则表达式, views视图函数,参数,别名),]

Django 2.0

from django.urls import path

urlpatterns = [
path('articles/2003/', views.special_case_2003),
path('articles/ /', views.year_archive),
path('articles/ / /', views.month_archive),
path('articles/ / / /', views.article_detail),]
1.1 参数说明
正则表达式:一个正则表达式字符串

views视图函数:一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串

参数:可选的要传递给视图函数的默认参数(字典形式)

别名:一个可选的name参数

  1. 路由分发 (include)

from django.conf.urls import include, url

urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^blog/', include('blog.urls')), # 可以包含其他的URLconfs文件]
3.0 反向解析
例子:

路由配置

url(r'^home', views.home, name='home'), # 给我的url匹配模式起名为 home
url(r'^index/(\d*)', views.index, name='index'), # 给我的url匹配模式起名为index
模板里面引用

{% url 'home' %}
views 函数中引用

from django.urls import reverse

reverse("index", args=("2018", ))

  1. 名称空间模式
    即使不同的APP使用相同的URL名称,URL的命名空间模式也可以让你唯一反转命名的URL。

例子:

project中的urls.py

from django.conf.urls import url, include

urlpatterns = [
url(r'^app01/', include('app01.urls', namespace='app01')),
url(r'^app02/', include('app02.urls', namespace='app02')),]
app01中的urls.py

from django.conf.urls import url
from app01 import views

app_name = 'app01'
urlpatterns = [
url(r'^(?P \d+)/$', views.detail, name='detail')]
app02中的urls.py

from django.conf.urls import url
from app02 import views

app_name = 'app02'
urlpatterns = [
url(r'^(?P \d+)/$', views.detail, name='detail')]
现在,我的两个app中 url名称重复了,我反转URL的时候就可以通过命名空间的名称得到我当前的URL。

模板中使用

{% url 'app01:detail' pk=12 pp=99 %}
views中的函数中使用

v = reverse('app01:detail', kwargs={'pk':11})
这样即使app中URL的命名相同,我也可以反转得到正确的URL了。

四. 视图层
一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应。

响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片。

无论视图本身包含什么逻辑,都要返回响应。代码写在哪里也无所谓,只要它在你当前项目目录下面。除此之外没有更多的要求了——可以说“没有什么神奇的地方”。为了将代码放在某处,大家约定成俗将视图放置在项目(project)或应用程序(app)目录中的名为views.py的文件中。

参考地址:https://www.cnblogs.com/Dominic-Ji/articles/10982298.html

五、模板层
常用语法:
只需要记两种特殊符号:
{{ }}和 {% %}

变量相关的用{{}},逻辑相关的用{%%}。

变量
在Django的模板语言中按此语法使用:{{ 变量名 }}。

当模版引擎遇到一个变量,它将计算这个变量,然后用结果替换掉它本身。 变量的命名包括任何字母数字以及下划线 ("_")的组合。 变量名称中不能有空格或标点符号。

例子

def template_test(request):
l = [11, 22, 33]
d = {"name": "alex"}

class Person(object):
def init(self, name, age):
self.name = name
self.age = age

def dream(self):
return "{} is dream...".format(self.name)

Alex = Person(name="Alex", age=34)
Egon = Person(name="Egon", age=9000)
Eva_J = Person(name="Eva_J", age=18)

person_list = [Alex, Egon, Eva_J]
return render(request, "template_test.html", {"l": l, "d": d, "person_list": person_list})
模板中支持的写法

{# 取l中的第一个参数 #}
{{ l.0 }}
{# 取字典中key的值 #}
{{ d.name }}
{# 取对象的name属性 #}
{{ person_list.0.name }}
{# .操作只能调用不带参数的方法 #}
{{ person_list.0.dream }}

  1. Filter
    过滤器的语法: {{ value|filter_name:参数 }}

deault:如果一个变量是false或者为空,使用给定的默认值。 否则,使用变量的值。

{{ value|default:"nothing"}}

length: 返回值的长度,作用于字符串和列表

{{ value|length }}

返回value的长度,如 value=['a', 'b', 'c', 'd']的话,就显示4.

filesizeformat:将值格式化为一个 “人类可读的” 文件尺寸 (例如 '13 KB', '4.1 MB', '102 bytes', 等等)

{{ value|filesizeformat }}
如果 value 是 123456789,输出将会是 117.7 MB。

slice :切片

{{value|slice:"2:-1"}}

date: 格式化

{{ value|date:"Y-m-d H:i:s"}}

safe : 转义

value = "点我"

{{ value|safe}}

truncatechars:如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾。

参数:截断的字符数

{{ value|truncatechars:9}}

truncatewords: 在一定数量的字后截断字符串。

{{ value|truncatewords:9}}

cut:移除value中所有的与给出的变量相同的字符串

{{ value|cut:' ' }}

  1. filter

    for 循环

    {% for user in user_list %}
  • {{ user.name }}
  • {% endfor %}

forloop.counter 当前循环的索引值(从1开始)
forloop.counter0 当前循环的索引值(从0开始)
forloop.revcounter 当前循环的倒序索引值(从1开始)
forloop.revcounter0 当前循环的倒序索引值(从0开始)
forloop.first 当前循环是不是第一次循环(布尔值)
forloop.last 当前循环是不是最后一次循环(布尔值)
forloop.parentloop 本层循环的外层循环

if

{% if user_list %}
用户人数:{{ user_list|length }}
{% elif black_list %}
黑名单数:{{ black_list|length }}
{% else %}
没有用户
{% endif %}

with : 定义一个中间变量,多用于给一个复杂的变量起别名。

{% with total=business.employees.count %}
{{ total }} employee{{ total|pluralize }}
{% endwith %}

{% with business.employees.count as total %}
{{ total }} employee{{ total|pluralize }}
{% endwith %}

  1. 继承
    母板

<!DOCTYPE html>





Title
{% block page-css %}

{% endblock %}



这是母板的标题



{% block page-main %}

{% endblock %}

母板底部内容


{% block page-js %}

{% endblock %}


继承母板

{% extends 'layouts.html' %}
块:通过在母板中使用{% block xxx %}来定义"块"。

在子页面中通过定义母板中的block名来对应替换母板中相应的内容。

{% block page-main %}

世情薄


人情恶


雨送黄昏花易落


{% endblock %}
组件 : 可以将常用的页面内容如导航条,页尾信息等组件保存在单独的文件中,然后在需要使用的地方按如下语法导入即可。

{% include 'navbar.html' %}
静态文件

{% load static %}
<img src="{% static "images/hi.jpg" %}" alt="Hi!" />
六、Django ORM

  1. 常用字段

    AutField

int自增列,必须填入参数 primary_key=True。当model中如果没有自增列,则自动会创建一个列名为id的列。

InterField

一个整数类型,范围在 -2147483648 to 2147483647。(一般不用它来存手机号(位数也不够),直接用字符串存,)

CharField

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

自定义字段

from django.db import models

Create your models here.

Django中没有对应的char类型字段,但是我们可以自己创建

class FixCharField(models.Field):
'''
自定义的char类型的字段类
'''
def init(self,max_length,*args,**kwargs):
self.max_length=max_length
super().__init__(max_length=max_length,*args,**kwargs)

def db_type(self, connection):
'''
限定生成的数据库表字段类型char,长度为max_length指定的值
:param connection:
:return:
'''
return 'char(%s)'%self.max_length

应用上面自定义的char类型

class Class(models.Model):
id=models.AutoField(primary_key=True)
title=models.CharField(max_length=32)
class_name=FixCharField(max_length=16)
gender_choice=((1,'男'),(2,'女'),(3,'保密'))
gender=models.SmallIntegerField(choices=gender_choice,default=3)

自定义及使用
2.字段合集

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

对应关系:
'AutoField': 'integer AUTO_INCREMENT',
'BigAutoField': 'bigint AUTO_INCREMENT',
'BinaryField': 'longblob',
'BooleanField': 'bool',
'CharField': 'varchar(%(max_length)s)',
'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
'DateField': 'date',
'DateTimeField': 'datetime',
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
'DurationField': 'bigint',
'FileField': 'varchar(%(max_length)s)',
'FilePathField': 'varchar(%(max_length)s)',
'FloatField': 'double precision',
'IntegerField': 'integer',
'BigIntegerField': 'bigint',
'IPAddressField': 'char(15)',
'GenericIPAddressField': 'char(39)',
'NullBooleanField': 'bool',
'OneToOneField': 'integer',
'PositiveIntegerField': 'integer UNSIGNED',
'PositiveSmallIntegerField': 'smallint UNSIGNED',
'SlugField': 'varchar(%(max_length)s)',
'SmallIntegerField': 'smallint',
'TextField': 'longtext',
'TimeField': 'time',
'UUIDField': 'char(32)',

ORM字段与MySQL字段对应关系

  1. 字段参数
    null
    用于表示某个字段可以为空。

unique
如果设置为unique=True 则该字段在此表中必须是唯一的 。

db_index

如果db_index=True 则代表着为此字段设置索引。

default
为该字段设置默认值。

  1. DateField 和DateField

auto_now_add
配置auto_now_add=True,创建数据记录的时候会把当前时间添加到数据库。

auto_now
配置上auto_now=True,每次更新数据记录的时候会更新该字段。

  1. ForeignKey
    外键类型在ORM中用来表示外键关联关系,一般把ForeignKey字段设置在 '一对多'中'多'的一方。

ForeignKey可以和其他表做关联关系同时也可以和自身做关联关系

5.1 字段参数

to : 设置要关联的表

to_field:设置要关联的字段

on_delete: 当删除关联数据时,当前表与其关联的行为

db_constraint:是否在数据库中创建外键约束,默认是True

设置:models.SET(可执行对象)

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)
)

  1. OneToOneField
    一对一字段

通常一对一字段用来扩展已有字段。(通俗的说就是一个人的所有信息不是放在一张表里面的,简单的信息一张表,隐私的信息另一张表,之间通过一对一外键关联

6.1 字段参数
to

设置要关联的表。

to_field

设置要关联的字段。

on_delete

当删除关联表中的数据时,当前表与其关联的行的行为。(参考上面的例子)

6.2 必会13条

返回QuerySet对象的方法有
all()

filter()

exclude()

order_by()

reverse()

distinct()

特殊的QuerySet
values() 返回一个可迭代的字典序列

values_list() 返回一个可迭代的元祖序列

返回具体对象的
get()

first()

last()

返回布尔值的方法有:
exists()

返回数字的方法有
count()
6.3神奇的下划线操作

models.Tb1.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值

models.Tb1.objects.filter(id__in=[11, 22, 33]) # 获取id等于11、22、33的数据
models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in

models.Tb1.objects.filter(name__contains="ven") # 获取name字段包含"ven"的
models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感

models.Tb1.objects.filter(id__range=[1, 3]) # id范围是1到3的,等价于SQL的bettwen and

类似的还有:startswith,istartswith, endswith, iendswith 

date字段还可以:
models.Class.objects.filter(first_day__year=2017)
date字段可以通过在其后加__year,__month,__day等来获取date的特点部分数据

date

    #
    # Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
    # Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))


# year
#
# Entry.objects.filter(pub_date__year=2005)
# Entry.objects.filter(pub_date__year__gte=2005)

# month
#
# Entry.objects.filter(pub_date__month=12)
# Entry.objects.filter(pub_date__month__gte=6)

# day
#
# Entry.objects.filter(pub_date__day=3)
# Entry.objects.filter(pub_date__day__gte=3)

# week_day
#
# Entry.objects.filter(pub_date__week_day=2)
# Entry.objects.filter(pub_date__week_day__gte=2)
需要注意的是在表示一年的时间的时候,我们通常用52周来表示,因为天数是不确定的,老外就是按周来计算薪资的哦~

集锦

  1. ForeignKey 操作
    7.1 正向查找(跨表)

1. 对象查找(跨表)

语法: 对象.关联字段.字段

要点: 先拿到对象,再通过对象去查对应的外键字段

book_obj = models.Book.objects.first() # 第一本书对象(第一步)
print(book_obj.publisher) # 得到这本书关联的出版社对象
print(book_obj.publisher.name) # 得到出版社对象的名称

2. 字段查找(跨表)

语法: 关联字段__字段

要点:利用Django给我们提供的神奇的双下划线查找方式

models.Book.objects.all().values("publisher__name")

拿到所有数据对应的出版社的名字,神奇的下划线帮我们夸表查询


7.2 反向查找(跨表)

对象查找:

语法:obj.表名_set

要点:先拿到外键关联多对一,一中的某个对象,由于外键字段设置在多的一方,所以这里还是借用Django提供的双下划线来查找

publisher_obj = models.Publisher.objects.first() # 找到第一个出版社对象
books = publisher_obj.book_set.all() # 找到第一个出版社出版的所有书
titles = books.values_list("title") # 找到第一个出版社出版的所有书的书名
结论:如果想通过一的那一方去查找多的一方,由于外键字段不在一这一方,所以用__set来查找即可

字段查找

语法:表名__字段

要点:直接利用双下滑线完成夸表操作

titles = models.Publisher.objects.values("book__title")

  1. ManyToManyField
    8.1关联管理器:是在一对多或者多对多的关联上下文的管理器
    存在下面两种情况:

① 外键关系反向查询

② 多对多关联关系

简单来说就是在多对多表关系并且这一张多对多的关系表是有Django自动帮你建的情况下,下面的方法才可使用。

create():

创建一个关联对象,并自动写入数据库,且在第三张双方的关联表中自动新建上双方对应关系。

models.Author.objects.first().book_set.create(title="偷塔秘籍")
上面这一句干了哪些事儿:
1.由作者表中的一个对象跨到书籍比表
2.新增名为偷塔秘籍的书籍并保存
3.到作者与书籍的第三张表中新增两者之间的多对多关系并保存
add():

把指定的model对象添加到第三张关联表中。

添加对象:

author_objs = models.Author.objects.filter(id__lt=3)
models.Book.objects.first().authors.add(*author_objs)
添加id:

models.Book.objects.first().authors.add(*[1, 2])
set()

更新某个对象在第三张表中的关联对象。不同于上面的add是添加,set相当于重置

book_obj = models.Book.objects.first()
book_obj.authors.set([2, 3])
remove()

从关联对象集中移除执行的model对象(移除对象在第三张表中与某个关联对象的关系)

book_obj = models.Book.objects.first()
book_obj.authors.remove(3)
clear()
从关联对象集中移除一切对象。(移除所有与对象相关的关系信息)

book_obj = models.Book.objects.first()
book_obj.authors.clear()
注意:

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

2.对于所有类型的关联字段,add()、create()、remove()和clear(),set()都会马上更新数据库。换句话说,在关联的任何一端,都不需要再调用save()方法。

9.聚合查询和分组查询
9.1 聚合查询(利用聚合函数)
aggregate()是QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。

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

用到的函数

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

from django.db.models import Avg, Sum, Max, Min, Count
models.Book.objects.all().aggregate(Avg("price"))
{'price__avg': 13.233333}
重命名

models.Book.objects.aggregate(average_price=Avg('price'))
{'average_price': 13.233333}
多个函数:

models.Book.objects.all().aggregate(Avg("price"), Max("price"), Min("price"))
{'price__avg': 13.233333, 'price__max': Decimal('19.90'), 'price__min': Decimal('9.90')}
9.2 分组查询

from django.db.models import Avg
models.Dept.objects.annotate(avg=Avg("employee__salary")).values("name", "avg")
总结
value里面的参数对应的是sql语句中的select要查找显示的字段,

filter里面的参数相当于where或者having里面的筛选条件

annotate本身表示group by的作用,前面找寻分组依据,内部放置显示可能用到的聚合运算式,后面跟filter来增加限制条件,最后的value来表示分组后想要查找的字段值

  1. F查询和Q查询
    10.1 F查询
    当查询条件来自数据库的某个字段,这时候必须使用F

使用方法

先导入F Q查询的库

from django.db.modles import F

当卖出的数大于库存数的商品

res = models.Product.objects.filter(maichu__gt = F('kucun'))

将所有的商品价格提高100块

models.Product.objects.update(price=F('price')+100)

将所有的商品的名字后面加上爆款

from django.db.models.functions import Concat
from django.db.models import Value

modles.Product.objects.update(Concat(F('name'),Value('爆款')))
Q 查询

filter()等方法中逗号隔开的条件是与的关系。 如果你需要执行更复杂的查询(例如OR语句),你可以使用Q对象`。

当查询条件想以或的关系查询时候

查询书名火影忍者或者价格为89.99的

models.Product.objects.filter(Q(name='火影忍者')|Q(price=89.99))

Q与普通条件混用

models.product.objects.filter(Q(name='火影忍者'),price=89.99)
我们可以组合& 和| 操作符以及使用括号进行分组来编写任意复杂的Q 对象。

同时,Q 对象可以使用~ 操作符取反,这允许组合正常的查询和取反(NOT) 查询。

  1. 事务:
    原子性

完整性

一致性

from django.db import transaction
with transaction.atomic():
# 内部写多个数据库操作
print('其他逻辑')
建立表的三种方式

第一种:Django ORM自动创建

class Book(models.Model):
name = models.Charfied(max_length=32)
authors = models.ManyToManyField(to='Author')

class Author(models.Model):
name = models.CharField(max_length=32)

第二种:纯手动创建第三张表(可拓展,但是不支持orm查询)

class Book(models.Model):
name= models.CharField(max_length=32)

class Author(models.Model):
name = models.CharField(max_length=32)

class Book2Author(models.Model)
book = models.ForeignKey(to='Book')
author = models.ForeignKey(to='Author')
info = models.CharField(max_length=32)

第三种:半自动创建第三张表(可拓展性比较高,并且符合orm查询)

class Book(models.Model):
name = models.CharField(max_length=32)

class Author(models.Model):
name = models.CharField(max_length=32)

class Book2Author(models.Model):
book = models.ForeignKey(to='Book')
author = models.Foreignkey(to='author')
info = models.CharField(max_length=32)
七、Django 与Ajax

  1. Ajax 前期准备知识
    urlencoded:
    对应的数据格式:name=Jason&password=666
    ​ 后端获取数据:request.post
    ​ ps : django 会将urlencoded 编码的数据解析自动放到request.POST

formdata:
form表单传输文件的编码格式
​ 后端获取文件的格式数据:request.FILES
​ 后端获取普通键值对数据:request.POST

application/json
ajax 发送json格式数据
​ 需要注意的是:编码与数据格式要一致

  1. Ajax属性
    前端有哪些向后端提交请求的方式

浏览器窗口手动输入网址 get请求

a标签的href属性 get请求

form表单 get/post请求(默认get请求)

ajax get/post请求

ajax特点

异步提交

局部刷新

  1. 基本语法

$('#d1').click(function)(){
$.ajax({
url:'/index/' //提交地址
type:'post', //提交方式
data:{'name':'jason','password':'123'}, //提交的数据
success:function(data){
alert(data) //data接收的就是异步提交返回结果
}
})
}

ajax默认的数据传输方式也是urlencoded

  1. Ajax 默认语法是json格式

ipt>



  1. ajax上传文件

$('#d1').click(function () {
let formdata = new FormData();
// Formdata 对象不仅仅可以传文件还可以传普通键值对
formdata.append('name','jason');
// 获取input框存放的文件 $('#i1).files[0]
formdata.append('myfile',$('#i1')[0].files[0]);
$.ajax({
url:'',
tyoe:'post',
data:formdata,
//发送文件需要修改两个固定参数
processData:false,
contentType:false,
//回调函数
success:function (data) {
alert(data)
}
})

})
6 form表单与ajax的异同点
form表单不支持异步提交局部刷新

form表单不支持传输json格式

form表单与ajax默认传输数据的编码格式都是urlencoded

  1. 自定义分页器
    先创建untils 文件夹,里面建文件page.py 文件
  • class Pagination(object):
    def init(self, current_page, all_count, per_page_num=2, pager_count=11):
    """
    封装分页相关数据
    :param current_page: 当前页
    :param all_count: 数据库中的数据总条数
    :param per_page_num: 每页显示的数据条数
    :param pager_count: 最多显示的页码个数

    用法:
    queryset = model.objects.all()
    page_obj = Pagination(current_page,all_count)
    page_data = queryset[page_obj.start:page_obj.end]
    获取数据用page_data而不再使用原始的queryset
    获取前端分页样式用page_obj.page_html
    """
    try:
    current_page = int(current_page)
    except Exception as e:
    current_page = 1

    if current_page < 1:
    current_page = 1

    self.current_page = current_page

    self.all_count = all_count
    self.per_page_num = per_page_num

    # 总页码
    all_pager, tmp = divmod(all_count, per_page_num)
    if tmp:
    all_pager += 1
    self.all_pager = all_pager

    self.pager_count = pager_count
    self.pager_count_half = int((pager_count - 1) / 2)

    @property
    def start(self):
    return (self.current_page - 1) * self.per_page_num

    @property
    def end(self):
    return self.current_page * self.per_page_num

    def page_html(self):
    # 如果总页码 < 11个:
    if self.all_pager <= self.pager_count:
    pager_start = 1
    pager_end = self.all_pager + 1
    # 总页码 > 11
    else:
    # 当前页如果<=页面上最多显示11/2个页码
    if self.current_page <= self.pager_count_half:
    pager_start = 1
    pager_end = self.pager_count + 1

    # 当前页大于5
    else:
    # 页码翻到最后
    if (self.current_page + self.pager_count_half) > self.all_pager:
    pager_end = self.all_pager + 1
    pager_start = self.all_pager - self.pager_count + 1
    else:
    pager_start = self.current_page - self.pager_count_half
    pager_end = self.current_page + self.pager_count_half + 1

    page_html_list = []
    # 添加前面的nav和ul标签
    page_html_list.append('''
    <nav aria-label='Page navigation>'

      ''')
      first_page = '
    • 首页
    • ' % (1)
      page_html_list.append(first_page)

      if self.current_page <= 1:
      prev_page = '
    • 上一页
    • '
      else:
      prev_page = '
    • 上一页
    • ' % (self.current_page - 1,)

      page_html_list.append(prev_page)

      for i in range(pager_start, pager_end):
      if i == self.current_page:
      temp = '
    • %s
    • ' % (i, i,)
      else:
      temp = '
    • %s
    • ' % (i, i,)
      page_html_list.append(temp)

      if self.current_page >= self.all_pager:
      next_page = '
    • 下一页
    • '
      else:
      next_page = '
    • 下一页
    • ' % (self.current_page + 1,)
      page_html_list.append(next_page)

      last_page = '
    • 尾页
    • ' % (self.all_pager,)
      page_html_list.append(last_page)
      # 尾部添加标签
      page_html_list.append('''


    ''')
    return ''.join(page_html_list)
    导入 my_page.py

from app01.utils import my_page
自定义分页器的使用

后端

book_list = models.Book.objects.all()

数据总条数

all_count = book_list.count()

当前页

current_page = request.GET.get('page',1)

示例分页器对象_count

page_obj = mypage.Pagination(current_page=current_page, all_count= all_count )

对数据进行切片

page_queryset = bool_list[page_obj.start:page_obj.end]

前端

前端

{{ page_obj.page_html|safe }} # 帮你渲染的是带有bootstrap样式的分页器

猜你喜欢

转载自www.cnblogs.com/king-home/p/11031788.html
今日推荐