赞
踩
前端朝后端发送请求的方式:
前端html的value属性是给传送给后端的默认值,前端html的name属性是传送给后端的字典键
前端通过form表单、input标签文本输入,input标签提交发送post请求, 后端通过request.POST来获取数据
前端通过ajax传送数据,可通过id属性或者class属性进行点击操作,或者val属性取值或者获取值,通过data键值发送给后端request.POST来获取数据
后端传给前端可通过django的三板斧即( render, redirect, HttpResponse),前端即可通过双花括号取值{{}},以及条件取值{%%}
页面上有三个input框
在前两个狂中输入数字,点击按钮,朝后端发送ajax请求,
后端计算出结果,再返回给前端动态展示到第三个input框中
整个过程页面不准有刷新,也不能再前端计算
// 朝后端发送ajax请求
$.ajax({
// 1、指定超哪个后端发送ajax请求,不写就是超当前地址提交
url:'',
// 2、请求方式,不指定默认就是get,都是小写
type:'POST',
// 3、数据 data:{'username':'jason', 'password':123},
data:{'i1':$('#d1').val(), 'i2':$('#d2').val()},
// 4、回调函数, 当后端给你返回结果的时候会自动触发,args接受后端的返回结果
success:function(args){
//alert(args) // 通过DOM操作动态渲染到第三个input里面
$('#d3').val(args)
}
})
前后端传输数据的编码格式:urlencoded, formdata, json;前后端传输数据的时候一定要确保编码格式跟数据真正的格式是一致的
form表单
ajax
django后端能够自动识别到FormData对象并且能够将内部的普通键值自动解析并封装到request.POST中,文件数据自动解析并封装到request.FILES中
from django.http import JsonResponse
from django.core import serializers
def ab_ser(request):
user_list = [{"name": 1}, {"name": 2}]
return JsonResponse(user_list, safe=False)
# res = serializers.serialize('json', user_queryset)
# return HttpResponse(res)
{#<a href="{% url 'book_delete' book_obj.id %}" class="btn btn-danger btn-xs">删除</a>#} <button class="btn btn-danger btn-xs del" delete_id="{{ book_obj.id }}">删除</button> <script> $('.del').on('click', function(){ {#alert($(this).attr('delete_id'))#} // 先将当前标签对象存储起来 let currentBtn = $(this); // 二次确认弹框 swal({ title: "Are you sure?", text: "You will not be able to recover this imaginary file!", type: "warning", showCancelButton: true, confirmButtonClass: "btn-danger", confirmButtonText: "Yes, delete it!", cancelButtonText: "No, cancel plx!", closeOnConfirm: false, closeOnCancel: false, showLoaderOnConfirm: true }, function(isConfirm) { if (isConfirm) { // 朝后端发送ajax请求删除数据之后,再弹下面的提示框 $.ajax({ {#url:'/delete/user/' + currentBtn.attr('delete_id'),#} url:'/delete/user/', type:'POST', data: {'delete_id': currentBtn.attr('delete_id')}, success: function (args){ // args = {'code':'', 'msg':''} // args为后端return的JsonResponse(back_dic) if(args.code === 1000){ swal("Deleted!", args.msg, "success"); currentBtn.parent().parent().remove() // 利用DOM操作,移除当前标签, 动态刷新 }else{ swal("no Deleted!", '未知错误', "info") } } }) } else { swal("Cancelled", "Your imaginary file is safe :)", "error"); } }); }) </script>
def ab_pl(request):
# 先插入一万条数据
# 当你批量插入数据的时候,使用orm给你提供的buLk_create能够大大的减少操作时间
book_list = []
for i in range(10000):
book_obj = models.Book(title=i)
book_list.append(book_obj)
models.Book.objects.bulk_create(book_list)
# 再将所有数据查询并展示到前端页面
return render(request, 'ab_pl.html', locals())
自定义分页器代码基于bootstrap样式,存在utils文件夹下
后端views.py
前端ab_pl.html
{% extends 'home.html' %}
{% block content %}
{% for j in page_queryset %}
<p> {{ j}}</p>
<nav aria-label="Page navigation"></nav>
{% endfor %}
{{ page_obj.page_html|safe }} {# // 因为是后端传来拼接好的html代码,标记为safe#}
{% endblock %}
自定义分页器封装代码:
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 = 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)
def ab_form(request): from django import forms class MyForm(forms.Form): # username最小3位最大8位 username = forms.CharField( min_length=3, max_length=8, label='用户名', error_messages={ 'min_length': '用户名最少3位', 'max_length': '用户名最大8位', 'required': '用户名不能为空' }, initial='shirmay', required=False, widget=forms.widgets.TextInput(attrs={'class': 'form-control'}) ) password = forms.CharField( min_length=3, max_length=8, label='密码', widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'}) ) confirm_password = forms.CharField( min_length=3, max_length=8, label='确认密码', error_messages={ 'min_length': '确认密码最少3位', 'max_length': '确认密码最大8位', 'required': '确认密码不能为空' }, widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'}) ) # email字段必须符合邮箱格式 email = forms.EmailField( label='邮箱', error_messages={'invalid': '邮箱格式不正确', 'required': '用户名不能为空'}, widget=forms.widgets.EmailInput(attrs={'class': 'form-control'}) ) # 局部钩子 def clean_username(self): # 获取到用户名 username = self.cleaned_data.get('username') # 提示前端展示错误信息 if '666' in username: self.add_error('username', '不能有666') # 将钩子函数钩出来数据再放回去 return username # 全局钩子 def clean(self): password = self.cleaned_data.get("password") confirm_password = self.cleaned_data.get("confirm_password") if not confirm_password == password: self.add_error('confirm_password', '两次密码不一致') # 将钩子函数钩去出来数据再放回去 return self.cleaned_data # form_obj = MyForm({'username':'dad', 'password':'123', 'email':'uerio'}) # 将带校验的数据组织成字典的形式传入即可 # form_obj.is_valid() # 检测数据是否合法,注意该方法只有在所有数据全部合法的情况下才返回True # print(form_obj.cleaned_data) # 查看所有校验通过的数据 # print(form_obj.errors) # 查看所有不符合校验规则以及不符合的原因 # 先产生一个空对象 form_obj = MyForm() if request.method == 'POST': form_obj = MyForm(request.POST) if form_obj.is_valid(): return HttpResponse('ok') # 直接将空对象传递给html页面 return render(request, 'ab_form.html', locals())
{% extends 'home.html' %} {% block content %} <form action="" method="post" novalidate> {# <p>第一种渲染方式,代码书写极少,封装程度太高,不便于后续的扩展,一般情况下只在本地测试使用 </p>#} {# {{ form_obj.as_p }}#} {# {{ form_obj.as_ul }}#} {# {{ form_obj.as_table }}#} {# <p>第二种渲染方式,可扩展性很强, 但是需要书写的代码太多</p>#} {# {{ form_obj.username.label }}:{{ form_obj.username }}#} <p>第三种渲染方式推荐使用, 代码书写简单,并且扩展性也高</p> {% for form in form_obj %} <p> {{ form.label }}:{{ form }} <span style="color:red"> {{ form.errors.0 }}</span> </p> {% endfor %} <input type="submit" class="btn btn-info"> </form> {% endblock %}
# 校验用户登录的装饰器 """ 用户如果在没有登录的情况下想访问一个需要登录的页面, 那么先跳转到登录页面,当用户输入正确的用户名和密码之后 应跳转到用户之前想要访问的页面去,而不是写死 """ def login_auth(func): def inner(request, *args, **kwargs): target_url = request.get_full_path() if request.COOKIES.get('username'): return func(request, *args, **kwargs) else: return redirect(f'/app02/login/?next={target_url}') return inner @login_auth def index(request): # # 获取cookie信息,判断你有没有 # if request.COOKIES.get('username') == 'shirmay': # if request.method == 'POST': # print(request.POST) # print(request.FILES) # return render(request, 'index.html') # # 没有登录应该跳转到登录页面 # else: # return redirect('/app02/login/') return render(request, 'index.html') def login(request): if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') if username == 'shirmay' and password == '123': # 获取用户上一次想要访问的url获取用户上一次想要访问的url target_url = request.GET.get('next') if target_url: obj = redirect(target_url) else: # 保存用户登录状态 obj = redirect('/app02/home/') # 让浏览器记录cookie数据, 浏览器不单单会帮你存,而且后面每次访问你的时候还会带着它过来 obj.set_cookie('username', 'shirmay') # 跳转到一个需要用户登录之后才能看到的页面 return obj return render(request, 'login_cookie.html') @login_auth def logout(request): obj = redirect('/app02/login/') obj.delete_cookie('username') return obj
def set_session(request):
request.session['hobby'] = 'cat'
return HttpResponse('hhh')
def get_session(request):
print(request.session.get('hobby'))
return HttpResponse('hsdkhaksjh')
def del_session(request):
print(request.session.flush())
return HttpResponse('delete session')
@method_decorator(check_login)
def post(self, request):
print("Home View POST method...")
return redirect("/index/")
@method_decorator(check_login, name="get")
@method_decorator(check_login, name="post")
class HomeView(View):
@method_decorator(check_login)
def dispatch(self, request, *args, **kwargs):
return super(HomeView, self).dispatch(request, *args, **kwargs)
from django.utils.decorators import method_decorator @method_decorator(check_login, name="get") @method_decorator(check_login, name="post") class HomeView(View): @method_decorator(check_login) def dispatch(self, request, *args, **kwargs): return super(HomeView, self).dispatch(request, *args, **kwargs) def get(self, request): return render(request, "home.html") @method_decorator(check_login) def post(self, request): print("Home View POST method...") return redirect("/index/")
django自带七个中间件,每个中间件都有各自对应的功能,如全局身份校验,全局访问频率校验,全局权限校验
并且django还支持程序员自定义中间件,并且暴露给程序员五个可以自定义的方法,只要涉及到全局相关的功能都可以使用中间件完成
process_request
:请求来的时候需要经过每一个中间件里面的process_request方法,结果的顺序是按配置文件中注册的中间件从上往下的顺序依次执行, 如果中间件没有定义该方法,直接跳过执行下一个中间件;如果该方法返回了HttpResponse对象,那么请求将不再继续往后执行,而是直接原路返回(校验失败不允许访问…);process_request方法就是用来做全局相关的所有限制功能process_response
:响应走到时候需要经过每一个中间件里面的process_response方法,该方法有两个额外的参数request,response;该方法必须返回一个HttpResponse对象,默认返回的是形参response;结果的顺序是按配置文件中注册的中间件从下往上的顺序依次执行 如果中间件没有定义该方法,直接跳过执行下一个中间件;如何自定义中间件: 创建文件夹>创建py文件>创建一个类,必须继承MiddlewareMixin,然后自定义五个方法,用几个写几个>将类的路径已字符串的形式注册到配置文件中才能生效
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
# 自定义的中间件
'mymiddleware.mydb.MyMiddleware',
]
from django.utils.deprecation import MiddlewareMixin
class MyMiddleware(MiddlewareMixin):
def process_request(self, request):
print("the first before request")
def process_response(self, request, response):
"""
response就是django后端返回给前端的内容
"""
print("the first before response")
return response
<input type='hidden' name='csrfmiddlewaretoken' value='唯一字符串'/>
{% load static %} <script src="{% static 'js/mysetup.js' %}"></script> <script> $.ajax({ url: "", type: "POST", {#// 第一种 利用标签查找获取页面上的随机字符串使用JQuery取出csrfmiddlewaretoken的值,拼接到data中#} {#data: {"username": "Tonny","password": 123456,"csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val() },#} {#// 第二种 利用模板语法提供的快捷书写#} {#data: {"username": "Tonny","password": 123456,"csrfmiddlewaretoken": '{{ csrf_token }}' },#} // 第三种 通用方式,导入已写好的mysetup.js文件,并引用到自己的html data: {"username": "Tonny","password": 123456}, success: function (data) { console.log(data); } }) </script>
function getCookie(name) { var cookieValue = null; if (document.cookie && document.cookie !== '') { var cookies = document.cookie.split(';'); for (var i = 0; i < cookies.length; i++) { var cookie = jQuery.trim(cookies[i]); // Does this cookie string begin with the name we want? if (cookie.substring(0, name.length + 1) === (name + '=')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; } var csrftoken = getCookie('csrftoken'); function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protection return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } $.ajaxSetup({ beforeSend: function (xhr, settings) { if (!csrfSafeMethod(settings.type) && !this.crossDomain) { xhr.setRequestHeader("X-CSRFToken", csrftoken); } } });
from django.views.decorators.csrf import csrf_exempt,csrf_protect
#FBV使用直接加就行
@csrf_exempt
def index(request):
pass
#CBV模式,除了csrf_exempt装饰器要按dispatch的方法加,csrf_protect三种加装饰器的方法都可行
@method_decorator(csrf_exempt,name="dispatch")
class Login(View):
def get(self, request, *args, **kwargs):
pass
def post(self, request, *args, **kwargs):
pass
from django.conf.urls import url from app02orm import views urlpatterns = ( # 首页 url(r'^home/', views.home), # 图书的展示 url(r'^book/list/', views.book_list, name="book_list"), # 书籍的添加 url(r'^book/add', views.book_add, name="book_add"), # 书籍的编辑 url(r'^book/edit/(?P<edit_id>\d+)', views.book_edit, name="book_edit"), # 书籍的删除 url(r'^book/delete/(\d+)', views.book_delete, name="book_delete"), # ajax相关 url(r'ab_ajax/', views.ab_ajax), # 前后端传输数据编码格式研究 url(r'^index/', views.index), # ajax发送json格式数据 url(r'^ab_json/', views.ab_json), # ajax发送文件数据 url(r'^ab_file/', views.ab_file), # 序列化组件 url(r'^ab_ser/', views.ab_ser), # 批量 url(r'^ab_pl/', views.ab_pl), # form组件 url(r'ab_form/', views.ab_form), # 登录功能 url(r'^login/', views.login), # 注销功能 url(r'^logout/', views.logout), # session操作 url(r'^set_session/', views.set_session), url(r'^get_session/', views.get_session), url(r'^del_session/', views.del_session), )
from django.shortcuts import render, redirect, HttpResponse import json from django.http import JsonResponse from django.core import serializers # Create your views here. book_querysets = [ {"title": "python2", "pub_date": "2019/3/2", 'author': ['aa', 'bb'], 'source': 'A出版社', 'id': 1}, {"title": "python2", "pub_date": "2019/3/2", 'author': ['aa'], 'source': 'B出版社', 'id': 2}, {"title": "python2", "pub_date": "2019/3/2", 'author': ['aa'], 'source': 'B出版社', 'id': 3}, {"title": "python2", "pub_date": "2019/3/2", 'author': ['aa'], 'source': 'A出版社', 'id': 4}, ] def home(request): return render(request, "home.html") def book_list(request): book_queryset = book_querysets return render(request, 'book_list.html', locals()) def book_add(request): if request.method == 'POST': # 1 获取前端提交过来的所有数据 title = request.POST.get("title") date = request.POST.get("pub_date") publish_id = request.POST.get("publish") authors_list = request.POST.getlist("authors") # 2 操作数据库存储数据 print(title, date, publish_id, authors_list) # 3 跳转到数据展示页面, 则会有新增的数据展示出来 # redirect括号内可以直接写url也可以直接写别名,但是如果你的别名需要给额外的参数的话,那么就必须使用reverser解析了 return redirect('book_list') authors_list = [{'id': '1', 'name': 'aa'}, {'id': '2', 'name': 'bb'}, {'id': '3', 'name': 'cc'}] source_list = [{'id': '1', 'name': 'A出版社'}, {'id': '2', 'name': 'B出版社'}] return render(request, 'book_add.html', locals()) def book_edit(request, edit_id): if request.method == 'POST': return HttpResponse("修改数据的脚本") edit_obj = {} for obj in book_querysets: if obj['id'] == int(edit_id): edit_obj = obj break authors_list = [{'id': '1', 'name': 'aa'}, {'id': '2', 'name': 'bb'}, {'id': '3', 'name': 'cc'}] source_list = [{'id': '1', 'name': 'A出版社'}, {'id': '2', 'name': 'B出版社'}] return render(request, "book_edit.html", locals()) def book_delete(request, delete_id): # 删除脚本, pass # 直接跳转到展示页 return redirect('book_list') def ab_ajax(request): if request.method == 'POST': # print(request.POST) # <QueryDict: {'username': ['jason'], 'password': ['123']}> i1 = request.POST.get('i1') i2 = request.POST.get('i2') i3 = int(i1) + int(i2) return HttpResponse(i3) return render(request, 'add_ajax.html') def ab_json(request): print(request.is_ajax()) print(request.POST) print(request.body) # b'{"username":"jason","age":32}' if request.is_ajax(): # json.loads括号内如果传入了一个二进制格式的数据那么内部自动解码再反序列化 json_dict = json.loads(request.body) # {"username":"jason","age":32} print(json_dict) return render(request, 'ab_json.html') def ab_file(request): if request.is_ajax(): print(request.POST) print(request.FILES) return render(request, 'ab_file.html') def ab_ser(request): user_list = [{"name": 1}, {"name": 2}] return JsonResponse(user_list, safe=False) # res = serializers.serialize('json', user_queryset) # return HttpResponse(res) def ab_pl(request): from utils.mypage import Pagination # 先插入一万条数据 query_list = [ {'id': '1', 'name': 'aa'}, {'id': '2', 'name': 'bb'}, {'id': '3', 'name': 'cc'}, {'id': '4', 'name': 'aaa'}, {'id': '5', 'name': 'bbb'}, {'id': '6', 'name': 'ccc'} ] # 当你批量插入数据的时候,使用orm给你提供的buLk_create能够大大的减少操作时间 # book_list = [] # for i in range(10000): # book_obj = models.Book(title=i) # book_list.append(book_obj) # models.Book.objects.bulk_create(book_list) # 再将所有数据查询并展示到前端页面 current_page = request.GET.get('page', 1) all_count = len(query_list) # 1 传值生成对象 page_obj = Pagination(current_page=current_page, all_count=all_count) # 2 直接对总数据进行切片操作 page_queryset = query_list[page_obj.start:page_obj.end] return render(request, 'ab_pl.html', locals()) def ab_form(request): from django import forms from django.core.validators import RegexValidator class MyForm(forms.Form): # username最小3位最大8位 username = forms.CharField( min_length=3, max_length=8, label='用户名', error_messages={ 'min_length': '用户名最少3位', 'max_length': '用户名最大8位', 'required': '用户名不能为空' }, initial='shirmay', required=False, widget=forms.widgets.TextInput(attrs={'class': 'form-control'}) ) password = forms.CharField( min_length=3, max_length=8, label='密码', widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'}) ) confirm_password = forms.CharField( min_length=3, max_length=8, label='确认密码', error_messages={ 'min_length': '确认密码最少3位', 'max_length': '确认密码最大8位', 'required': '确认密码不能为空' }, widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'}) ) # email字段必须符合邮箱格式 email = forms.EmailField( label='邮箱', error_messages={'invalid': '邮箱格式不正确', 'required': '用户名不能为空'}, widget=forms.widgets.EmailInput(attrs={'class': 'form-control'}) ) phone = forms.CharField( validators=[ RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头') ], ) gender = forms.fields.ChoiceField( choices=((1, "男"), (2, "女"), (3, "保密")), label="性别", initial=3, widget=forms.widgets.RadioSelect() ) hobby = forms.ChoiceField( choices=((1, "篮球"), (2, "足球"), (3, "双色球"),), label="爱好", initial=3, widget=forms.widgets.Select() ) # 多选 hobby1 = forms.MultipleChoiceField( choices=((1, "篮球"), (2, "足球"), (3, "双色球"),), label="爱好", initial=[1, 3], widget=forms.widgets.SelectMultiple() ) # 单选checkbox keep = forms.ChoiceField( label="是否记住密码", initial="checked", widget=forms.widgets.CheckboxInput() ) # 多选checkbox hobby2 = forms.MultipleChoiceField( choices=((1, "篮球"), (2, "足球"), (3, "双色球"),), label="爱好", initial=[1, 3], widget=forms.widgets.CheckboxSelectMultiple() ) # 局部钩子 def clean_username(self): # 获取到用户名 username = self.cleaned_data.get('username') # 提示前端展示错误信息 if '666' in username: self.add_error('username', '不能有666') # 将钩子函数钩出来数据再放回去 return username # 全局钩子 def clean(self): password = self.cleaned_data.get("password") confirm_password = self.cleaned_data.get("confirm_password") if not confirm_password == password: self.add_error('confirm_password', '两次密码不一致') # 将钩子函数钩去出来数据再放回去 return self.cleaned_data # form_obj = MyForm({'username':'dad', 'password':'123', 'email':'uerio'}) # 将带校验的数据组织成字典的形式传入即可 # form_obj.is_valid() # 检测数据是否合法,注意该方法只有在所有数据全部合法的情况下才返回True # print(form_obj.cleaned_data) # 查看所有校验通过的数据 # print(form_obj.errors) # 查看所有不符合校验规则以及不符合的原因 # 先产生一个空对象 form_obj = MyForm() if request.method == 'POST': form_obj = MyForm(request.POST) if form_obj.is_valid(): return HttpResponse('ok') # 直接将空对象传递给html页面 return render(request, 'ab_form.html', locals()) # 校验用户登录的装饰器 """ 用户如果在没有登录的情况下想访问一个需要登录的页面, 那么先跳转到登录页面,当用户输入正确的用户名和密码之后 应跳转到用户之前想要访问的页面去,而不是写死 """ def login_auth(func): def inner(request, *args, **kwargs): target_url = request.get_full_path() if request.COOKIES.get('username'): return func(request, *args, **kwargs) else: return redirect(f'/app02/login/?next={target_url}') return inner @login_auth def index(request): # # 获取cookie信息,判断你有没有 # if request.COOKIES.get('username') == 'shirmay': # if request.method == 'POST': # print(request.POST) # print(request.FILES) # return render(request, 'index.html') # # 没有登录应该跳转到登录页面 # else: # return redirect('/app02/login/') return render(request, 'index.html') def login(request): if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') if username == 'shirmay' and password == '123': # 获取用户上一次想要访问的url获取用户上一次想要访问的url target_url = request.GET.get('next') if target_url: obj = redirect(target_url) else: # 保存用户登录状态 obj = redirect('/app02/home/') # 让浏览器记录cookie数据, 浏览器不单单会帮你存,而且后面每次访问你的时候还会带着它过来 obj.set_cookie('username', 'shirmay', max_age=10, expires=10) # 跳转到一个需要用户登录之后才能看到的页面 return obj return render(request, 'login_cookie.html') @login_auth def logout(request): obj = redirect('/app02/login/') obj.delete_cookie('username') return obj def set_session(request): request.session['hobby'] = 'cat' return HttpResponse('hhh') def get_session(request): print(request.session.get('hobby')) return HttpResponse('hsdkhaksjh') def del_session(request): print(request.session.flush()) return HttpResponse('delete session')
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Home</title> {% load static %} <link rel="stylesheet" href= "{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}"> <script src="{% static 'bootstrap-3.3.7-dist/js/jquery-3.5.1.min.js' %}"></script> <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script> {% block css%} {% endblock %} </head> <body> <nav class="navbar navbar-inverse"> <div class="container-fluid"> <!-- Brand and toggle get grouped for better mobile display --> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">图书管理系统</a> </div> <!-- Collect the nav links, forms, and other content for toggling --> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav"> <li class="active"><a href="#">图书<span class="sr-only">(current)</span></a></li> <li><a href="#">作者</a></li> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">更多 <span class="caret"></span></a> <ul class="dropdown-menu"> <li><a href="#">Action</a></li> <li><a href="#">Another action</a></li> <li><a href="#">Something else here</a></li> <li role="separator" class="divider"></li> <li><a href="#">Separated link</a></li> <li role="separator" class="divider"></li> <li><a href="#">One more separated link</a></li> </ul> </li> </ul> <form class="navbar-form navbar-left"> <div class="form-group"> <input type="text" class="form-control" placeholder="Search"> </div> <button type="submit" class="btn btn-default">Submit</button> </form> <ul class="nav navbar-nav navbar-right"> <li><a href="#">Shirmay</a></li> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">更多操作 <span class="caret"></span></a> <ul class="dropdown-menu"> <li><a href="#">Action</a></li> <li><a href="#">Another action</a></li> <li><a href="#">Something else here</a></li> <li role="separator" class="divider"></li> <li><a href="#">Separated link</a></li> </ul> </li> </ul> </div><!-- /.navbar-collapse --> </div><!-- /.container-fluid --> </nav> <div class="container-fluid"> <div class="row"> <div class="col-md-3"> <div class="list-group"> <a href="#" class="list-group-item active"> 首页 </a> <a href="{% url 'book_list' %}" class="list-group-item">图书列表</a> <a href="#" class="list-group-item">出版社列表</a> <a href="#" class="list-group-item">作者列表</a> <a href="#" class="list-group-item">更多</a> </div> </div> <div class="col-md-9"> <div class="panel panel-primary"> <div class="panel-heading"> <h3 class="panel-title">BMS</h3> </div> <div class="panel-body"> {% block content %} <div class="jumbotron"> <h1>欢迎来到读书平台</h1> <p>这里都有</p> <p><a class="btn btn-primary btn-lg" href="#" role="button">点击看好多</a></p> </div> <div class="row"> <div class="col-sm-6 col-md-4"> <div class="thumbnail"> <img src="https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=4076820763,4198936175&fm=26&gp=0.jpg" alt="..."> <div class="caption"> <h3>Thumbnail label</h3> <p>...</p> <p><a href="#" class="btn btn-primary" role="button">Button</a> <a href="#" class="btn btn-default" role="button">Button</a></p> </div> </div> </div> <div class="col-sm-6 col-md-4"> <div class="thumbnail"> <img src="https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=2156579844,1915236356&fm=26&gp=0.jpg" alt="..."> <div class="caption"> <h3>Thumbnail label</h3> <p>...</p> <p><a href="#" class="btn btn-primary" role="button">Button</a> <a href="#" class="btn btn-default" role="button">Button</a></p> </div> </div> </div> <div class="col-sm-6 col-md-4"> <div class="thumbnail"> <img src="https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=269085220,2221469621&fm=26&gp=0.jpg" alt="..."> <div class="caption"> <h3>Thumbnail label</h3> <p>...</p> <p><a href="#" class="btn btn-primary" role="button">Button</a> <a href="#" class="btn btn-default" role="button">Button</a></p> </div> </div> </div> </div> {% endblock %} </div> </div> </div> </div> </div> {% block js %} {% endblock %} </body> </html>
{% extends 'home.html' %} {% block content %} <a href="{% url 'book_add' %}" class="btn btn-success">添加</a> <br><br> <table class="table table-hover table-striped"> <thead> <tr> <th>ID</th> <th>书名</th> <th>日期</th> <th>出版社</th> <th>作者</th> <th>操作</th> </tr> </thead> <tbody> {% for book_obj in book_queryset %} <tr> <td>{{ book_obj.id}}</td> <td>{{ book_obj.title}}</td> <td>{{ book_obj.pub_date}}</td> <td>{{ book_obj.source}}</td> <td>{{ book_obj.author}}</td> <td> <a href="{% url 'book_edit' book_obj.id %}" class="btn btn-primary btn-xs">编辑</a> <a href="{% url 'book_delete' book_obj.id %}" class="btn btn-danger btn-xs">删除</a> </td> </tr> {% endfor %} </tbody> </table> {% endblock %}
{% extends 'home.html' %} {% block content %} <h1 class="text-center">书籍添加</h1> <form action="" method="post"> <p>书名: <input type="text" name="title" class="form-control"> </p> <p>日期: <input type="date" name="pub_date" class="form-control"> </p> <p>出版社: <select name="publish" id="" class="form-control"> {% for p in source_list %} <option value="{{ p.id }}">{{ p.name }}</option> {% endfor %} </select> </p> <p>作者: <select name="authors" id="" multiple class="form-control"> {% for author in authors_list %} <option value="{{ author.id }}">{{ author.name }}</option> {% endfor %} </select> </p> <input type="submit" value="新增" class="btn btn-primary btn-block"> </form> {% endblock %}
{% extends 'home.html' %} {% block content %} <h1 class="text-center">书籍辑</h1> <form action="" method="post"> <p>书名: <input type="text" name="title" class="form-control" value="{{ edit_obj.title }}"> </p> <p>日期: <input type="text" name="pub_date" class="form-control" value="{{ edit_obj.pub_date}}"> </p> <p>出版社: <select name="publish" id="" class="form-control"> {% for p in source_list %} {% if edit_obj.publish == p %} <option value="{{ p.id }}" selected>{{ p.name }}</option> {% else %} <option value="{{ p.id }}">{{ p.name }}</option> {% endif %} {% endfor %} </select> </p> <p>作者: <select name="authors" id="" multiple class="form-control"> {% for author in authors_list %} {% if author.name in edit_obj.author %} <option value="{{ author.id }}" selected>{{ author.name }}</option> {% else %} <option value="{{ author.id }}">{{ author.name }}</option> {% endif %} {% endfor %} </select> </p> <input type="submit" value="编辑" class="btn btn-info btn-block"> </form> {% endblock %}
{% extends 'home.html' %} {% block content %} <input type="text" id="d1">+ <input type="text" id="d2">= <input type="text" id="d3"> <p><button id="btn">click </button></p> <script> $('#btn').click( // 先给按钮绑定一个点击事件 function(){ $.ajax({ // 朝后端发送ajax请求 url:'', // 1、指定超哪个后端发送ajax请求,不写就是超当前地址提交 type:'post', // 2、请求方式,不指定默认就是get // 3、数据 {#data:{'username':'jason', 'password':123},#} data:{'i1':$('#d1').val(), 'i2':$('#d2').val()}, // 4、回调函数, 当后端给你返回结果的时候会自动触发,args接受后端的返回结果 success:function(args){ $('#d3').val(args) {#alert(args) // 通过DOM操作动态渲染到第三个input里面#} } }) } ) </script> {% endblock %}
{% extends 'home.html' %} {% block content %} <form action="" method="post" enctype="multipart/form-data"> <p>username:<input type="text" name="username" class="form-control"></p> <p>password:<input type="password" name="password" class="form-control"></p> <p>file:<input type="file" name="file"></p> <input type="submit" class="btn btn-success"> <input type="button" class="btn btn-danger" value="按钮" id="d1"> </form> <script> $('#d1').click( function(){ $.ajax({ url: '', type:'POST', data:{'username':'jason', 'age':32}, success: function (args){ } }) } ) </script> {% endblock %}
{% extends 'home.html' %} {% block content %} <button class="btn btn-danger" id="d1">click me</button> <script> $('#d1').click( function(){ $.ajax({ url: '', type:'POST', data: JSON.stringify({'username':'jason', 'age':32}), contentType: 'application/json', // 指定编码格式 success: function (args){ } }) } ) </script> {% endblock %}
{% extends 'home.html' %} {% block content %} <p>username:<input type="text" id="d1"></p> <p>password:<input type="text" id="d2"></p> <p><input type="file" id="d3"></p> <button class="btn btn-info" id="d4">click</button> <script> $('#d4').click( // 点击按钮超后端发送普通键值对和文件数据 function(){ // 1、需要先利用FormData内置对象 let formDataObj = new FormData(); // 2、添加普通的键值对 formDataObj.append('username', $('#d1').val()); formDataObj.append('password', $('#d2').val()); // 3、添加文件对象 formDataObj.append('myfile', $('#d3')[0].files[0]) // 4、将对象基于ajax发送给后端 $.ajax({ url: '', type:'POST', data: formDataObj, // 直接将对象放在data后面即可 // ajax发送文件必须要指定的两个参数 contentType: false, // 不需使用任何编码,django后端能够自动识别FormData对象 processData: false, // 告诉浏览器不要对你的数据进行任何处理 success: function (args){ } }) } ) </script> {% endblock %}
{% extends 'home.html' %}
{% block content %}
{% for j in page_queryset %}
<p> {{ j}}</p>
<nav aria-label="Page navigation"></nav>
{% endfor %}
{{ page_obj.page_html|safe }} {# // 因为是后端传来拼接好的html代码,标记为safe#}
{% endblock %}
{% extends 'home.html' %} {% block content %} <form action="" method="post" novalidate> {# <p>第一种渲染方式,代码书写极少,封装程度太高,不便于后续的扩展,一般情况下只在本地测试使用 </p>#} {# {{ form_obj.as_p }}#} {# {{ form_obj.as_ul }}#} {# {{ form_obj.as_table }}#} {# <p>第二种渲染方式,可扩展性很强, 但是需要书写的代码太多</p>#} {# {{ form_obj.username.label }}:{{ form_obj.username }}#} <p>第三种渲染方式推荐使用, 代码书写简单,并且扩展性也高</p> {% for form in form_obj %} <p> {{ form.label }}:{{ form }} <span style="color:red"> {{ form.errors.0 }}</span> </p> {% endfor %} <input type="submit" class="btn btn-info"> </form> {% endblock %}
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登陆</title> <!-- <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css">--> <!-- <script src="/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>--> {% load static %} <script src="{% static 'bootstrap-3.3.7-dist/js/jquery-3.5.1.min.js' %}"></script> <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script> <link rel="stylesheet" href= "{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}"> </head> <body> <h1 class="text-center">登陆</h1> <div class="container"> <div class="row" > <div class="col-md-8 col-mod-offset-2"> <form action="" method="post"> <p>username:<input type="text" name="username" class="form-control"></p> <p>password:<input type="password" name="password" class="form-control"></p> <input type="submit" class="btn btn-success btn-block"> </form> </div> </div> </div> </body> </html>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。