zoukankan      html  css  js  c++  java
  • Web框架开发-Django-form组件

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

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

      

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

      4、Django的生命周期

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

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

     

    二、form组件

    一、Form组件介绍

    Form组件可以做的几件事情:

      1、用户请求数据验证

      2、自动生成错误信息    

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

      4、如果其中有一个错误了,其他的正确这,保留上次输入的内容

      4、自动创建input标签并可以设置样式

    二、Form组件的使用

      1、创建规则

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

      2、数据和规则进行匹配

    先导入view.py

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

    三、数据库表设计

    设计表时注意的几点:

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

      

    四、登录

     可设置一个装饰器

    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、一般配置文件的键都是大写的

     五、Form基本使用

    类
    字段
    is_valid()
    cleaned_data
    errors
    
    字段参数:
        max_length
        min_length
        validators = [RegexValidators("XXX")]
    
    钩子函数:
        clean_字段名
        注意:
            必须有返回值
            只能拿自己当前字段值
            raise ValidationError("XXX")
        
     下拉框数据源时时更新:
            1、重写init方法
                先执行父类构造方法
                self.fields["xx"].choices = XXXX
            2、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字段的值
        注意:在自己写钩子函数的时候,只能拿自己的字段不能拿别人的
        每一种字段就可以用 正则+自定义正则+自定义钩子函数
    

      

  • 相关阅读:
    征战蓝桥 —— 2015年第六届 —— C/C++A组第3题——奇妙的数字
    征战蓝桥 —— 2015年第六届 —— C/C++A组第3题——奇妙的数字
    征战蓝桥 —— 2013年第四届 —— C/C++A组第6题——逆波兰表达式
    征战蓝桥 —— 2013年第四届 —— C/C++A组第6题——逆波兰表达式
    征战蓝桥 —— 2013年第四届 —— C/C++A组第6题——逆波兰表达式
    信息学奥赛一本通(C++)在线评测系统——基础(三)数据结构 —— 1354:括弧匹配检验
    信息学奥赛一本通(C++)在线评测系统——基础(三)数据结构 —— 1354:括弧匹配检验
    C#通过反射对可空类型动态赋值的问题
    网段
    C#通过反射对可空类型动态赋值的问题
  • 原文地址:https://www.cnblogs.com/mike-liu/p/9784515.html
Copyright © 2011-2022 走看看