Django-Ajax、form组件

1.Ajax

1.AJAX:不是新的编程语言,而是一种使用现有标准的新方法,我们目前学习的是jQuery版本。特点:异步提交,局部刷新。

2.AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。(这一特点给用户的感受是在不知不觉中完成请求和响应过程)

3.基本语法
	$.ajax({
        url:'',  // 后端地址 三种填写方式 与form标签的action一致
        type:'post',  // 请求方式 默认也是get
        data:{'v1':v1Val, 'v2':v2Val},  // 发送的数据
        success:function (args) {  // 后端返回结果之后自动触发 args接收后端返回的数据
         	 $('#d3').val(args)
                                }
    })
	
"""
作业:设置一个注册小程序,用户名不能为jason并且密码不能为123或123456,不能用户点击提交就应该显示:
思路:jQuery事件,ajax事件
register.html:
<body>
    <form action="" method="post">
        <p>username:
            <input type="text" id="i1" name="username">
            <span id="s1" style="color: red"></span>
        </p>
        <p>password:
            <input type="text" id="i2" name="password">
            <span id="s2" style="color: red"></span>
        </p>
        <input type="submit" id="i3">
    </form>
    <script>
        $('#i1').blur(function () {
            $.ajax({
                url:'',
                type:'post',
                data: {'i1':$('#i1').val()},
                success:function (args) {
                    $('#s1').text(args)
                }
            })
        })
        $('#i2').blur(function () {
            $.ajax({
                url:'',
                type: 'post',
                data:{'i2':$('#i2').val()},
                success:function (args) {
                    $('#s2').text(args)
                }
            })
        })
    </script>
</body>

views.py:
def register(request):
    if request.method == 'POST':
        username = request.POST.get('i1')
        password = request.POST.get('i2')
        if username:
            if username == 'jason':
                return HttpResponse('用户名不能为jason')
            else:
                return HttpResponse('')
        if password:
            if password == '123' or password == '123456':
                return HttpResponse('密码过于简单,请重新输入')
            else:
                return HttpResponse('')
    return render(request, 'register.html')
	
urls.py:
urlpatterns = [
    path('register/',views.register)
]

作业2:在前端编写三个输入框,前两个输入框让用户输入数字,点击按钮之后第三个输入框自动返回两数之和:
views.py:
def index(request):
    if request.method == 'POST':
        i1 = request.POST.get('i1')
        i2 = request.POST.get('i2')
        i3 = int(i1) + int(i2)
        return HttpResponse(i3)
    return render(request,'index.html')
	
index.html:
<body>
    <input type="text" id="i1"> + <input type="text" id="i2"> = <input type="text" id="i3">
    <input type="submit" value="点我发送ajax请求" id="sub">
    <script>
        $('#sub').click(function () {
            $.ajax({
                url:'',
                type:'post',
                data:{
                    'i1':$('#i1').val(),
                    'i2':$('#i2').val()
                },
                success:function (args) {
                    $('#i3').val(args)
                }
            })
        })
    </script>
</body>

作业3:编写一个可以实时校验用户名的输入框,如果用户名为jason,用户色自提提示。 不能点击或者失焦才实现:
# input实时监听事件,ajax时间

register.html:
<body>
    <p>username:
        <input type="text" name="username" id="username">
        <span style="color: red" id="s1"></span>
    </p>
    <p>password:
        <input type="password" name="password" id="password">
        <span style="color: red" ></span>
    </p>
    <script>
        $('#username').on('input',function () {
            $.ajax({
                url:'',
                type:'post',
                data:{'i1':$('#username').val()},
                success:function (args) {
                    $('#s1').text(args)
                }
            })
        })
    </script>
</body>

views.py:
def register(request):
    if request.method == 'POST':
        username = request.POST.get('i1')
        if username:
            if username == 'jason':
                return HttpResponse('用户名不能为jason')
            else:
                return HttpResponse('')
        return HttpResponse('')
    return render(request,'register.html')
"""

2.Content-Type

1.urlencoded
	ajax默认的编码格式、form表单默认也是
	数据格式  xxx=yyy&uuu=ooo&aaa=kkk
 	django后端会自动处理到request.POST中,用request.POST.get('xxx')拿到值

2.formdata
	django后端针对普通的键值对还是处理到request.POST中 但是针对文件会处理到request.FILES中。
"""
系统会根据不同的content-Type来分辨有几种文件类型,需要几个request。
"""

3.application/json:发送json格式数据类型
	form表单不支持 ajax可以
	<script>
    $('#d1').click(function () {
        $.ajax({
            url:'',
            type:'post',
            data:JSON.stringify({'name':'jason','age':18}),  // 千万不要骗人家
            contentType:'application/json',  //要指定contentType
            success:function (args) {
                alert(args)
            }

        })
    })
</script>
	后端需要从request.body中获取并自己处理
"""
views.py:
import json
def jsonfunc(request):
    if request.method == 'POST':
        data = request.body  # b'{"name":"max","age":25}'
        userdict = json.loads(data)  # loads自带将二进制转为十进制功能
        print(userdict)  # {'name': 'max', 'age': 25}
        return HttpResponse('成功成功')
    return render(request,'jsonfunc.html')
	
jsonfunc.html:
<body>
    <button id="b1">点我用ajax发送json数据</button>
    <script>
        $('#b1').click(function () {
            $.ajax({
                url:'',
                type:'post',
                data:JSON.stringify({'name':'max','age':25}),
                contentType:'application/json',
                success:function (args) {
                    alert(args)
                }
            })
        })
    </script>
</body>
"""

3.ajax携带文件数据

<script>
    $('#d3').click(function () {
        // 1.先产生一个FormData对象
        let myFormDataObj = new FormData();
        // 2.往该对象中添加普通数据
        myFormDataObj.append('name', 'jason');
        myFormDataObj.append('age', 18);
        // 3.往该对象中添加文件数据
        myFormDataObj.append('file', $('#d2')[0].files[0])
        // 4.发送ajax请求
        $.ajax({
            url:'',
            type:'post',
            data:myFormDataObj,

            // ajax发送文件固定的两个配置
            contentType:false,
            processData:false,
            success:function (args){
                alert(args)
            }

        })
    })
</script>
"""
getfile.html:
<body>
    <input type="file" id="i1">
    <input value="通过ajax发送文件" id="i2">
    <script>
        $('#i2').click(function () {
            let myFormDataObj = new FormData();
            myFormDataObj.append('name','max');
            myFormDataObj.append('age',18);
            myFormDataObj.append('file',$('#i1')[0].files[0])
            $.ajax({
                url:'',
                type:'post',
                data:myFormDataObj,
                contentType:false,
                processData:false,
                success:function (args) {
                    alert(args)
                }
            })
        })
    </script>
</body>

views.py:
def getfile(request):
    if request.method == 'POST':
        print(request.POST)  # <QueryDict: {'name': ['max'], 'age': ['18']}>
        print(request.FILES)  # <MultiValueDict: {'file': [<TemporaryUploadedFile: Capture001.png (image/png)>]}>
        return HttpResponse('成功')
    return render(request,'getfile.html')
"""

4.ajax补充说明

1.后端print(request.isajax)可以判断当前请求是否由ajax发出。

2.后端返回的三板斧都会被args接收不再影响整个浏览器页面:
返回一个页面被args接收,同理,返回字典根本就不会被接收:

3.选择使用ajax做前后端交互时,后端一般返回的都是json格式的字典数据,当我们从前端打印出来时发现它是一个字符类型,这也就意味着它不能通过点的方式取值:
views.py:
def ajax1(request):
    if request.is_ajax():
        userdict = {'code':10000 ,'name':'max', 'age':25}
        import json
        user_data = json.dumps(userdict)
        return HttpResponse(user_data)
    return render(request,'ajax1.html')

ajax1.html:
<body>
    <button id="d1">发送ajax请求</button>
    <script>
        $('#d1').click(function () {  # 点击一次就发送一个ajax请求
            $.ajax({
                url: '',
                type: 'post',
                data: {'name':'max'},
                success:function (args) {
                    console.log(args)
                    console.log(typeof args)
                }
            })
        })
    </script>
</body>

我们可以在$.ajax的字典中增加一个键值对:dataType:'json',这样前端就可以自动将字符串反序列化称为自定义对象。
views.py:
def ajax1(request):
    if request.is_ajax():
        userdict = {'code':10000 ,'name':'max', 'age':25}
        import json
        userdata = json.dumps(userdict)
        return HttpResponse(userdata)
    return render(request,'ajax1.html')

ajax1.html:
<body>
    <button id="d1">发送ajax请求</button>
    <script>
        $('#d1').click(function () {
            $.ajax({
                url: '',
                type: 'post',
                data: {'name':'max'},
                dataType:'json',
                success:function (args) {
                    console.log(args)
                    console.log(typeof args)
                    console.log(args.name)
                }
            })
        })
    </script>
</body>

4.此外还有一种方式:我们在后端用JsonResponse模块发送字典,在前端本身就是一个自定义对象,可以直接通过点的方式取值。
views.py:
def ajax1(request):
    if request.is_ajax():
        userdict = {'code':10000 ,'name':'max', 'age':25}
        from django.http import JsonResponse
        return JsonResponse(userdict)
    return render(request,'ajax1.html')

ajax1.html:
<body>
    <button id="d1">发送ajax请求</button>
    <script>
        $('#d1').click(function () {
            $.ajax({
                url: '',
                type: 'post',
                data: {'name':'max'},
                success:function (args) {
                    console.log(args)
                    console.log(typeof args)
                    console.log(args.name)
                }
            })
        })
    </script>
</body>

5.多对多三种创建方式

1.全自动创建(需要创建外键字段,系统会根据外键自动创建第三张表):
class Book(models,Model):
	title = models.CharField(max_length=32)
	authors = models.ManyToManyField(to='Author')  
    
class Author(models.Model):
	name = models.CharField(max_length=32)
'''
优势:自动创建第三张表,并且提供了add,remove,set,clear四种操作发方法。
劣势:字段固定,没办法扩展更多的字段
'''

2.纯手动创建(不需要创建外键,第三张表自己创建,可以扩展更多字段):
	 class Book(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')
        others = models.CharField(max_length=32)
        join_time = models.DateField(auto_now_add=True)
 	 优势:第三张表完全由自己创建 扩展性强
	 劣势:编写繁琐 并且不再支持add、remove、set、clear以及正反向概念
'''没有外键,意味着第三幢表的关系需要自己添加,并且不好判断是正向还是反向查询'''

3.半自动创建():
	 class Book(models.Model):
        title = models.CharField(max_length=32)
        authors = models.ManyToManyField(to='Author',
                          through='Book2Author',      									through_fields=('book','author')
                                        )
    class Author(models.Model):
        name = models.CharField(max_length=32)
    class Book2Author(models.Model):
        book = models.ForeignKey(to='Book', on_delete=models.CASCADE)
        author = models.ForeignKey(to='Author', on_delete=models.CASCADE)
        others = models.CharField(max_length=32)
        join_time = models.DateField(auto_now_add=True)
优势:第三张表完全由自己创建,扩展性强 正反向概念依然清晰可用
劣势:编写繁琐不再支持add、remove、set、clear

6.django自带的序列化组件

1.前后端分离的项目,只需要返回json格式的数据即可。

将所有的书籍信息放在一个大字典内,然后返回给前端:
def ajax2(request):
    book_queryset = models.Book.objects.all()
    data_dict = {}
    for book_obj in book_queryset:
        tem_dict = {}
        tem_dict['pk'] = book_obj.pk
        tem_dict['title'] = book_obj.title
        tem_dict['price'] = book_obj.price
        tem_dict['info'] = book_obj.info
        data_dict[book_obj.pk] = tem_dict
    return JsonResponse(data_dict, json_dumps_params={'ensure_ascii':False})

2.上述结果我们可以直接用序列化组件serializers实现,serializers可以直接将queryset转成json格式发给前端并且前端还拥有自定义对象的特性。
def ajax2(request):
    book_queryset = models.Book.objects.all()
    from django.core import serializers
    res = serializers.serialize('json', book_queryset)
    return HttpResponse(res)
"""
但是拿到的结果是编码过后的结果,需要在BEJSON中查看解码之后的结果
"""

7.批量操作数据(bulk_create)

1.如果想在一张表中插入100000条数据,我们的思路如下:
views.py:
def ajax4(request):
	for i in range(1,10000)
    models.Book.objects.create(title='第%s本书'%i,info='很带劲',price=888.88)
	 book_queryset = models.Book.objects.all()
    return render(request,'ajax4.html',locals())

html.py:
<body>
    <p>
    {% for book_obj in book_queryset %}
        {{ book_obj.title }}
    {% endfor %}
    </p>
</body>

2.如果添加的数据很多,并且数据之间有规律,我们可以采用bulk_create插入:
views.py:
def ajax5(request):
    book_obj_list = []  # 1.首先生成一个空列表
    for i in range(100000):
        book_obj = models.Users(name='max',country='china')
        book_obj_list.append(book_obj)  # 2.生成100000个空对象并且添加到列表中
    models.Users.objects.bulk_create(book_obj_list)  # 3.直接将列表当做参数传入表中
    return HttpResponse('数据传输中...')

8.自定义分页器模块

"""
分页器代码流程推导参考:
https://www.cnblogs.com/Dominic-Ji/articles/12035722.html
"""
自定义分页器代码封装:
1.在应用下新建一个目录utils,在该目录下新建一个py文件,命名为:myPage.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:  最多显示的页码个数
        """
        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>'
                    <ul class='pagination'>
                ''')
        first_page = '<li><a href="?page=%s">首页</a></li>' % (1)
        page_html_list.append(first_page)
 
        if self.current_page <= 1:
            prev_page = '<li class="disabled"><a href="#">上一页</a></li>'
        else:
            prev_page = '<li><a href="?page=%s">上一页</a></li>' % (self.current_page - 1,)
 
        page_html_list.append(prev_page)
 
        for i in range(pager_start, pager_end):
            if i == self.current_page:
                temp = '<li class="active"><a href="?page=%s">%s</a></li>' % (i, i,)
            else:
                temp = '<li><a href="?page=%s">%s</a></li>' % (i, i,)
            page_html_list.append(temp)
 
        if self.current_page >= self.all_pager:
            next_page = '<li class="disabled"><a href="#">下一页</a></li>'
        else:
            next_page = '<li><a href="?page=%s">下一页</a></li>' % (self.current_page + 1,)
        page_html_list.append(next_page)
 
        last_page = '<li><a href="?page=%s">尾页</a></li>' % (self.all_pager,)
        page_html_list.append(last_page)
        # 尾部添加标签
        page_html_list.append('''
                                           </nav>
                                           </ul>
                                       ''')
        return ''.join(page_html_list)
    
2.views.py:
def page(request):
    friend_queryset = models.Friend.objects.all()
    from app01.utils.myPage import Pagination
    current_page = request.GET.get('page')
    '''可以在这里设置每页展业数据条数,页数'''
    page_obj = Pagination(current_page=current_page,all_count=friend_queryset.count(),per_page_num=20,pager_count=7)
    page_queryset = friend_queryset[page_obj.start:page_obj.end]
    return render(request,'page.html',locals())

page.html:
	{% for friend_obj in page_queryset %}
		<p style="text-align: center">{{ friend_obj.name }}</p>
	{% endfor %}
	<div class="text-center">{{ page_obj.page_html|safe }}</div>
</body>

posted @ 2023-04-23 20:47  ERROR404Notfound  阅读(17)  评论(0)    收藏  举报
Title