Web框架开发-Django-form组件

django 之知识点总结以及Form组件

1、model经常使用操做html

  一、13个API查询:all,filter,get ,values,values_list,distinct,order_by ,reverse , exclude(排除),count,first,last,esits(判断是否存在)python

  须要掌握的all、values、values_listweb

  • all:打印的是一个QuerySet集合,一个列表里面放的对象
  • values:是一个字典形式
  • values_list:是一个元组形式

all的性能是最低的正则表达式

  二、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里面的字段,取其它的字段效率过低了,尽量的少的链接数据库django

  三、路由系统浏览器

  反向生成URL:服务器

    有两种方式:{% url “a1” %}session

          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})

  

def index(request):
    if request.method == "POST":
        """
        两个return是同样的,用url反向解析就至关于下面的路径在urls里面
        协商别名name="index",但在模板中仍是要用{%url"index"%}
        """
       # return redirect(reverse(index))
        return redirect("index.html")   # 跳转到我的主页
    return render(request, "hh.html")

  四、Django的生命周期

  web服务器网关接口(Python Web Server Gateway Interface,缩写为WSGI)

  1.   首先走wsgi模块,这个模块也是一个协议,包括wsgiref和uwsgi
  2. 而后路由分配---------views视图
  3. 从数据库取数据--------渲染到HTML

 

2、form组件

1、Form组件介绍

Form组件能够作的几件事情:

  一、用户请求数据验证

  二、自动生成错误信息    

  三、打包用户提交的正确信息

  四、若是其中有一个错误了,其余的正确这,保留上次输入的内容

  四、自动建立input标签并能够设置样式

2、Form组件的使用

  一、建立规则

class Foo(Form)    # 必须继承
        username = XXX
        password = XXX
        email = XXX
注意这里的字段必须和input字段一致

  二、数据和规则进行匹配

先导入view.py

from django.forms import Form
from django.forms import fields
from django.forms import widgets

  

# 一、建立规则
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={"requeired": "邮箱不能为空!",
                        "invalid": "无效的邮箱格式"},
        widget=widgets.EmailInput(attrs={"placeholder":"邮箱", "class": "form-control"})
    )


# 二、使用规则:将数据和规则进行匹配
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)

        if form.is_valid(): # 开始验证
            form.cleaned_data['ut_id'] = 1  # 要分的清是班主任仍是讲师
            models.UserInfo.objects.all().create(**form.cleaned_data)
            return redirect("/teacherindex/")

        else:
            return render(request, "add.html", {"form": form})

  add.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>添加老师信息</title>
</head>
<body>
<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>

</body>
</html>

  

teacherindex.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-md-8">
            <table class="table-bordered table-striped">
                <thead>
                    <tr>
                        <th>编号</th>
                        <th>姓名</th>
                        <th>邮箱</th>
                    </tr>
                </thead>
                <tbody>
                    {% for teacher in teacher_obj %}
                    <tr>
                        <td>{{ teacher.id }}</td>
                        <td>{{ teacher.username }}</td>
                        <td>{{ teacher.email }}</td>
                    </tr>
                    {% endfor %}
                </tbody>
            </table>
        </div>
    </div>
</div>

</body>
</html>

  

  若是访问视图的是一个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

3、数据库表设计

设计表时注意的几点:

  一、 nid = models.AutoField(primary_key=True)        #若是不指定django会默认加上id的

    nid = models.BigAutoField(primary_key=True)   #但那些整型知足不了你的时候,就用BigAutoField

  二、对于类的注释通常加在类里面

  三、verbose_name=“标题”   字段的中文提示

  四、ForeignKey(to = "表名",tofield= "字段")    #这两个to能够不用写,可是关联的表名必定要写

  五、releated_name = "uuu"   反向查询。若是一个表中有多个ManyTwoMany()或者ForeignKey()必须加上releated_name 

  六、字段常常变更的适合连表

     字段变化小,不怎么变的适合在一个表中,不进行连表:就用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
   t....    科技...     2
   t....    科技...     1
   t....    科技...     2
NewsType:
 id    title
     图片
     挨踢1024
     段子
 
# 查看全部新闻
				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)

  

4、登陆

 可设置一个装饰器

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

  

 须要注意的:  

  一、action不写路径,默认提交到当前 

  二、向后台提交数据用post,获取数据用get

  三、submit通常加上value,有些浏览器可能会不识别

  四、通常配置文件的键都是大写的

 5、Form基本使用

类
字段
is_valid()
cleaned_data
errors

字段参数:
    max_length
    min_length
    validators = [RegexValidators("XXX")]

钩子函数:
    clean_字段名
    注意:
        必须有返回值
        只能拿本身当前字段值
        raise ValidationError("XXX")
    
 下拉框数据源时时更新:
        一、重写init方法
            先执行父类构造方法
            self.fields["xx"].choices = XXXX
        二、ModelChoiceField

  用户登陆

- form的字段能够定义正则表达式
            password = fields.CharField(
                required=True,
                min_length=3,
                max_length=18,
                error_messages={
                    'required': '密码不能为空',
                    'min_length': '密码长度不能小于3',
                    'max_length': '密码长度不能大于18',
                    'invalid': '密码格式错误',
                },
                validators=[RegexValidator('\d+','只能是数字') ]
            )
            注意:error_messages的优先级比validators高

 

class LoginForm(Form):
    username = fields.CharField(
        required=True,  #必填字段
        min_length=3,
        max_length=16,
        error_messages={
            "required":"用户名不能为空",
            "min_length":"长度不能小于3",
            "max_length":"长度不能大于16"
        },
        widget=widgets.TextInput({"placeholder":"username","class":"form-control"})
    )
    password = fields.CharField(
        required=True,
        min_length=3,
        max_length=16,
        error_messages={
            "required": "密码不能为空",
            "min_length": "密码长度不能小于3",
            "max_length": "密码长度不能大于16",
            # "invalid":"密码格式错误"
            # error_messages的优先级高,若是写上"invalid":"密码格式错误"这个就会优先显示这个错误
        },
        widget=widgets.PasswordInput({"placeholder":"password","class":"form-control"}),
        validators=[RegexValidator("\d+","密码只能是数字")]  #能够进行正则匹配提示错误
    )

    def clean_username(self):
        user = self.cleaned_data["username"]
        is_exits = models.UserInfo.objects.filter(username=user).count()
        if not is_exits:
            raise ValidationError("用户名和密码错误")
        return user   #必须有return

  

- 主动向form中添加错误信息
  # form.add_error('password','用户名或密码错误')
  form.add_error('password',ValidationError('用户名或密码错误'))
  这两个均可以,建议用第二个 

 

Form扩展(钩子函数)

若是对username作扩展
#先作正则表达式判断
#而后自定义方法验证:也就是clean_xx,称为钩子函数

def clean_username(self):
        #能够写本身的验证提示
        不像validators只写正则表达式。在这里能够随意写
        user=self.clean_data["username"]
        is_esits = models.UserInfo.objects.filter(username=user).count()
        if not is_esits:
            raise validationError("用户名不存在")
        return user   #必须有返回值
    若是 def clean_username(self):  只能取password字段的值
    若是 def clean_username(self):  只能取username字段的值
    注意:在本身写钩子函数的时候,只能拿本身的字段不能拿别人的
    每一种字段就能够用 正则+自定义正则+自定义钩子函数
相关文章
相关标签/搜索