首页 > 技术文章 > 聚合查询、分组查询、事务、ORM中常用字段及参数、choices参数、多对多创建方式、Ajax介绍

jgx0 2022-03-04 19:19 原文

昨日内容回顾

  • 外键字段的增删改查
# 一对一 一对多
	增:
	先查询数据的对象
		publish=跟对象
		publish_id=具体的id值
        
# 多对多
	1. 先有数据的对象
	2. 使用对象点外键字段
    
	# 增
		add(1, 2, 3)
		add(obj1, obj2, obj3)

	# 改
		set([1, 2, 3])
		set([obj1, obj2, obj3])

	# 删
		remove(1, 2)

	# 清除
		clear()
  • 正反向查询
1. 正向
2. 反向
'''
	判断依据就是看外键字段在哪里?
	如果外键字段在我手里,我查你就是正向
	如果外键字段不再我手里,我查你就是反向查询
'''

# 1. 正向查询按字段(外键字段)
# 2. 反向查询按表名小写(或者添加 _set.all())
  • 基于对象的跨表查询
# 子查询
	1. 判断是谁查谁
	2. 判断正向还是反向
	3. 根据正反向查询的依据执行代码
  • 基于双下划线的查询
# 一条SQL语句解决
	.values('')

# 连表操作
	inner join left join right join union
  • F和Q查询
# F查询是可以拿到字段的原始数据值
	update t set price = price + 100,  where id=1;

	from django.db.models import F
	res = Book.objects.update(price=F('price')+100)

# F默认操作的是数字类型的,对于字符串的话,不能直接使用
	from django.db.models.functions import Concat
	from django.db.models import Value
	res = Book.objects.update(title=Concat(F('title'), Value('aaaa')))

    
# Q查询
	Q查询支持3种方式
		1. and
		2. or
		3. 非

	filter(Q(price__gt=100), Q(id=1)) # and 关系
	filter(Q(price__gt=100) | Q(id=1)) # or 关系
	filter(~Q(price__gt=100), ~Q(id=1)) # 非 关系(取反)

# Q的高级查询
	q = Q()
	q.connector='OR'
	q.children.append(('title', 'aaa'))
	q.children.append(('price__gt', 200))

	res = models.Book.objects.fileter(q)
	print(res)

今日内容概要

  • 聚合查询和分组查询
  • 事务
  • ORM中常用的参数
  • choices参数
  • 批量增加数据
  • 多对多的三种创建方式
  • Ajax的基本使用
  • Ajax提交文件数据

内容详细

1. 聚合查询

# 数据准备同上期
# 聚合查询关键字:aggregate
# 在tests.py文件中测试:

    # 聚合查询
    from django.db.models import Max, Min, Sum, Count, Avg

    # 1.查询数据中价格最高的
    # SQL语句:select max(price) from book
    # orm中使用聚合查询关键字:aggregate
    # res = models.Book.objects.aggregate(Max('price'))
    # res1 = models.Book.objects.aggregate(max_price=Max('price'))  # 起别名
    # print(res)  # {'price__max': Decimal('600.00')}
    # print(res1)  # {'max_price': Decimal('600.00')}

    # 2.查询所有书籍的总价格
    # SQL语句:select sum(price) as sum_price from book  # 起别名 as sum_price
    # SQL语句:select sum(price) as sum_price, min(price) as min_price from book  # 查询多个数据分别起别名
    # res = models.Book.objects.aggregate(sum_price=Sum('price'))
    # print(res)  # {'sum_price': Decimal('1511.00')}

    # 3.查询所有书籍的平均价格
    # SQL语句:select avg(price) as avg_price from book
    # res = models.Book.objects.aggregate(avg_price=Avg('price'))
    # print(res)  # {'avg_price': 377.75}

    # 4.一起使用
    # res = models.Book.objects.aggregate(max_price=Max('price'), min_price=Min('price'), sum_price=Sum('price'), avg_price=Avg('price'))
    # print(res)  # {'max_price': Decimal('600.00'), 'min_price': Decimal('211.00'), 'sum_price': Decimal('1511.00'), 'avg_price': 377.75}

image

2. 分组查询

# 关键字:group by
	select * from t group by price, title,
	'''分组之后只能拿到分组的依据'''

	1. group_concat: 分组之后用
	2. concat: 分组之前使用
	3. concat_ws:
		select concat(title,":",age,":", gender,":") from t 
		select concat_ws(':', title, age, gender) from t;
   
# 在tests.py文件中测试:
    # ORM中使用分组关键字:annotate
    # 1.统计每一本书的作者个数
    # res = models.Book.objects.annotate()  # 代表按照书籍分组
    # res = models.Book.objects.annotate(author_num=Count('authors__pk')).values('title', 'author_num')
    # print(res)  # <QuerySet [{'title': '西游记', 'author_num': 1}, {'title': '西游记1', 'author_num': 1}, {'title': '红楼梦', 'author_num': 2}, {'title': '三国演义', 'author_num': 2}]>

    # 2.统计每个出版社出版的最便宜的书的价格
    # res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name', 'min_price')
    # print(res)  # <QuerySet [{'name': '北京大学出版社', 'min_price': Decimal('300.00')}, {'name': '清华大学出版社', 'min_price': Decimal('211.00')}, {'name': '武汉大学出版社', 'min_price': Decimal('400.00')}]>

    # 3.统计不止一个作者的书
    # 01 先查询出每本书的作者个数
    # 02 再筛选掉小于等于一的
    # res = models.Book.objects.annotate(author_num=Count('authors__pk')).values('title', 'author_num')
    # print(res)  # <QuerySet [{'title': '西游记', 'author_num': 1}, {'title': '西游记1', 'author_num': 1}, {'title': '红楼梦', 'author_num': 2}, {'title': '三国演义', 'author_num': 2}]>
    # res1 = models.Book.objects.annotate(author_num=Count('authors__pk')).filter(author_num__gt=1).values('title', 'author_num')
    # print(res1)  # <QuerySet [{'title': '红楼梦', 'author_num': 2}, {'title': '三国演义', 'author_num': 2}]>

    # 4.查询各个作者出的书的总价格
    # res = models.Author.objects.annotate(sum_price=Sum('book__price')).values('name', 'sum_price')
    # print(res)  # <QuerySet [{'name': 'beijing', 'sum_price': Decimal('700.00')}, {'name': 'qinghua', 'sum_price': Decimal('1211.00')}, {'name': 'wuhan', 'sum_price': Decimal('600.00')}]>

image

image

image

3. 事务

# 作用:保证数据安全
'''
面试题:
	四大特性:ACID
	事务的隔离级别
'''

# 1. 开启事务:
	start transaction;
    
# 2. 提交事务
	commit;
    
# 3. 回滚事务
	rollback;
    
    
# 在tests.py文件中测试:
    """通过django开启事物"""
    from django.db import transaction

    try:
        # 执行的SQL语句
        with transaction.Atomic:
            # sql语句
            # sql语句
            # 写在里面都属于同一个事物
            pass
    except Exception as e:
        print(e)
        transaction.rollback()

4. ORM中常用字段和参数

4.1 ORM字段

AutoField

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

IntegerField

一个整数类型,范围在 -2147483648 to 2147483647。

CharField

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

DateField

日期字段,日期格式 YYYY-MM-DD,相当于Python中的datetime.date()实例。

DateTimeField

日期时间字段,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],相当于Python中的datetime.datetime()实例

常用和非常用字段

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

4.2 ORM字段参数

null

用于表示某个字段可以为空。

unique

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

db_index

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

default

为该字段设置默认值。

DateField和DateTimeField

auto_now_add

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

auto_now

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

null                数据库中字段是否可以为空
    db_column           数据库中字段的列名
    db_tablespace
    default             数据库中字段的默认值
    primary_key         数据库中字段是否为主键
    db_index            数据库中字段是否可以建立索引
    unique              数据库中字段是否可以建立唯一索引
    unique_for_date     数据库中字段【日期】部分是否可以建立唯一索引
    unique_for_month    数据库中字段【月】部分是否可以建立唯一索引
    unique_for_year     数据库中字段【年】部分是否可以建立唯一索引

    verbose_name        Admin中显示的字段名称
    blank               Admin中是否允许用户输入为空
    editable            Admin中是否可以编辑
    help_text           Admin中该字段的提示信息
    choices             Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
                        如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1)

    error_messages      自定义错误信息(字典类型),从而定制想要显示的错误信息;
                        字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date
                        如:{'null': "不能为空.", 'invalid': '格式错误'}

    validators          自定义错误验证(列表类型),从而定制想要的验证规则
                        from django.core.validators import RegexValidator
                        from django.core.validators import EmailValidator,URLValidator,DecimalValidator,\
                        MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator
                        如:
                            test = models.CharField(
                                max_length=32,
                                error_messages={
                                    'c1': '优先错信息1',
                                    'c2': '优先错信息2',
                                    'c3': '优先错信息3',
                                },
                                validators=[
                                    RegexValidator(regex='root_\d+', message='错误了', code='c1'),
                                    RegexValidator(regex='root_112233\d+', message='又错误了', code='c2'),
                                    EmailValidator(message='又错误了', code='c3'), ]
                            )

4.3 关系字段

ForeignKey

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

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

to

设置要关联的表

to_field

设置要关联的表的字段

反向操作时,使用的字段名,用于代替原反向查询时的'表名_set'。

例如:

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

class Student(models.Model):
    name = models.CharField(max_length=32)
    theclass = models.ForeignKey(to="Classes")

当我们要查询某个班级关联的所有学生(反向查询)时,我们会这么写:

models.Classes.objects.first().student_set.all()

当我们在 ForeignKey 字段中添加了参数 related_name 后,

class Student(models.Model):
    name = models.CharField(max_length=32)
    theclass = models.ForeignKey(to="Classes", related_name="students")

当我们要查询某个班级关联的所有学生(反向查询)时,我们会这么写:

models.Classes.objects.first().students.all()

反向查询操作时,使用的连接前缀,用于替换表名。

on_delete

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

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

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

OneToOneField

一对一字段。

通常一对一字段用来扩展已有字段。

一对一的关联关系多用在当一张表的不同字段查询频次差距过大的情况下,将本可以存储在一张表的字段拆开放置在两张表中,然后将两张表建立一对一的关联关系。

class Author(models.Model):
    name = models.CharField(max_length=32)
    info = models.OneToOneField(to='AuthorInfo')
    

class AuthorInfo(models.Model):
    phone = models.CharField(max_length=11)
    email = models.EmailField()
to

设置要关联的表。

to_field

设置要关联的字段。

on_delete

同ForeignKey字段。

ManyToManyField

用于表示多对多的关联关系。在数据库中通过第三张表来建立关联关系

to

设置要关联的表

同ForeignKey字段。

同ForeignKey字段。

symmetrical

仅用于多对多自关联时,指定内部是否创建反向操作的字段。默认为True。

举个例子:

class Person(models.Model):
    name = models.CharField(max_length=16)
    friends = models.ManyToManyField("self")

此时,person对象就没有person_set属性。

class Person(models.Model):
    name = models.CharField(max_length=16)
    friends = models.ManyToManyField("self", symmetrical=False)

此时,person对象现在就可以使用person_set属性进行反向查询。

through

在使用ManyToManyField字段时,Django将自动生成一张表来管理多对多的关联关系。

但我们也可以手动创建第三张表来管理多对多关系,此时就需要通过through来指定第三张表的表名。

through_fields

设置关联的字段。

db_table

默认创建第三张表时,数据库中表的名称。

4.4 多对多关联关系的三种方式

方式一:自行创建第三张表

class Book(models.Model):
    title = models.CharField(max_length=32, verbose_name="书名")


class Author(models.Model):
    name = models.CharField(max_length=32, verbose_name="作者姓名")


# 自己创建第三张表,分别通过外键关联书和作者
class Author2Book(models.Model):
    author = models.ForeignKey(to="Author")
    book = models.ForeignKey(to="Book")

    class Meta:
        unique_together = ("author", "book")

方式二:通过ManyToManyField自动创建第三张表

class Book(models.Model):
    title = models.CharField(max_length=32, verbose_name="书名")


# 通过ORM自带的ManyToManyField自动创建第三张表
class Author(models.Model):
    name = models.CharField(max_length=32, verbose_name="作者姓名")
    books = models.ManyToManyField(to="Book", related_name="authors")

方式三:设置ManyTomanyField并指定自行创建的第三张表

class Book(models.Model):
    title = models.CharField(max_length=32, verbose_name="书名")


# 自己创建第三张表,并通过ManyToManyField指定关联
class Author(models.Model):
    name = models.CharField(max_length=32, verbose_name="作者姓名")
    books = models.ManyToManyField(to="Book", through="Author2Book", through_fields=("author", "book"))
    # through_fields接受一个2元组('field1','field2'):
    # 其中field1是定义ManyToManyField的模型外键的名(author),field2是关联目标模型(book)的外键名。


class Author2Book(models.Model):
    author = models.ForeignKey(to="Author")
    book = models.ForeignKey(to="Book")

    class Meta:
        unique_together = ("author", "book")

注意:

当我们需要在第三张关系表中存储额外的字段时,就要使用第三种方式。

但是当我们使用第三种方式创建多对多关联关系时,就无法使用set、add、remove、clear方法来管理多对多的关系了,需要通过第三张表的model来管理多对多关系。

4.5 元信息

ORM对应的类里面包含另一个Meta类,而Meta类封装了一些数据库的信息。主要字段如下:

db_table

ORM在数据库中的表名默认是 app_类名,可以通过db_table可以重写表名。

index_together

联合索引。

unique_together

联合唯一索引。

ordering

指定默认按什么字段排序。

只有设置了该属性,我们查询到的结果才可以被reverse()。

    class UserInfo(models.Model):
        nid = models.AutoField(primary_key=True)
        username = models.CharField(max_length=32)

        class Meta:
            # 数据库中生成的表名称 默认 app名称 + 下划线 + 类名
            db_table = "table_name"

            # 联合索引
            index_together = [
                ("pub_date", "deadline"),
            ]

            # 联合唯一索引
            unique_together = (("driver", "restaurant"),)
            
            ordering = ('name',)
            
            # admin中显示的表名称
            verbose_name='哈哈'

            # verbose_name加s
            verbose_name_plural=verbose_name

4.6 自定义字段(了解)

自定义char类型字段:

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

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


class Class(models.Model):
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=25)
    # 使用自定义的char类型的字段
    cname = FixedCharField(max_length=25)

5. choices参数

eg:
    性别
    学历
    来源   
# 针对与这种可以列举完的可能性,我们就可以使用choices参数


# 在models.py中创建表:
class User(models.Model):
    name = models.CharField(max_length=32)
    # gender = models.IntegerField()
    gender_choices = (
        (1, '男'),
        (2, '女'),
        (3, '其他'),
    )
    '''
    对于choices参数,数据类型该怎么选?
        判断依据是:小元组里面第一个参数的数据类型
    '''
    gender = models.IntegerField(choices=gender_choices)
    """
	####字符串类型的#####
	score_choices = (
        ('A', '优秀'),
        ('B', '良好'),
        ('C', '及格'),
        ('D', '不及格'),
    )
    
    score = models.CharField(max_length=8)
    """

    
# 在tests.py中测试:
import os

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite7.settings")
    import django
    django.setup()
    from app01 import models

    # 代码写在此处下面
    # models.User.objects.create(name='ly', gender=1)
    # models.User.objects.create(name='ly2', gender=2)
    # models.User.objects.create(name='ly3', gender=3)
    # models.User.objects.create(name='ly4', gender=4)

    res = models.User.objects.filter(pk=1).first()
    print(res.gender)  # 1
    '''
        固定语法结构取值:get_字段名_display()
        如果查询出来的数据不再choices范围内,会显示原始数据。
    '''
    print(res.get_gender_display())  # 男
    
    

image

6. 多对多的创建方式

# 一共三种创建方式
	1. 自己创建表关系
	2. 通过ManyToManyField自动创建第三张表
	3. 设置ManyTomanyField并指定自行创建的第三张表
    

    
# 自行创建第三张表
class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8, decimal_places=2)

class Publish(models.Model):
    title = 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')
    create_time = models.DateTimeField()
''''
    自行创建第三张表不能使用一下四个方法
        add set remove clear
    不支持正反向查询
'''


# 设置ManyTomanyField并指定自行创建的第三张表
class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8, decimal_places=2)

class Author(models.Model):
    name = models.CharField(max_length=32)
    book = models.ManyToManyField(to='Author', through='Book2Author',through_fields=('author', 'book'))

class Book2Author(models.Model):
    book = models.ForeignKey(to='Book')
    author = models.ForeignKey(to='Author')
    create_time = models.DateTimeField()

7. Ajax技术

# AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步Javascript和XML”

# 即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML,现在更多使用json数据)

 
# 同步交互:客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求;

# 异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求。
 

# AJAX除了异步的特点外,还有一个就是:浏览器页面局部刷新;(这一特点给用户的感受是在不知不觉中完成请求和响应过程)


"""
ajax的精髓:
	1. 异步提交
	2. 局部刷新
"""

1. 我们不学习原生的ajax(js写的)
2. 我们目前学习jq封装之后的
3. 如果想使用ajax,必须引入jquery

# 小案例:
	我们在页面上,来一个简单计算
    
# 在settings.py中注释掉
	# 'django.middleware.csrf.CsrfViewMiddleware',
    
# views.py文件中写入:
from django.shortcuts import render, HttpResponse
# Create your views here.

def index(request):
    # if request.method == 'POST':
    if request.is_ajax():
        print(request.POST)
        d1 = request.POST.get('d1')
        d2 = request.POST.get('d2')

        d3 = int(d1) + int(d2)
        return HttpResponse(d3)
    return render(request, 'index.html')
    
    
# 在urls.py文件中添加路由:
url(r'^index/', views.index),
    
    
# 新建index.html文件:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
    <input type="text" id="d1"> +
    <input type="text" id="d2"> =
    <input type="text" id="d3">
    <button class="btn btn-success">结果</button>
<script>
    $('.btn').click(function () {
        var d1 = $('#d1').val();
        var d2 = $('#d2').val();

        // 直接发起Ajax请求
        $.ajax({
            // 1.指定提交的请求地址
            url:'/index/',

            // 2.指定请求方式
            type:'post',

            // 3.指定提交的数据
            data:{d1:d1, d2:d2},

            // 4.接收 后端返回的结果
            success:function (res) {
                // res时后端返回的数据
                console.log(res);
                $('#d3').val(res)
            }
        })
    })
</script>
</body>
</html>

"""
注意:
----------------------------------------------------------
# views.py文件中写入:
# 给到前端的时json数据
def index(request):
    # if request.method == 'POST':
    if request.is_ajax():
        print(request.POST)
        d1 = request.POST.get('d1')
        d2 = request.POST.get('d2')

        # d3 = int(d1) + int(d2)
        # return HttpResponse(d3)

        import json
        user_dict = {'name': 'jason', 'hobby': {'like': 'ball'}}
        res = json.dumps(user_dict)
        return HttpResponse(res)
    return render(request, 'index.html')
    


# 针对前端拿到的json数据取值
# 写在index.html文件:
            // 4.接收 后端返回的结果
            success:function (res) {
                // res时后端返回的数据
                console.log(res);

                // 情景一 反序列化
                // 后端使用HttpResponse,前端使用下面的方式
                res = JSON.parse(res)
                console.log(res.name);
                
                {#$('#d3').val(res)#}
            }
            
            
----------------------------------------------------------
# views.py文件中写入:
# 给到前端的时json数据
from django.shortcuts import render, HttpResponse
# Create your views here.

def index(request):
    # if request.method == 'POST':
    if request.is_ajax():
        print(request.POST)
        d1 = request.POST.get('d1')
        d2 = request.POST.get('d2')

        # d3 = int(d1) + int(d2)
        # return HttpResponse(d3)

        # import json
        # user_dict = {'name': 'jason', 'hobby': {'like': 'ball'}}
        # res = json.dumps(user_dict)
        # return HttpResponse(res)

        from django.http import JsonResponse
        user_dict = {'name': 'jason', 'hobby': {'like': 'ball'}}
        return JsonResponse(user_dict)

    return render(request, 'index.html')



# 针对前端拿到的json数据取值
# 写在index.html文件:
            // 4.接收 后端返回的结果
            success:function (res) {
                // res时后端返回的数据
                console.log(res);

                // 情景一 反序列化
                {#res = JSON.parse(res)#}
                {#console.log(res.name);#}

                // 情景二
                console.log(res.name);

                {#$('#d3').val(res)#}
            }
                


--------------------------------------------------------------

# views.py文件中写入:
# 给到前端的时json数据

from django.shortcuts import render, HttpResponse
# Create your views here.

def index(request):
    # if request.method == 'POST':
    if request.is_ajax():
        print(request.POST)
        d1 = request.POST.get('d1')
        d2 = request.POST.get('d2')

        # d3 = int(d1) + int(d2)
        # return HttpResponse(d3)

        import json
        user_dict = {'name': 'jason', 'hobby': {'like': 'ball'}}
        res = json.dumps(user_dict)
        return HttpResponse(res)

        # from django.http import JsonResponse
        # user_dict = {'name': 'jason', 'hobby': {'like': 'ball'}}
        # return JsonResponse(user_dict)

    return render(request, 'index.html')



# 针对前端拿到的json数据取值
# 写在index.html文件(写在3 4 之间即可):
            // 3.指定提交的数据
            data:{d1:d1, d2:d2},

            // 情景三 指定请求方式
            // 指定后端返回的数据格式
            dataType: 'json',

            // 4.接收 后端返回的结果
"""

image

image

image

推荐阅读