- 目录
- 1、django创建项目和修改表:
- 1.1、创建项目:
- 2.1、修改表:
- 2、前端模板:
- 3、ORM:
- 3.1、表单的初始化(常用):
- 3.2、查询:
- 4、表单:
- 4.1、普通处理:
- 4.2、Form:
- 4.3、ModelForm(管理功能的表单最常用):
- 4.3.1、初始样式:
- 4.3.2、不过如果想要在表单中初始化内容,则需要在数据库表中定义:
- 4.3.3、表单只输入部分属性时:
- 4、下面讲讲输入校验:
- 4.4.1、普通路由方法的校验:
- 4.4.2ajax的输入校验:
- 5、分页小组件(自定义组件):
- 6、登录功能:
- 6.1、登录功能时,中间件的使用:
- 6.2、session的使用:
1、django项目初始化和数据库初始化:
1.1、项目:
1.1.1、创建项目:
直接在pycharm中创建django项目,然后删掉默认的template文件和将settings中的这一句
改成
1.1.2、创建app:
然后就创建号一个app文件了,名字可随意。
创建完app后记得到settings文件进行注册
1.1.3、创建数据库连接:
记得要先创建对应数据库
DATABASES = {
"default": {
"ENGINE": "django.db.backends.mysql",
"NAME": "work",
"USER": "root",
"PASSWORD": "",
"HOST": "127.0.0.1",
"PORT": "3306",
}
}
1.1.4、修改编码:
1.2、表:
1.2.1、创建和修改表:
例如
from django.db import models
# Create your models here.
class Admin(models.Model):
username=models.CharField(verbose_name="用户名",max_length=32)
password=models.CharField(verbose_name="密码",max_length=64)
在终端轮流执行这两个。注意不可后期添加属性,要么删表重建,要么全部设置默认值
python manage.py makemigrations
python manage.py migrate
2、前端模板:
定义一个模板文件后,在模板文件中
。。。。。。
<div>
{% block 自定义名1 %}{% endblock %}
</div>
。。。。。。
这样,就可以在别的文件里直接这样写
{% extends '自定义模板文件名' %}
{% block 自定义名1 %}
不同的代码部分
{% endblock %}
PS:“content”这个字符可自行定义
3、ORM:
3.1、表单的初始化(常用):
模板案例
class X(models.Model):
level_choices=(
(1,"紧急"),
(2,"重要"),
(3,"临时")
)
level=models.SmallIntegerField(verbose_name="级别",choices=level_choices,default=1)
title=models.CharField(verbose_name="标题",max_length=64)
detail=models.TextField(verbose_name="详细信息")
price=models.IntegerField(verbose_name="价格")
account=models.DecimalField(verbose_name="余额",max_length=10,max_digits=10,decimal_places=2,default=0)
级联删除,当Admin中某用户对象删除后,对应关联的x表中的x对象也全部删除
user=models.ForeignKey(verbose_name="负责人",to="Admin",to_fields="id"(这个可以不写),on_delete=models.CASCADE)
price = models.FloatField(。。。)
class Admin(..):
..
3.2、查询:
//按照id倒序获取所有行对象
queryset=models.Order.objects.all().order_by('-id')
//删除行对象
models.Order.objects.filter(id=uid).delete()
//获取某种属性
queryset=AllTable.objects.values('types')
或 queryset=AllTable.objects.values('title','cover','rate','directors','actors','year','language','country','types','comments','movieUrl')
4、表单:
重点!!:
<form method="post">
{% csrf_token %} 一定不要忘了这个
表单中的选择属性可以这样():
在定义数据表时:
gender_choices=(
(1,"男"),
(2,"女"),
)
gender=models.SmallIntegerField(verbose_name="性别",choices=gender_choices)#性别
这样就可以在定义这个时:
class UserModelFrom(forms.ModelForm):
class Meta:
model=models.UserInfo
fields=["name","password","age","account","create_time","gender","depart"]
# class Meta:
# model=models.Task
# fields="__all__" 这直接取所有属性
def user_add(request):
if request.method=="GET":
form=UserModelFrom()
return render(request,'user_add.html',{"form":form})
这样直接把gender传到前端,就能实现表单选择初始化了。
<th>{{ i.age }}</th>
<th>{{ i.account }}</th>
<th>{{ i.create_time|date:"Y-m-d" }}</th>#这是年月日格式化
<th>{{ i.get_gender_display }}</th>#这是数据在当前表的情况
<td>
另一种情况:
当depart在另一个表里时,由于表单传递的是depart的具体对象,想要获取name比较麻烦。在该表加上那个函数,这样直接调用该对象时,就会返回一个自定义值
class Department(models.Model):
name=models.CharField(max_length=32)#部门名
def __str__(self):
return self.name
<th>{{ i.depart.name }}</th>#这是前端对应代码
PS:之所以要这么搞,是因为整型数存储消耗比字符少
4.1、普通处理:
例如
def user_add(request):
if request.method=="GET":
models.UserInfo.之类的
#提交数据
name=request.POST.get('name')
password=request.POST.get('password')
。。。。。。。。。
这样写很麻烦,每一个属性都要手动处理,而且还要考虑校验的问题
4.2、Form:
直接在myform进行定制
然后在前端:
4.3、ModelForm(管理功能的表单最常用):
4.3.1、初始样式:
要在对应路由函数前定义:
这是自己定制输入框的麻烦方法
class UserModelFrom(forms.ModelForm):
class Meta:
model=models.UserInfo
fields=["name","password","age","account","create_time","gender","depart"]
fields是包含xx属性,exclude=['oid']则是除xx外,fields=“__all__”则是所有
就是这
widgets={
"name": forms.TextInput(attrs={"class": "form-control", "placeholder": UserInfo._meta.get_field('name').verbose_name})
}
#这个是用便捷函数的方法
class UserModelFrom(forms.ModelForm):
class Meta:
model=models.UserInfo
fields=["name","password","age","account","create_time","gender","depart"]
def __init__(self,*args,**kwargs):
super().__init__(*args,**kwargs)
for name,field in self.fields.items():
field.widget.attrs={"class":"form-control","placeholder":field.label}
def user_add(request):
if request.method=="GET":
form=UserModelFrom()
return render(request,'user_add.html',{"form":form})
这样就可以在路由函数中使用form了。而且可以通过widgets对表单输入框进行定制。
下面是封装继承的方法,这样就可以把BootStrapModelForm(这个类可自定义)作为父类,封装到另一个专门放置类的文件里面进行引用,让后续的表单继承
from django import forms
class BootstrapModelForm(forms.ModelForm):
def __init__(self,*args,**kwargs):
super().__init__(*args, **kwargs)
# 循环ModelForm中的所有字段,给每个字段的插件设置
for name,field in self.fields.items():
# 字段中有属性,保留原来的属性,没有属性,才增加。
if field.widget.attrs:
field.widget.attrs["class"] ="form-control"
field.widget.attrs["placeholder"] = field.label
else:
field.widget.attrs = {
"class": "form-control",
"placeholder":field.label
}
这样就可以使用了
4.3.2、不过如果想要在表单中初始化内容,则需要在数据库表中定义:
例如
class UserInfo(models.Model):
name = models.CharField(verbose_name="姓名",max_length=32)
password = models.CharField(verbose_name="密码",max_length=64)
age = models.IntegerField(verbose_name="年龄",null=True, blank=True)
这里的verbose_name="年龄"可以通过form传到前端,然后在前端
这个是用简便函数处理的,所有field.label就是verbose_name。后端只要提供form,就能生成相应表单
<form method="post">
{% csrf_token %}
{% for field in form %}
<div class="form-group">
<label>{{ field.label }}</label>
{{ field }}
<span>{{ field.errors.0 }}</span>#这是错误原因反馈
</div>
{% endfor %}
<button type="submit" class="btn btn-primary">提交</button>
</form>
上面的初始化内容只是静态内容,如果我想初始化的是表中原有的数据。比如编辑数据的时候:
PS:重点instance
def user_edit(request,id):
#这可以获得一个行对象
row_object = models.UserInfo.objects.filter(id=id).first()
if request.method=="GET":
form =UserModelFrom(instance=row_object) #instance=row_object这里用该对象进行填充
return render(request,'user_edit.html',{'form':form})
form=UserModelFrom(data=request.POST,instance=row_object)#这里的instance=row_object起到了覆盖当前对象的作用,这样就不会新添一行了。
if form.is_valid():
print(form.cleaned_data)
form.save()
return redirect('/user/list/')
return render(request,'user_edit.html',{"form":form})
讲一种几种特殊情况
class PrettyEditForm(forms.ModelForm):
让mobile不可改
mobile=forms.CharField(disabled=True,label="手机号")
class Meta:
model=models.PrettyNum
fields=["mobile","price","level","status"]#或者直接在这去掉mobile
class AdminModelForm(forms.ModelForm):
加一个确认密码的框
confirm_password=forms.CharField(label="确认密码")
class Meta:
model=models.Admin
fields=["username","password"]
def __init__(self,*args,**kwargs):
super().__init__(*args,**kwargs)
for name,field in self.fields.items():
field.widget.attrs={"class":"form-control","placeholder":field.label}
由此可见,如果想对表单进行操作,可以考虑在modelform类里进行操作
4.3.3、表单只输入部分属性时:
@csrf_exempt
def order_add(request):
form=OrderModelFrom(data=request.POST)
if form.is_valid():
oid属性数据可以在这里加上
form.instance.oid=“自己想加啥就加啥”
form.save()
data_dict={"status":True}
return JsonResponse(data_dict)
data_dict={"status":False,'error':form.errors}
return JsonResponse(data_dict)
4、下面讲讲输入校验:
4.4.1、普通路由方法的校验:
def user_add(request):
if request.method=="GET":
form=UserModelFrom()
return render(request,'user_add.html',{"form":form})
form=UserModelFrom(data=request.POST)#校验
if form.is_valid():
form.cleaned_data是表单验证通过后输入的所有数据,类型为字典
print(form.cleaned_data)
form.save()这是判断无误后快速插入数据库操作
return redirect('/user/list/')
return render(request,'user_add.html',{"form":form})
结合上面的 <span>{{ field.errors.0 }}</span>进行使用
如果想要对输入校验进行定义,则
class UserModelFrom(forms.ModelForm):
在这定义例如:
name=forms.CharField(min_lenth=3,label=“用户名”)
这样就对name这一行的输入框进行了一些定义
class Meta:
model=models.UserInfo
fields=["name","password","age","account","create_time","gender","depart"]
.........
也可以用钩子方法:
例如:
from django.core.exceptions import ValidationError
class PrettyModelForm(forms.ModelForm):
class Meta:
model=models.PrettyNum
fields=["mobile","price","level","status"]
def __init__(self,*args,**kwargs):
super().__init__(*args,**kwargs)
for name,field in self.fields.items():
field.widget.attrs={"class":"form-control","placeholder":field.label}
所谓钩子函数,其实就是自定义添加一个form.is_valid()里的判断功能。
def clean_mobile(self):
txt_mobile=self.cleaned_data["mobile"]
exists=models.PrettyNum.objects.filter(mobile=txt_mobile).exists()#防止输入重复
if exists:
raise ValidationError("手机号已存在")
if len(txt_mobile)!=11:#防止长度不符合
raise ValidationError("格式错误")
return txt_mobile
def prettynum_add(request):
if request.method=="GET":
form=PrettyModelForm()
return render(request,'prettynum_add.html',{'form':form})
form=PrettyModelForm(data=request.POST)
if form.is_valid():
print(form.cleaned_data)
form.save()
return redirect('/prettynum/list/')
return render(request,'prettynum_add.html',{'form':form})
报错信息都包含在form里了,所以如果想添加报错信息,可以这样:form.add_error("password","用户名或密码错误"),这样错误信息就能通过password属性调用了
如:<span style="color: red">{{ form.password.errors.0 }}</span>
4.4.2ajax的输入校验:
如例。
@csrf_exempt
def task_add(request):
form=TaskModelForm(data=request.POST)
if form.is_valid():
form.save()
data_dict = {"status": True}
return JsonResponse(data_dict)
data_dict={"status":False,'error':form.errors}
return JsonResponse(data_dict)
定义data_dict是为了更好的在前端看到反馈,如:
success: function (res) {
if (res.status) {
alert("添加成功"); 成功的弹窗
} else {
将data_dict的error报错字典信息拆成 name、data两部分
name用于定位输入框,data作为文本形式返回。具体语法参考jquery笔记。
$.each(res.error, function (name,data) {
console.log(name,data);
$("#id_" + name).next().text(data[0])
})
}
}
如果需要清空错误信息,可参考:
利用类绑定<span class="error-msg" style="color: red;position: absolute"></span>
function binBtnAddEvent() {
$("#btnadd").click(function () {
$(".error-msg").empty()
$.ajax({........
这样每次提交数据时,都会对原来的错误进行empty()清空,重新生成错误。
5、分页小组件(自定义组件):
可以直接使用。功能较为全面
例如
导入提前写好的
from app01.utils.page import Pagination
def admin_list(request):
queryset=models.Admin.objects.all()
#下面这个是组件的使用方法
page_object=Pagination(request,queryset)
context={
"queryset":page_object.page_queryset,
"page_string":page_object.html()
}
return render(request,'admin.html',context)
前端:
<ul class="pagination">
{{ page_string }}
</ul>
6、登录功能:
以下是简易登陆界面模板。可以直接参考
<style>
.account {
width: 400px;
border: 1px solid #dddddd;
border-radius: 5px;
box-shadow: 5px 5px 20px #aaa;
margin-left: auto;
margin-right: auto;
margin-top: 100px;
padding: 20pX 40pX;
}
.account h2 {
margin-top: 10px;
text-align: center;
}
</style>
<div class="account">
<h2>用户登录</h2>
<form>
<div class="form-group">
<label >用户名</label>
<input type="text" class="form-control" placeholder="用户名"></div>
<div class="form-group">
<label >密码</label>
<input type="password" class="form-control" placeholder="密码">
</div>
<input type="submit" value="登 录" class="btn btn-primary"></form>
</div>
表单部分可以用这两种方法,效果一样的
from django.shortcuts import render,redirect
from django import forms
Form的方法
class LoginForm(forms.Form):
username=forms.CharField(label="用户名")
password=forms.CharField(label="密码")
ModelForm的方法
from app01 import models
class LoginModelForm(forms.ModelForm):
class Meta:
model=models.Admin
fields=['username','password']
可以直接在表单内定义样式,这样直接将表单传给前端,前端就不用自己写表单了
6.1、登录功能时,中间件的使用:
原理,每个网络请求都会需要经过中间件:
定义中间件:
最好新建一个目录文件存放中间件文件
from django.utils.deprecation import MiddlewareMixin
class M1(MiddlewareMixin):
def process_request(self,request):
这个函数里面可以自己定义,如果返回为空,则该网站访问可以进行下去。
例如:
class M1(MiddlewareMixin):
def process_request(self,request):
if request.path_info=="/login/": 这里是获取当前访问的url
return
获取session中的登录字典,如果有,则说明已登录,没有则跳转到登录界面
这个东西也可以放在每个页面的视图函数开头进行一波判断,但是很麻烦。
info_dict=request.session.get("info")
if info_dict:
return
return redirect('/login/')
#def process_response(self,request,response):
# print("zou")
setting.py中注册使用该中间件:
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',
'app01.middieware.login.M1', <--------这个
]
6.2、session的使用:
例如,在登陆函数中
def login(request):
if request.method=="GET":
form = LoginForm()
return render(request,'login.html',{'form':form})
form = LoginForm(data=request.POST)
if form.is_valid():
print(form.cleaned_data)
admin_object=models.Admin.objects.filter(**form.cleaned_data).first()
if not admin_object:
form.add_error("password","用户名或密码错误")
return render(request, 'login.html', {'form': form})
里将登录表单数据存到session中。注意,request.session["info"]是一个字典
request.session["info"]={'id':admin_object.id,'name':admin_object.username} 这。
return redirect("/admin/list")
return render(request,'login.html',{'form':form})
后面如果用到session里的数据的话:
方法1:
直接在调用后端返回的request对象,这样就可以获取session字典中name值了
aria-expanded="false">{{ request.session.info.name }}<span class="caret"></span></a>
方法2:
在后端的对应视图函数中,通过 info_dict=request.session["info"]
获取到session字典。再通过将字典info_dict返回给前端即可调用。其实原理和方法1一样.