django 写的一个在网页上对学生信息进行操作,用到了ajax,jquery操作表格等,还有 bootstrap,和 font-awesome(图标),这些框架写好了各种各样的网页元素,用起来十分的方便,
下面是效果图,
#models.py 文件 的建表信息
from django.db import models
# Create your models here.
class Classes(models.Model):
title = models.CharField(max_length=32)
m = models.ManyToManyField("Teacher")
class Teacher(models.Model):
name = models.CharField(max_length=32)
class Student(models.Model):
username = models.CharField(max_length=32)
age = models.IntegerField()
gender = models.NullBooleanField()
cs = models.ForeignKey("Classes",on_delete=models.CASCADE)
路由分发文件,
# urls.py 路由文件
from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path("students.html/", views.students),
path("add_student/", views.add_student),
path("del_students/", views.del_students),
path("edit_student/", views.edit_student),
]
这个是视图函数文件,处理URL分发的事件
# views.py 文件
from django.shortcuts import render
from django.shortcuts import HttpResponse
from app01 import models
import json
# Create your views here.
def students(request):
all_students = models.Student.objects.all()
all_classes = models.Classes.objects.all()
return render(request, "students.html",{
"all_students": all_students,
"all_classes": all_classes,
})
def add_student(request):
response = {'status':True,"message":None,"nid":None}
try:
username = request.POST.get("username")
age = request.POST.get("age")
gender = request.POST.get("gender")
cls_id = request.POST.get("cls_id")
print(username,age,gender,cls_id)
obj = models.Student.objects.create(
username=username,
age=age,
gender=gender,
cs_id=cls_id,
)
response["nid"] = obj.id
except Exception as e:
response["status"] = False
response["message"] = "用户输入错误"
import json
response_json = json.dumps(response)
return HttpResponse(response_json)
def del_students(request):
if request.method == "POST":
response = {"status":True}
try:
nid = request.POST.get("nid")
models.Student.objects.filter(id=nid).delete()
except Exception as e:
response["status"] = False
response_ret = json.dumps(response)
return HttpResponse(response_ret)
def edit_student(request):
response = {'code':1000, 'message': None}
if request.method == "POST":
try:
nid = request.POST.get("nid")
username = request.POST.get("username")
age = request.POST.get("age")
gender = request.POST.get("gender")
cs_id = request.POST.get("cls_id")
print(nid,username,age,gender,cs_id)
models.Student.objects.filter(id=nid).update(
username=username,
age=age,
gender=gender,
cs_id=cs_id,
)
except Exception as e:
response["code"] = 1001
response["message"] = str(e)
return HttpResponse(json.dumps(response))
下面这个是主文件了,就只有一个html文件,主要通信都是用ajax
# 这个是 student.html 文件
Title
添加
ID
姓名
年龄
性别
班级
操作
{% for foo in all_students %}
{{ foo.id }}
{{ foo.username }}
{{ foo.age }}
{% if foo.gender %}
男
{% else %}
女
{% endif %}
{{ foo.cs.title }}
{% endfor %}
添加按钮提示框,当用户输入有问题时就会提示 ’ 用户输入错误 ‘ ,
下面这个是编辑框,点击打开某个学生时会默认选中,
整个总体来说写的还是存在一个bug,例如在添加学生信息时,页面上是用 js 创建tr表格的,各种属性没有添加上去,
页面信息有时候用js添加比较好,不用刷新整个页面,而有时候是页面整个刷新为好,看各种情况了。
下面是总结呵,
1.
Python序列化
字符串 = json.dumps(对象) 对象->字符串
对象 = json.loads(字符串) 字符串->对象
JavaScript:
字符串 = JSON.stringify(对象) 对象->字符串
对象 = JSON.parse(字符串) 字符串->对象
应用场景:
数据传输时,
发送:字符串
接收:字符串 -> 对象
2. ajax
$.ajax({
url: 'http//www.baidu.com',
type: 'GET',
data: {'k1':'v1'},
success:function(arg){
// arg是字符串类型
// var obj = JSON.parse(arg)
}
})
$.ajax({
url: 'http//www.baidu.com',
type: 'GET',
data: {'k1':'v1'},
dataType: 'JSON',
success:function(arg){
// arg是对象
}
})
$.ajax({
url: 'http//www.baidu.com',
type: 'GET',
data: {'k1':[1,2,3,4]},
dataType: 'JSON',
success:function(arg){
// arg是对象
}
})
发送数据时:
data中的v
a. 只是字符串或数字
$.ajax({
url: 'http//www.baidu.com',
type: 'GET',
data: {'k1':'v1'},
dataType: 'JSON',
success:function(arg){
// arg是对象
}
})
b. 包含属组
$.ajax({
url: 'http//www.baidu.com',
type: 'GET',
data: {'k1':[1,2,3,4]},
dataType: 'JSON',
traditional: true, //// 要加这一句
success:function(arg){
// arg是对象
}
})
c. 传字典,或者将其转换成字符串
b. 包含属组
$.ajax({
url: 'http//www.baidu.com',
type: 'GET',
data: {'k1': JSON.stringify({}) },
dataType: 'JSON',
success:function(arg){
// arg是对象
}
})
3. 事件委托
$('要绑定标签的上级标签').on('click','要绑定的标签',function(){})
$('要绑定标签的上级标签').delegate('要绑定的标签','click',function(){})
4. 编辑
5. 总结
新URL方式: //也就是跳转到新页面的方式
- 独立的页面
- 数据量大或条目多
对话框方式:
- 数据量小或条目少
-增加,编辑
- Ajax: 考虑,当前页;td中自定义属性
- 页面(***)
删除:
对话框
这个就到这里了。路漫漫其修远兮
django 分页
补充:
写一个对页面分页的类,django的内置分页太丑了
# tests.py 文件,建立自定制的类
class couPaginator(object):
def __init__(self,totalCount,CurrentPage,perPageItemNum=30,maxPageNum=8):
# 数据总个数
self.total_count = totalCount
# 当前页
self.current_page = CurrentPage
# 每页最多显示的条数
self.per_page_item_num = perPageItemNum
# 最多显示页面
self.max_page_num = maxPageNum
self.check()
def check(self): # 检查数据,
try:
self.total_count = int(self.total_count)
self.current_page = int(self.current_page)
if self.current_page > self.num_pages: # 如果当前页大于最大页数
self.current_page=self.num_pages
if self.current_page <= 1: # 如果当前页小于等于1
self.current_page=1
except Exception as e:
pass
@property # 装饰器,可以使得函数不加 () 直接调用
def num_pages(self):
a,b=divmod(self.total_count,self.per_page_item_num) # 总数目/每页显示数据,返回整除和余数
if b==0:
return a
else:
return a+1
def start(self): # 返回 开始
return (self.current_page-1)*self.per_page_item_num
def end(self): # 返回结束
return self.current_page*self.per_page_item_num
@property
def pager_num_range(self): # 这个是分页函数,也就是页面下面的一排跳转页面
if self.num_pages <= self.max_page_num:
return range(1,self.num_pages+1)
if self.current_page <= self.max_page_num/2:
return range(1,self.max_page_num+1)
part = int(self.max_page_num/2)
if self.current_page+part>=self.num_pages+1:
return range(self.num_pages-self.max_page_num+1,self.num_pages+1)
return range(self.current_page-part,self.current_page+part)
def page_str(self): # 对上面的分页函数转成html,可以直接在模版渲染出来,不用再做另外的转换
test_list=[]
if self.current_page==1:
prev = "上一页 "
else:
prev = "上一页 " %(self.current_page-1)
if self.current_page==self.max_page_num:
next = "下一页 "
else:
next = "下一页 " %(self.current_page+1)
test_list.append(prev)
test_list.append(next)
for i in self.pager_num_range:
if i == self.current_page:
temp = "%s " %(i,i)
else:
temp = "%s " %(i,i)
test_list.append(temp)
first = "首页 "
last = "尾页 " %(self.num_pages)
test_list.append(first)
test_list.append(last)
return ' '.join(test_list)
模版文件
# index2.html 文件
Title
{% for foo in data %}
{{ foo.name }} - {{ foo.age }}
{% endfor %}
{{ test.page_str|safe }}
视图函数
# 视图函数,views.py 文件
test_list = [] # 创建数据
for i in range(999):
temp = {'name':'root'+str(i),'age':i}
test_list.append(temp)
def index2(request):
p = request.GET.get("p")
from app01.tests import couPaginator
test = couPaginator(999,p,perPageItemNum=10)
return render(request,"index2.html",{
"data":test_list[test.start():test.end()],
"test":test,
})
不要忘记在 urls.py 文件中添加路由导航,还有要在静态文件下添加bootstrap 文件,静态文件目录也需要配置
2.分页组件
- Django内置分页
- Paginator、 Page
- 页面:include
- 扩展Django的内置分页
- CustomPaginator(Paginator)
传入:
- 所有数据
- 当前页
- 每页显示30条
- 最多页面7个
- 自定义分页
传入:
- 所有数据的个数
- 当前页
- 每页显示30条
- 最多页面7个
form 表单验证,基本
调用 django 内置的 Form 组件,对前端的输入进行验证和返回错误提示信息,
# views.py 文件下的
from django import forms
from django.forms import fields
class F1form(forms.Form):
user = fields.CharField(
max_length=18, # 最长
min_length=6, # 最短
required=True, # 限制不能为空
error_messages={ # 自定制返回到前端的错误提示信息
"required": "用户名不能为空",
"max_length": "用户名太长",
"min_length": "用户名太短",
}
)
pwd = fields.CharField(
min_length=32,
required=True,
error_messages={
"min_length": "最短32个字符",
"required": "密码不能为空",
}
)
age = fields.IntegerField(
required=True,
error_messages={
"required": "年龄不能为空",
"invalid": "必须为数字",
}
)
email = fields.EmailField(
required=True,
error_messages={
"required": "邮箱不能为空",
"invalid": "邮箱格式错误",
}
)
def fm(request):
if request.method == "GET":
return render(request,"fm.html")
if request.method == "POST":
# user = request.POST.get("user")
# age = request.POST.get("age")
# pwd = request.POST.get("pwd")
# email = request.POST.get("email")
# print(user,age,pwd,email)
obj = F1form(request.POST)
if obj.is_valid():
print(obj.cleaned_data) # 验证通过获取到用户输入的数据
else:
print(obj.errors) # 验证失败返回错误信息
return render(request,"fm.html",{"obj":obj})
前端的html文件
# fm.html 文件,用obj.errors.user.0 来取到user错误信息的第一个,因为一个输入框会不止一个错误提示
Title
在URL路由文件urls.py 文件下要添加路径导航,
path('fm.html/', views.fm),
要注释掉 form 的锁 csrf
django内置的 forms 还能自己生成html代码,也就是输入框,所以, views.py 和 fm.html 文件也可以改成下面的,
# views.py 文件
def fm(request):
if request.method == "GET":
obj = F1form() # 改动的地方
return render(request,"fm.html",{"obj":obj}) # 还有这里
if request.method == "POST":
# user = request.POST.get("user")
# age = request.POST.get("age")
# pwd = request.POST.get("pwd")
# email = request.POST.get("email")
# print(user,age,pwd,email)
obj = F1form(request.POST)
if obj.is_valid():
print(obj.cleaned_data)
else:
print(obj.errors)
return render(request,"fm.html",{"obj":obj})
# html 文件中的 input 输入框就可以用 django 中的来代替了
Title
form 也可以验证ajax提交的数据,因为ajax提交的数据到服务器也是用post提取的,(具体看你ajax中type的设置了)
Form组件
- 对用户请求的验证
- AJax
- Form
- 生成HTML代码
a. 创建一个类
b. 类中创建字段(包含正则表达式)
c. GET
obj = Fr()
obj.user = > 自动生成HTML
d. POST
obj = Fr(request.POST)
if obj.is_valid():
obj.cleaned_data
else:
obj.errors
return .... obj
form 提交数据,验证数据的有效性,
我们可以自定制正则,也可以用django内置的规则,
# models.py 创建一个表格
from django.db import models
# Create your models here.
class userInfo(models.Model):
username = models.CharField(max_length=32)
email = models.EmailField(max_length=32)
# urls.py
from django.contrib import admin
from django.urls import path
from app01 import views
from django.conf.urls import url
urlpatterns = [
path('admin/', admin.site.urls),
path('users/', views.users),
path('add_user/', views.add_user),
url("^edit_user-(\d)$", views.edit_user), #这个是之前版本的路由导航
]
# fm.py 自创建的文件,放置 form 类
from django import forms
from django.forms import fields
class UserForm(forms.Form):
username = fields.CharField(
max_length=32,
required=True,
error_messages={ # 自定制错误提示信息
"required":"请输入用户名",
"max_length": "必须输入32个字符",
}
)
email = fields.EmailField(
required=True,
error_messages={
"required": "必须输入邮箱",
"invalid": "不是正确的邮箱格式",
}
)
# views.py
from django.shortcuts import render
from django.shortcuts import redirect
from app01 import models
from app01 import fm
def users(request): # 返回所有的数据,也就是所有表格的信息
data_list = models.userInfo.objects.all()
return render(request,"users.html",{"data_list":data_list})
def add_user(request): # 添加数据,跳转到add_user.html,
if request.method == "GET":
obj = fm.UserForm()
return render(request,"add_user.html",{"obj":obj})
if request.method == "POST": # post 接收数据,用form检测格式
obj = fm.UserForm(request.POST)
if obj.is_valid():
print(obj.cleaned_data)
models.userInfo.objects.create(**obj.cleaned_data) # 检测通过创建数据
return redirect("/users.html")
else:
return render(request,"add_user.html",{"obj":obj}) # 错误提示,返回错误信息
def edit_user(request,nid): # 编辑信息,使用form为我们写好的生成html,在edit_user.html中
if request.method == "GET":
data = models.userInfo.objects.filter(id=nid)[0] # nid 在ulrs.py 文件正则取得
obj = fm.UserForm({"username":data.username,"email":data.email})
return render(request,"edit_user.html",{"obj": obj,"nid":nid})
if request.method == "POST":
obj = fm.UserForm(request.POST)
if obj.is_valid():
print(obj.cleaned_data)
models.userInfo.objects.filter(id=nid).update(**obj.cleaned_data)
return redirect("/users")
else:
print(obj.errors) # 记得,返回错误信息时还要返回一次nid
return render(request,"edit_user.html",{"obj":obj,"nid":nid})
# users.html ----》user 函数(对应)
Title
添加
{% for foo in data_list %}
{{ foo.id }}
{{ foo.username }}
{{ foo.email }}
编辑
{% endfor %}
# add_user.html ----》add_user 函数
Title
# edit_user.html ----》edit_user
Title
Form组件
- form表单(验证;保留上次内容)
-
- Ajax(验证;无需上次内容)
- 返回HttpResponse
- 前端:跳转或错误信息
所谓的扩展
1. Form组件扩展:
1.简单扩展
利用Form组件自带的正则扩展:
a. 方式一
from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.validators import RegexValidator
class MyForm(Form):
user = fields.CharField(
error_messages={'invalid': '...'},
validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
)
b. 方式二
from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.validators import RegexValidator
class MyForm(Form):
user = fields.RegexField(r'^[0-9]+$',error_messages={'invalid': '...'})
2.基于源码流程
a. 单字段
from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
class AjaxForm(forms.Form):
username = fields.CharField()
user_id = fields.IntegerField(
widget=widgets.Select(choices=[(0,'alex'),(1,'刘皓宸'),(2,'杨建'),])
)
# 自定义方法 clean_字段名
# 必须返回值self.cleaned_data['username']
# 如果出错:raise ValidationError('用户名已存在')
def clean_username(self):
v = self.cleaned_data['username']
if models.UserInfo.objects.filter(username=v).count():
# 整体错了
# 自己详细错误信息
raise ValidationError('用户名已存在')
return v
def clean_user_id(self):
return self.cleaned_data['user_id']
b. 整体错误验证
class AjaxForm(forms.Form):
username = fields.CharField()
user_id = fields.IntegerField(
widget=widgets.Select(choices=[(0,'alex'),(1,'刘皓宸'),(2,'杨建'),])
)
# 自定义方法 clean_字段名
# 必须返回值self.cleaned_data['username']
# 如果出错:raise ValidationError('用户名已存在')
def clean_username(self):
v = self.cleaned_data['username']
if models.UserInfo.objects.filter(username=v).count():
# 整体错了
# 自己详细错误信息
raise ValidationError('用户名已存在')
return v
def clean_user_id(self):
return self.cleaned_data['user_id']
def clean(self):
value_dict = self.cleaned_data
v1 = value_dict.get('username')
v2 = value_dict.get('user_id')
if v1 == 'root' and v2==1:
raise ValidationError('整体错误信息')
return self.cleaned_data
PS: _post_clean
form结束了,就这些东西,扩展也并不是很多内容
2. Django序列化
a.对象
b.字典
c.元祖
===================================
首先能完成任务,
亮点,分为两种,一参加过某种大型的架构,二某种东西研究得特别深,那就研究,
1.笔试:
2.面试
方向:
- 基础
- 亮点
基础:
1.设计程序
2.开发
亮点:
某框架的源码:
Tornado - 异步非堵塞(IO多路复用)
关于序列化问题,也就是 Queryset 类型转成 json 类型,可以参考
博客:http://www.cnblogs.com/wupeiqi/articles/5246483.html
http://www.cnblogs.com/wupeiqi/articles/6144178.html
今天在编辑后丢了很多东西,好气啊
关于 NON_FIELD_ERRORS,也就是 all 了,下面是一个补充:
from django.shortcuts import render
from django.shortcuts import HttpResponse
from app01 import models
from django import forms
from django.forms import fields
from django.forms import widgets
from django.core.exceptions import ValidationError
class LoginForm(forms.Form):
username = fields.CharField(
max_length=32,
required=True,
error_messages={
'required':'请输入用户名',
'max_length':'最长输入32个字符',
},
widget=widgets.TextInput()
)
# def clean_username(self):
# v1 = self.cleaned_data['username']
# v2 = models.User.objects.filter(username=v1).first()
# if not v2:
# raise ValidationError("用户名错误") # 这个引发的错误会在errors.username显示
# return v1
password = fields.CharField(
max_length=32,
required=True,
error_messages={
'required':'请输入密码',
'max_length':'最长输入32个字符'
},
widget=widgets.PasswordInput()
)
def clean(self):
v1 = self.cleaned_data.get('username')
v2 = self.cleaned_data.get('password')
obj = models.User.objects.filter(username=v1).first()
if not obj:
raise ValidationError("用户名错误")
elif obj.password != v2:
raise ValidationError("密码错误")
return self.cleaned_data
from django.core.exceptions import NON_FIELD_ERRORS
def login(request):
if request.method == "GET":
obj = LoginForm()
return render(request,"login.html",{"obj":obj})
else:
obj = LoginForm(request.POST)
all_code = None
if obj.is_valid():
print(obj.cleaned_data)
return HttpResponse("登陆成功")
else:
print(obj.errors)
all_code = obj.errors[NON_FIELD_ERRORS]
# 在 template中没有 NON_FIELD_ERRORS,我只想到这个办法来传过去
return render(request,"login.html",{"obj":obj,"all_code":all_code})