一, model 常用操作
1,13 个 API 查询: all,filter,get ,values,values_list,distinct,order_by ,reverse , exclude(排除),count,first,last,esits(判断是否存在)
需要掌握的 all,values,values_list 的区别
all: 打印的是一个 QuerySet 集合, 一个列表里面放的对象
values : 是一个字典形式
values_list: 是一个元组形式
all 的性能是最低的
2,only 和 defer
- datalist = models.Userinfo.objects.all().only("name","email") #拿到的还是一个 QuerySet 集合, 仅仅取 name 和 email
- for item in datalist:
- print(item.id)
- print(item.name)
- print(item.pwd) #只要表里有这个字段, 一样会取到值, 额外的会再发一次请求
- datalist = models.Userinfo.objects.all().defer("name","email") #阻止, 不取 name 和 email
- for item in datalist:
- print(item.id)
- print(item.pwd)
注意: 用 only 的话就去取 only 里面的字段, 取其他的字段效率太低了, 尽可能的少的连接数据库
3, 路由系统
反向生成 URL:
有两种方式:{% url "a1" %}
reverse("a1")
用 reverse 需要导入 from django.core.urlresolvers import reverse
- /index/ func name=a1
- {% url "a1"}
- reverse('a1')
- /index/(\d+)/ func name=a2
- {% url "a2" 11 %}
- reverse('a2',args=(11,))
- /index/(?P<nid>\d+)/ func name=a3
- {% url "a2" nid=11 %}
- reverse('a3',kwargs={'nid':11})
4,Django 的生命周期
web 服务器网关 https://baike.so.com/doc/3438331-3618438.html 接口 (Python Web Server Gateway Interface, 缩写为 WSGI)
1, 首先走 wsgi 模块, 这个模块也是一个协议, 包括 wsgiref 和 uwsgi.
2, 然后路由分配 -------views 视图
3, 从数据库取数据 ----------- 渲染到 HTML
注意如果导入 JS 文件, 是不会渲染的.
5,HTTP 协议
详见下一篇博客
二, Form 组件
一, Form 组件介绍
Form 组件可以做的几件事情:
1, 用户请求数据验证
2, 自动生成错误信息
3, 打包用户提交的正确信息
4, 如果其中有一个错误了, 其他的正确这, 保留上次输入的内容
4, 自动创建 input 标签并可以设置样式
二, Form 组件的使用
1, 创建规则
- class Foo(Form): #必须继承
- username = xxx
- password = xxx
- email = xxx
注意这里的字段必须和 input 的 name 字段一致
2, 数据和规则进行匹配
先导入 view.py
- from django.forms import Form
- from django.forms import fields
- from django.forms import widgets
- from django.shortcuts import render,redirect
- from app01 import models
- # Create your views here.
- from django.forms import Form
- from django.forms import fields
- from django.forms import widgets
- # 1, 创建规则
- class TeacherForm(Form): #必须继承 Form
- # 创建字段, 本质上是正则表达式
- username = fields.CharField(
- required=True, #必填字段
- error_messages={"required":"用户名不能为空!!"}, #显示中文错误提示
- widget=widgets.TextInput(attrs={"placeholder":"用户名","class":"form-control"}) #自动生成 input 框
- )
- password = fields.CharField(required=True, error_messages={'required': '密码不能为空'},
- widget=widgets.TextInput(attrs={'placeholder': '密码', 'class': 'form-control'})) # 不能为空
- email = fields.EmailField(
- required=True,
- error_messages={"required":"邮箱不能为空!!","invalid":"无效的邮箱"},
- widget=widgets.EmailInput(attrs={"placeholder": "邮箱", "class": "form-control"}) # 自动生成 input 框
- ) #不能为空且邮箱格式要一致
- # 2, 使用规则: 将数据和规则进行匹配
- def teacherindex(request):
- teacher_obj = models.UserInfo.objects.all()
- # print(teacher_obj)
- return render(request,"teacherindex.html",{"teacher_obj":teacher_obj})
- def add(request):
- if request.method=="GET":
- form = TeacherForm() #只是让显示一个 input 框
- return render(request,"add.html",{"form":form })
- else:
- form = TeacherForm(data=request.POST)
- # print(form) #<QuerySet [<UserInfo: UserInfo object>, <UserInfo: UserInfo object>, <UserInfo: UserInfo object>]>
- if form.is_valid():# 开始验证
- # print('执行成功',form.cleaned_data) # 所有匹配成功, 字典
- # {'username': 'asd', 'password': 'sdf', 'email': 'sadf@live.com','ut_id':1}
- form.cleaned_data['ut_id'] = 1 #要分的清是班主任还是讲师
- models.UserInfo.objects.all().create(**form.cleaned_data)
- return redirect("/teacherindex/")
- else:
- # print("=====?",form.errors,type(form.errors))# 返回失败的结果
- # print(form.errors["username"][0]) #拿到返回失败的结果, 渲染到页面
- return render(request,"add.html",{"form":form})
HTML.py
- {% block right %}
- <h1 > 添加老师信息 </h1>
- <hr>
- <form method="post" novalidate>
- {% csrf_token %}
- <p > 姓名:{{ form.username }}</p>{{ form.errors.username.0 }}
- <p > 密码:{{ form.password }}</p>{{ form.errors.password.0 }}
- <p > 邮箱:{{ form.email }}</p>{{ form.errors.email.0 }}
- <p><input type="submit" value="提交"></p>
- </form>
- {% endblock %}
如果访问视图的是一个 GET 请求, 它将创建一个空的表单实例并将它放置到要渲染的模板的上下文中. 这是我们在第一个访问该 URL 时预期发生的情况.
如果表单的提交使用 POST 请求, 那么视图将再次创建一个表单实例并使用请求中的数据填充它: form = NameForm(request.POST). 这叫做 "绑定数据至表单"(它现在是一个绑定的表单).
我们调用表单的 is_valid() 方法; 如果它不为 True, 我们将带着这个表单返回到模板. 这时表单不再为空 (未绑定), 所以 HTML 表单将用之前提交的数据填充, 然后可以根据要求编辑并改正它.
如果 is_valid() 为 True, 我们将能够在 cleaned_data 属性中找到所有合法的表单数据. 在发送 HTTP 重定向给浏览器告诉它下一步的去向之前, 我们可以用这个数据来更新数据库或者做其它处理.
注意: form = TeacherForm() #没有参数, 只是一个 input 框
- form = TeacherForm(data=request.POST) # 数据和规则放置一起 (添加的时候用)
- form = TeacherForm(initial={
- 'username':obj.username,'password':obj.password,'email':obj.email
- }) # 显示 input, 并且将数据库中的默认值填写到 input 框中 (编辑的时候用)
- Widgets
每个表单字段都有一个对应的 Widget 类, 它对应一个 HTML 表单 Widget, 例如 < input type="text">.
在大部分情况下, 字段都具有一个合理的默认 Widget. 例如, 默认情况下, CharField 具有一个 TextInput Widget, 它在 HTML 中生成一个 < input type="text">.
字段的数据
不管表单提交的是什么数据, 一旦通过调用 is_valid() 成功验证 (is_valid() 返回 True), 验证后的表单数据将位于 form.cleaned_data 字典中. 这些数据已经为你转换好为 Python 的类型.
注: 此时, 你依然可以从 request.POST 中直接访问到未验证的数据, 但是访问验证后的数据更好一些.
在上面的联系表单示例中, is_married 将是一个布尔值. 类似地, IntegerField 和 FloatField 字段分别将值转换为 Python 的 int 和 float.
三, 数据库表设计
设计表时注意的几点:
- 1, nid = models.AutoField(primary_key=True) #如果不指定 django 会默认加上 id 的
- nid = models.BigAutoField(primary_key=True) #但那些整型满足不了你的时候, 就用 BigAutoField
2, 对于类的注释一般加在类里面
3,verbose_name="标题" 字段的中文提示
4,ForeignKey(to = "表名",tofield= "字段") #这两个 to 可以不用写, 但是关联的表名一定要写
5,releated_name = "uuu" 反向查询. 如果一个表中有多个 ManyTwoMany() 或者 ForeignKey() 必须加上 releated_name
6, 字段经常变动的适合连表
字段变化小, 不怎么变的适合在一个表中, 不进行连表: 就用 choices
把班主任和老师可以放到一个表中, 因为他们有相同的属性, 如果属性全是一样的, 可以放在一个表里 (推荐)
也可以分开放, 老师表是老师表, 班主任表是班主任表. 这样就会进行连表操作, 连表有性能消耗.
举例: 文章和文章类型
分析: 一个文章有一个类型, 一个类型可以对应多个文章 (所以文章和文章类型是一对多的关系, 关联字段要放在多的一方)
一: 连表设计:
- class News(models.Model):
- title = models.CharField(max_length=32)
- summary = models.CharField(max_length=255)
- news_type = models.ForeignKey(to="NewsType")
- class NewsType(models.Model):
- type_title = models.CharField(max_length=32)
- News:
- id title summary news_type_id
1 t.... 科技... 2
2 t.... 科技... 1
3 t.... 科技... 2
- NewsType:
- id title
1 图片
2 挨踢 1024
3 段子
- # 查看所有新闻
- new_list = models.News.objects.all()
- for row in new_list:
- print(row.title,row.summary,row.news_type.title)
二 : 放在一个表中的操作: choices
- class News2(models.Model):
- title = models.CharField(max_length=32)
- summary = models.CharField(max_length=255)
- news_type_chices = (
- (1, '图片'),
- (4, '挨踢 1024'),
- (3, '段子'),
- )
- news_type = models.IntegerField(choices=news_type_chices)
- # 查看所有新闻
- new_list = News.objects.all()
- for row in new_list:
- print(row.title,row.summary, row.get_news_type_display() )
举例二: 用户和用户类型
一: 连表设计
- class UserType(models.Model):
- """
- 用户类型表, 个数经常变动
- """
- title = models.CharField(max_length=32)
- class UserInfo(models.Model):
- """
- 用户表: 讲师和班主任
- """
- username = models.CharField(max_length=32)
- password = models.CharField(max_length=64)
- email = models.CharField(max_length=32)
- ut = models.ForeignKey(to="UserType")
二: 不连表设计: choices
- class UserInfo(models.Model):
- # """
- # 用户表
- # """
- username = models.CharField(max_length=32)
- password = models.CharField(max_length=64)
- email = models.CharField(max_length=32,verbose_name="邮箱")
- user_type_choices = (
- (1, '班主任'),
- (2, '讲师'),
- )
- user_type_id = models.IntegerField(choices=user_type_choices)
四, 登录
可设置一个装饰器
- def auth(func):
- def inner(request,*args,**kwargs):
- is_login = request.session.get("is_login", None)
- if not is_login:
- return redirect("/login/")
- ret = func(*args,**kwargs)
- return ret
- return inner
需要注意的:
1,action 不写路径, 默认提交到当前
2, 向后台提交数据用 post, 获取数据用 get
3,submit 一般加上 value, 有些浏览器可能会不识别
4, 一般配置文件的键都是大写的
来源: http://www.bubuko.com/infodetail-2927258.html