zoukankan      html  css  js  c++  java
  • django+xadmin在线教育平台(五)

    3-3 django orm介绍与model设计

    上节教程完成后代码(来学习本节前置条件):

    对应commit: 留言板前端页面展示。本次内容截止教程3-2结束。

    可能现在你还在通过手写sql语句来操作数据库,当我们有了orm,数据库操作变得很简单。这一小节我们来学习Django中的orm。

    原生sql 与 orm

    没有orm 的情况下message/views.py代码:

    import MySQLdb
    
    # 使用原生sql获取书的列表
    def book_list(request):
        # 创建到数据库的连接: 指明用户名,数据库,密码
        db = MySQLdb.connect(user = 'me', db='mydb', passwd='secret', host='localhost')
        # 创建一个游标对象执行器
        cursor = db.cursor()
        # 书写我们需要的sql语句
        cursor.execute('SELECT name FROM books ORDER BY name')
        # 对于fetchall()的结果做遍历,将遍历回来的结果当做数组,取第0个值name。
        names = [row[0] for row in cursor.fetchall()]
        db.close()
    

    可不可以让数据库字段的查询和使用类的一个属性一样简单?没错登登登:orm上场了

    book:name
    
    book.name
    book.save()
    

    Django的orm就是为了让我们不再写上面那样的语句,而是像使操作数据库像使用类和类属性一样。

    创建我们的models

    verbose_name:对象的人类可读的名称,单数:

    verbose_name = "pizza"
    
    class Meta,内嵌于 UserMessage 这个类的定义中
    如果 class Publisher 是顶格的,那么 class Meta 在它之下要缩进4个空格--按 Python 的传统
    你可以在任意一个 模型 类中使用 Meta 类,来设置一些与特定模型相关的选项。
    如:设置ordering = ['name'],默认地都会按 name 字段排序
    

    message/models.py:

    # 继承于django.db.models.Model
    class UserMessage(models.Model):
        # 设置最大长度,verbose_name在后台显示字段会用到
        name = models.CharField(max_length=20, verbose_name=u"用户名")
        # Django提供内置的邮箱字段会帮忙验证` default_validators = [validators.validate_email]`
        email = models.EmailField(verbose_name=u"邮箱")
        address = models.CharField(max_length=100, verbose_name=u"联系地址")
        message = models.CharField(max_length=500, verbose_name=u"留言信息")
    
    
        class Meta:
            verbose_name = u"用户留言信息"
            # db_table ,这里我们让它自动生成所以不用指定
    

    这时我们执行makemigrations messages会发现并没有改动。

     
    mark

    因为setting中我们没有注册我们的app: message

    注意:新建的app都要在setting中注册

    在setting中注册我们的app

    DjangoGetStarted/settings.py 大概36行INSTALLED_APPS:

    `INSTALLED_APPS`
    [
        前面的不用变,后面新增下一行
        'message'
    ]
    

    这时候我们重新运行Tools 菜单下 Run manage.py Task会提示:

    如果提示:

    SyntaxError: Non-ASCII character 'xe7' in file D:CodeSpacePythonProjectDjangoGetStartedappsmessagemodels.py on line
    

    请注意可能你忘记在写过中文的地方加上:

    #coding: utf-8
    

    注意必须加在第一或二行。

    然后执行下面命令:

    makemigrations message
    
     
    mark
    migrate message 生成数据表
    
     
    mark

    前往Navicat验证:

     
    mark

    可以看到我们的数据表已经创建成功。默认数据表名称为app名称_类名转换为小写
    自动生成的id作为主键。

    Models讲解

    除过普通的对应数据库的字段类型如CharField,还有很多高级类型。如EmailField提供email验证。

        models.ForeignKey     # 外键
        models.DateTimeField  # 时间字段
        models.IntegerField   # 整型
        models.IPAddressField # IP地址
        models.FileField      # 上传文件
        models.ImageField     # 图片
    

    ctrl按住+左键点击models 进入之后点击fields拖到文件开始可以看到所有字段:

    __all__ = [str(x) for x in (
        'AutoField', 'BLANK_CHOICE_DASH', 'BigIntegerField', 'BinaryField',
        'BooleanField', 'CharField', 'CommaSeparatedIntegerField', 'DateField',
        'DateTimeField', 'DecimalField', 'DurationField', 'EmailField', 'Empty',
        'Field', 'FieldDoesNotExist', 'FilePathField', 'FloatField',
        'GenericIPAddressField', 'IPAddressField', 'IntegerField', 'NOT_PROVIDED',
        'NullBooleanField', 'PositiveIntegerField', 'PositiveSmallIntegerField',
        'SlugField', 'SmallIntegerField', 'TextField', 'TimeField', 'URLField',
        'UUIDField',
    )]
    

    介绍字段参数

    CharField必须指明默认最大长度。null=True,blank=True指明字段可以为空
    defalut = " "指定默认值。

    name = models.CharField(max_length=20,null=True,blank=True, verbose_name=u"用户名")
    

    id是自动生成的,如果需要自定义主键,message/models.py中添加字段:

    object_id = models.CharField(primary_key=True, verbose_name="主键")
    

    此时点击Tools 菜单下 Run manage.py Task输入makemigrations message

     
    mark

    知识点:CharField必须指明最大长度

    object_id改为:

        object_id = models.CharField(primary_key=True, max_length=50 ,verbose_name="主键")
    

    这时点击Tools 菜单下 Run manage.py Task输入makemigrations message

    You are trying to add a non-nullable field 'object_id' to usermessage without a default; we can't do that (the database needs something to populate existing rows).
    Please select a fix:
     1) Provide a one-off default now (will be set on all existing rows)
     2) Quit, and let me add a default in models.py
    

    根据提示信息,我们需要给object_id添加默认值:

        object_id = models.CharField(primary_key=True, max_length=50,default="", verbose_name="主键")
    

    get新知识点:object_id必须有默认值

    输入2 退出:然后输入makemigrations message

     
    mark

    再输入下面命令生成数据表

    migrate message 
    

    可以看到上图过程中会告诉我们做了哪些变化,如删除了默认系统生成的主键id
    ,变更了name。新增了我们的object_id

    前往Navicat验证右键设计表:

     
    mark

    可以看到object_id已经成为我们的新主键。

    介绍Meta信息:

    Meta信息中我们可以指定常见的类型:

    db_table = "user_meassage"
    

    自定义后生成表,表名会与我们的保持一致。而不会前缀appname如:message_

    这里因为我们已经生成过了,就不要做验证改变表名了。

    ordering = '-object_id'
    

    ordering指定默认排序字段,如:就会以object_id倒序

    verbose_name_plural = u"用户留言信息"
    

    verbose_name_plural:复数信息,便于人阅读。否则会在后台显示用户留言信息s

    已经学习完毕了orm将数据表映射表。
    github地址:https://github.com/mtianyan/DjangoGetStarted
    此节结束对应github commit:

    留言板数据库orm映射成表完成。内容截止教程3-3结束。

    3-4 django model的增删改

    github仓库地址:https://github.com/mtianyan/DjangoGetStarted

    • 上小节完成代码对应commit: 留言板数据库orm映射成表完成。内容截止教程3-3结束。

    message/views.py中:

    from .models import UserMessage
    

    将我们刚才创建的model,import进来。.代表是与当前同级的目录。

    按照下图所示添加一条测试数据。

     
    mark

    然后再我们的getform方法内部添加下面代码:

    def getform(request):
        # UserMessage默认的数据管理器objects。
        # 方法all()是将所有数据返回成一个queryset类型(django的内置类型)
        all_message = UserMessage.objects.all()
    
        #我们可以对于all_message进行遍历操作
        for message in all_message:
            # 每个message实际就是一个UserMessage对象(这时我们就可以使用对象的相关方法)。
            print message.name
    
        return render(request, 'message_form.html')
    

    调试过程:

     
    mark
    • 点击上图小红框位置,打上断点。

    • 点击Run -> debug后:在浏览器里打开:http://127.0.0.1:8000/form/

     
    mark
    • 弹出上图代表已进入断点。
     
    mark
    • 此时鼠标左键点击:all_message.可以看到这是一个{QuerySet}类型的对象,里面存放着[<UserMessage: UserMessage object>]

    • f6使运行到下一步。此时下方的值窗口内可以看到message的值。说明我们成功取到了数据库的值。

     
    mark

    filter取出指定要求值

    all_message = UserMessage.objects.filter(name=' mtianyan', address='西安')
    
     
    mark

    按照上面调试过程重新调试可以看到我们同样取出了值。

    小练习:将名字改为与自己数据库存放值不同的。查看结果。

     
    mark

    变成了空列表,说明一切正确。

    将数据存入数据库

    了解:django/db/models/base.py 源码中提供save方法

    def save(self, force_insert=False, force_update=False, using=None,
                 update_fields=None):
    

    getform方法中添加代码:

     # 存储部分
    
        # 首先实例化一个对象
        user_message = UserMessage()
    
        # 为对象增加属性
        user_message.name = "mtianyan2"
        user_message.message = "blog.mtianyan.cn"
        user_message.address = "西安"
        user_message.email = "1147727180@qq.com"
        user_message.object_id = "efgh"
    
        # 调用save方法进行保存
        user_message.save()
    
    • 打上断点:如下图。
     
    mark
    • 一直惦记f6单步调试,直到如下图:蓝色到return语句
     
    mark

    可以在下方值窗口查看到值

     
    mark

    Navicat进行验证

    可以看到成功的添加了数据mtianyan2

     
    mark

    如何从html的提交中取到数据并保存进数据库

    templates/message_form.html:

     
    mark

    method是post。action就是指向我们在urls.py中配置的/form/
    前面必须加斜杠指根路径下form
    里面的input会自动把值传递给后台:这时我们就可以在getform中取到刚才传递过来的值。

    运行项目:然后输入需要填写的值。点击提交:出现403错误

    Forbidden (403)
    CSRF verification failed. Request aborted.
    

    根据提示:我们的页面没有进行crsf的验证,这时django的安全机制,不允许任意form都往后台提交。

    知识点:所以我们需要在html页面中加入csrf_token

        {% csrf_token %}
    
     
    mark

    原有那行删除掉。打上断点

     
    mark

    刷新页面并提交。这时候在值窗口可以看到request对象下的POST中存放着我们提交的数据。内容如下

    <QueryDict: {u'message': [u'u54c8u54c8'], u'address': [
    u'u897fu5b89u5e02'], u'csrfmiddlewaretoken': [
    u'uIYSMOTWPJBPOPucRwd3uDaWtCzeEaem'], u'name': [
    u'u5929u6dafu660eu6708u7b19'], u'email': [u'1147727180@qq.com']}>
    
     
    mark

    数据以dict:key-value 形式存储 key是由如下图html中的name所决定对应的。

     
    mark

    数据库新增。

    request.POST中数据取出,存入user_message对象

     # html表单部分
    
        # 此处对应html中的method="post",表示我们只处理post请求
        if request.method == "POST":
            # 就是取字典里key对应value值而已。取name,取不到默认空
            name = request.POST.get('name', '')
            message = request.POST.get('message', '')
            address = request.POST.get('address', '')
            email = request.POST.get('email', '')
    
            # 实例化对象
            user_message = UserMessage()
    
            # 将html的值传入我们实例化的对象.
            user_message.name = name
            user_message.message = message
            user_message.address = address
            user_message.email = email
            user_message.object_id = "ijkl"
    
            # 调用save方法进行保存
            user_message.save()
    
    • 打断点在下图位置:
     
    mark
    • 进入调试:点击点击method:是get请求。因为我们并没有按提交按钮,而是get这个网页
     
    mark
    • 点击f8继续运行我们的项目 浏览器中填写表单内容点提交。
     
    mark

    因为这次是表单提交,已经变成了post方式。按f6进行单步调试。

    一直单步到如下图蓝色

     
    mark

    这时候值浏览窗口可以看到

     
    mark

    检查我们的user_message对象的属性是否已经全部添加进去,

    使用f8 继续项目并前往Navicat验证

     
    mark

    可以看到我们的数据库中已经新增,标志着我们已经成功存入数据。

    删除数据。

    对于查询到的数据做删除:

    # 方法2 :filter取出指定条件值,逗号代表and 必须同时满足两个条件才返回。
    all_message = UserMessage.objects.filter(name='mtianyan', address='西安')
    
    # 我的数据库里保存着可以匹配到该条数据的一行。
    
    # 删除操作:使用delete方法删除all_message
    
    all_message.delete()
    
        for message in all_message:
            # 删除取到的message对象
            message.detele()
            # print message.name
    

    点击run并访问:http://127.0.0.1:8000/form/
    进入Navicat进行验证。

     
    mark

    可以看到我们的那条mtianyan + 西安的数据已经被删除。

    至此:我们已经学会了新增,删除,查询。

    本节结束github对应commit:

    django model的增删改数据库。本次内容截止教程3-4。

    3-5 django url templates配置

    项目Github地址:https://github.com/mtianyan/DjangoGetStarted
    本节开始对应对应Github的commit:django model的增删改数据库。本次内容截止教程3-4。

    本节将介绍url的配置,以及如何将数据库数据填充回前台html页面。

    情景:只允许用户修改mtianyan,如果没有就添加,如果有就回填使用户可以修改。

    取出数据

    message/views.py中的getform方法中

        message = None
        all_message = UserMessage.objects.filter(name='mtianyan', address='西安')
    
        # if 判断是否存在数据
        if all_message:
            # all_message是一个list,可以使用切片。
            message = all_message[0]
    
    

    这里注意把前几节写的删除掉

    将数据回填至html中

    修改return render

    return render(request, 'message_form.html',{
            "my_message" : message
    })   
    

    这里前面的"my_meassage"是我们可以自行命名的。会有一个my_message对象随着返回前端页面。

    在前端页面中放入值。

    为input系列标签添加value: 使用my_message.name取到我们传递过来的my_message对象的属性值。

            <input id="name" type="text" name="name"  
            value="{{ my_message.name }}" class="error" placeholder="请输入您的姓名"/>
    

    请自行完成姓名,邮箱,联系地址三个input标签。

    textarea标签添加值

     
    mark
            <textarea id="message" name="message"  
            placeholder="请输入你的建议">{{ my_message.message }}</textarea>
    

    运行项目,访问:http://127.0.0.1:8000/form/

     
    mark

    成功!!我们已经将后台数据库数据成功展示到前台。

    template模板渲染中的一些用法。

    在我们的template模板中也就是form.html中,不允许我们写Python的语法,
    它提供了一套自己的内建标签。

    官方文档中template内建标签用法传送门

    常用的几种模板标签介绍:

    if - else

    官方提供模板如下:

     
    mark

    个人实践:

     
    mark

    满足if运行结果:

     
    mark

    不满足if:如改为my_message.name == "mtianyan1"运行结果:

     
    mark
    ifequal & ifnotequal
     
    mark

    官方文档解释:ifequal a b 相当于f a == b.ifnotequal则相当于if a != b

    个人实践:


     
    mark

    结果为:未找到中文昵称

    slice
     
    mark

    官方文档解释:其实就是切片操作。从头开始切到第n个。

    个人实践:

     
    mark

    本来mtianyanmtianyan1是不同的,但是切片后前八位相同。
    运行结果显示 :对应中文昵称:天涯明月笙

    URl的别名设置技巧

    DjangoGetStarted/urls.py:

    r'^form/$'添加别名:

        url(r'^form/$', getform, name = "form_new")
    

    前往html中修改action地址为下面所示:

    <form action="{% url "form_new" %}" method="post" class="smart-green">
    

    这时我们如果改动urls.py中的r'^form/$'不需要再修改前端代码中值。

    url先后顺序问题

    注意url匹配规则中一定不要忘记/$符号代表以form/结束的才会有效。不会向后继续匹配。比如没有/$

        url(r'^form', getform, name="form_new")
    

    这时我们进入浏览器访问时输入http://127.0.0.1:8000/formemmm都可以被响应。

     
    mark

    特别是如果底下还配置有被这个规则包含的条目,会产生被写在更靠前的拦截住得不到正确处理的Bug。

     
    mark

    上图我们是想要让formtest响应admin.site.urls。但是会被form提前拦截住。

    所以我们一定要注意加上/$符号。

    至此我们完成了留言板项目:学习到了Django必备的基础知识。
    下一章我们将开始我们的进阶学习:开发在线教育平台网站。

    本章结束:



    原文学习来自简书,作者:天涯明月笙
    原文链接:https://www.jianshu.com/p/273134a8aea6
  • 相关阅读:
    Oc中UIKit框架的继承结构
    iOS中的事件传递和响应者链
    音频视频,音乐,录音参考资料
    对象序列化(对对象的归档NSKeyedArchiver、接档NSKeyedUnarchiver)的理解
    iOS--UI篇——UIToolbar的简单使用
    iOS--内购的使用方法
    协调-分布式锁
    协调-协调架构原理
    协调-分布式配置
    队列-生产者消费者模式
  • 原文地址:https://www.cnblogs.com/xinjie57/p/9186070.html
Copyright © 2011-2022 走看看