前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >零基础使用Django2.0.1打造在线教育网站(五):简易留言簿交互实现

零基础使用Django2.0.1打造在线教育网站(五):简易留言簿交互实现

原创
作者头像
啃饼思录
修改2018-09-10 21:17:49
1.3K0
修改2018-09-10 21:17:49
举报

关于博主

努力与运动兼备~有任何问题可以加我好友或者关注微信公众号,欢迎交流,我们一起进步!

代码语言:txt
复制
                 微信公众号:  啃饼思录
代码语言:txt
复制
                 QQ: 2810706745(啃饼小白)

写在前面

本篇笔记主要是简易留言簿的交互实现,笔记中本篇(第五篇)对应上传的仓库为:https://github.com/licheetools/djangoTest对应第五篇截止代码。好了,我们先来看一下我们上篇笔记的最终效果:

交互实现

对象关系映射ORM

通常而言,为了实现我们数据意义上的增删改查,你可能会选择使用原生的数据库查询语句如:select * from database where id =8;又比如下面一段代码:

代码语言:txt
复制
import MySQLdb  # 导入数据库驱动模块


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

尽管这种方法可以对数据进行操作,但是一旦需要进行操作的数据过多而且不仅仅是查询操作,这种方法就显得很捉襟见肘了。那么有没有一种简便的方法呢?答案是有的!这就用到了我们的ORM了。

***

对象关系映射(英语:(Object Relational Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换 。从效果上说,它其实是创建了一个可在编程语言里使用的--“虚拟对象数据库”。

***

你可以借鉴面向对象编程的思想这么理解,把数据当做对象(事实上在面向对象编程的思想里,一切都是对象,别忘了Python也就是面向对象编程语言),那么它就有方法和属性了。举个例子来说:car,它的属性可以是颜色(color),大小(size),长度(length)等,可以这么表示为

代码语言:txt
复制
car.color      car.size       car.length

;它的方法可以是启动(start),运行(run),停车(stop)等,也可以这样表示为:

代码语言:txt
复制
car.start()         car.run()       car.stop()

创建我们的models(数据库信息)

从前面的描述中你就知道了,models.py这个文件就是用于数据库的操作,包括连接,访问,数据定义,修改等,接下来我们就开始定义数据,写我们的代码了。

在空白处输入以下代码:

代码语言:txt
复制
class UserMessage(models.Model):   # 继承于django.db.models.Model
# max_length设置最大长度,verbose_name在后台显示字段会用到,也就是中文显示文本内容
    name = models.CharField(max_length=20, verbose_name="昵称")  
    email = models.EmailField(verbose_name="邮箱")
    address = models.CharField(max_length=100 ,verbose_name="联系地址")
    message = models.CharField(max_length=500, verbose_name="你的轨迹")

    class Meta:
        verbose_name = "用户留言信息"
# class Meta,内嵌于 UserMessage 这个类的定义中,主要是用于后台管理显示中文信息

前面说到,一旦数据发现变动就必须执行我们的makemigrationsmigrate操作,我们运行一下:

为什么会这样呢,怎么一点反应也没有,其实因为你还没有把新创建的apps在setting中注册,所以才会出现这样的情况。

在settings.py中注册我们新创建的apps

在djangoTest/settings.py 第33行的INSTALLED_APPS:的尾部加上一行代码'liuyan',如下图所示:

代码语言:txt
复制
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'liuyan',
]

这时候我们再来重新运行Tools 菜单下 Run manage.py Task然后输入makemigrations或者makemigrations liuyan,因为这里只有一个app所以我就直接makemigrations,多个可以根据自己的需要来选择makemigrations的对象,如下图所示:

接着运行migrate命令:

提示生成了一些文件信息,我们打开Navicat去看一下:

看到没,我们的数据信息在数据库成功显示了。默认数据表的名称为app名称_类名(转换为小写),自动生成的id作为主键(数据查询必备,这里系统给我们自己添加了)。

关于Models的一些说明

前面我们用到了一些字段如CharField,EmailField等,还有一些这里没用到但是今后会用到的字段,我列举了一下:

代码语言:txt
复制
    models.TextField    # 文本注意与CharField的区别,范围大小不一样
    models.ForeignKey     # 外键
    models.DateTimeField  # 时间
    models.IntegerField   # 整型
    models.IPAddressField # IP地址
    models.FileField      # 文件
    models.ImageField     # 图片
如果你想看全部的信息可以,将光标放在models上面,按住ctrl+然后单击,进入models/--init--.py文件,之后以同样的操作点击任意一个fields单词,就可以打开fields/--init--.py文件了,在最前面就可以看到所有字段:

字段参数的说明

1、CharField必须指明默认的最大长度(max_length)。null=True,blank=True指明字段可以为空,defalut = " "指定默认值为空。通常我们地址这一栏可以为空,所以修改如下:

代码语言:txt
复制
address = models.CharField(max_length=100 ,null=True,blank=True,verbose_name="联系地址")

2、表的id是自动生成的,如果需要自定义主键,那么需要在models.py中添加字段:

代码语言:txt
复制
object_id = models.CharField(primary_key=True,max_length=100 ,verbose_name="主键")

再来makemigrationsmigrate一下:

我们发现出错了,其实是要求我们需要给object_id添加默认值,那我们默认为空:

代码语言:txt
复制
  object_id = models.CharField(primary_key=True,max_length=100,default="" ,verbose_name="主键")

重新运行一下,makemigrationsmigrate

我们现在再次刷新一下Navicat,发现系统默认生成的主键id没了,主键变成了我们自定义的object_id。右键liuyan_usermessage这个表,选择设计表打开:

Meta的说明

1、在Meta信息中我们可以指定表的名称,如db_table:

代码语言:txt
复制
db_table = "user_liuyan"

2、可以指定排序的字段,如ordering:

代码语言:txt
复制
ordering = 'object_id'

这是以其升序的,倒序的话只需要这样ordering = '-object_id'即可。

3、可以更改后台信息,如verbose_name_plural:

verbose_name_plural是verbose_name的复数形式,如果不改则会在其后面加s。

代码语言:txt
复制
verbose_name = "用户留言信息"
则verbose_name_plural 会显示 "用户留言信息s",所以一般这2个的值都是相同的
即
verbose_name =verbose_name_plural="用户留言信息"

models的增删改查

首先将我们的数据信息导入到我们的视图函数中来,在liuyan/views.py中:写上这行代码,完成导入(同一目录下的包的导入用.表示当前目录):

代码语言:txt
复制
from .models import UserMessage

既然是要对数据进行操作,必然是先有数据,所以按照图所示,填入数据:

接下来我们完善一下我们的视图函数,修改代码如下:

代码语言:txt
复制
def getstart(request):
    all_message = UserMessage.objects.all()  
  # 我们这个函数直接继承最高类objects,并且调用它的all()方法,all()方法是将所有数据返回成一个queryset类型(这是django的一个内置的类型)

 # 对取出的all_message进行遍历
    for message in all_message:
 # 每个message其实就是一个UserMessage对象
        print(message.name) #打印名字

    return render(request, 'start.html')

断点调试

在view.py文件的for message in all_message的左侧双击(连续单击2次),就出现红点,然后开启debug模式

点击Run -> debug后:在浏览器里打开:

代码语言:txt
复制
http://127.0.0.1:8000/start/

点击一下,就进入这个页面了

再一次次按图片上的调试按钮,我们的值被一步步的取出来了。

采用filter可以取出特定的值

代码语言:txt
复制
all_message = UserMessage.objects.filter(name="newbai", address="珠海")

我们修改之后再来debug一下,发现依然取到了数据:

我们尝试去一个不存在的数据,看有什么结果:

代码语言:txt
复制
all_message = UserMessage.objects.filter(name="newbai", address="广州")

看,结果是什么也没取到,因为本来就没有符合条件的数据啊,不是空值才怪!!!

数据入库

刚才是我们直接在数据库中添加了数据,如果现在我们要求不能直接在数据库中添加数据,这该怎么办呢?我们可以在文件里自己添加数据,django/db/models/base.py 中提供save方法:

代码语言:txt
复制
def save(self, force_insert=False, force_update=False, using=None,
             update_fields=None):

所以我们在view.py中修改代码如下:(按住Ctrl+/键可以快速注释代码)

代码语言:txt
复制
def getstart(request):
    # all_message = UserMessage.objects.filter(name="newbai", address="广州")
    # for message in all_message:
    #     print(message.name)

    user_message = UserMessage()  # 首先实例化一个对象

    user_message.name = "newbee"  # 为对象增加属性
    user_message.message = "重新测试一下"
    user_message.address = "深圳"
    user_message.email = "2131247535@qq.com"
    user_message.object_id = "liuyan.top"

    user_message.save()   # 调用save方法进行保存

    return render(request, 'start.html')

我们在实例化对象的地方打上一个断点,开启debug模式:一次次按调试按钮,直到运行到蓝色return render(request, 'start.html')语句为止,我们的值被一步步的取出来了。

到底数据是否存入到数据库中呢?我们打开Navicat并且刷新一下,看到确实在数据库里面:

那么现在就有一个问题了,我们从页面填入的数据如何保存到数据库中呢?

html页面提交数据并存入数据库

有过网页知识的小伙伴们就知道网页请求常见有get和post,但是post一般用于表单数据的提交,而get一般用于获取信息。打开我们的start.html,看到第10行,我们发现它的提交方式就是post.

这里我们修改代码如下:

代码语言:txt
复制
<form action="/start/" method="post" class="smart-green">

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

***

现在我们重新运行一下我们的项目:runserver。输入

代码语言:txt
复制
http://127.0.0.1/start/
,在出现的页面填入我们的信息:
然后点击提交:

出现了错误,其实这是必然的,为了提高网站的安全性,防止CSRF攻击,django不允许没有进行crsf的验证的信息提交,这是它的一种安全机制。所以我们需要在html页面中加入{% csrf_token %},具体都是加在</form>标签的前面。记得把前面那行去掉:

现在我们将view.py文件中的信息都注释掉,只保留这4行代码:

代码语言:txt
复制
from django.shortcuts import render
from .models import UserMessage

def getstart(request):
    return render(request, 'start.html')

再次运行我们的项目,在出现的页面填入信息:

然后在最后一行return render(request, 'start.html')打上一个断点,开启debug模式,最后再点击提交按钮(顺序很重要,不要弄错!)

可以看到信息出现了,POST里面的数据以dict(字典):key-value 形式存储的!

数据库新增数据

前面已经看到有数据进入POST里面了,现在是考虑如何从request.POST中取出数据,并存入user_message对象里面。从前面的分析中我们可以知道,数据提交的方式是POST,接下来我们就模拟一下数据的表单的提交。在views.py文件修改如下:

代码语言:txt
复制
from django.shortcuts import render
from .models import UserMessage
# Create your views here.


def getstart(request):
    if request.method == "POST":
        name = request.POST.get('name', '')     # 根据dict里面的键值对(key对应value值)来取出相应的属性,取不到默认为空。
        message = request.POST.get('message', '')
        address = request.POST.get('address', '')
        email = request.POST.get('email', '')

        user_message = UserMessage()  # 实例化对象

        user_message.name = name   # 将取到的html的数据传入我们实例化的对象(数据库对象).
        user_message.message = message
        user_message.address = address
        user_message.email = email
        user_message.object_id = "2333"  # 随便写一个即可

        user_message.save()   # 调用save方法进行保存

    return render(request, 'start.html')

然后先开启debug模式,在浏览器中输入http://127.0.0.1/start/,待页面正常显示以后,再在`if request.method == "POST":`左侧打上一个断点,重新刷新一下页面:

我们在这里发现此处我们的Method是GET,也就是说浏览器采用get方式获取数据:

现在我们返回页面,在页面输入一些信息:

然后点击提交,在Pycharm里面,我们每按一下单步运行按钮,注意右侧是否出现绿色的文字,表示已经成功获取到数据。然后继续按单步执行按钮,直到蓝色横栏出现在return render(request, 'start.html')为止!

现在我们打开我们的Navicat,去数据库里看一下我们的数据是否已经存进去了。通过打开,我们发现数据已经进去了:

这说明,我们数据库的新增数据已经完成了!

数据的删除

有一个问题,那就是有时候你输入信息的时候未来得及检查就提交了,提交了不完整的信息,可是这时候数据库已经把你刚才提交的数据存进去了,所以接下来是如何对其进行删除操作。

正如你所知道的,我们删除只是删除一部分内容,也就是有选择性的删除,那么就要用到前面说过的filter过滤了。在views.py文件,修改并注释一些代码:

代码语言:txt
复制
from django.shortcuts import render
from .models import UserMessage
# Create your views here.


def getstart(request):
    # if request.method == "POST":
    #     name = request.POST.get('name', '')     # 根据dict里面的键值对(key对应value值)来取出相应的属性,取不到默认为空。
    #     message = request.POST.get('message', '')
    #     address = request.POST.get('address', '')
    #     email = request.POST.get('email', '')
    #
    #     user_message = UserMessage()  # 实例化对象
    #
    #     user_message.name = name   # 将取到的html的数据传入我们实例化的对象(数据库对象).
    #     user_message.message = message
    #     user_message.address = address
    #     user_message.email = email
    #     user_message.object_id = "2333"    # 随便写一个即可
    #
    #     user_message.save()   # 调用save方法进行保存

        # filter取出符合指定条件的值,逗号代表and ,必须同时满足两个(这里只设定了2个)条件才返回值,否则为空。
        all_message = UserMessage.objects.filter(name='newbai', address='珠海')  # 数据库里保存着可以匹配到该条数据的一行。

        all_message.delete()   # 删除操作:使用delete方法删除all_message

        for message in all_message:
            # 删除取到的message对象
            message.detele()
            # print message.name

        return render(request, 'start.html')

如下图所示:

然后重新启动运行一下,在浏览器端口输入:

代码语言:txt
复制
http://127.0.0.1/start/

,刷新一下页面,然后再次打开Navicat,查看一下数据库,我们发现那条数据被删除了!

之前:
之后;

看到这里,数据库的查询,增加,删除都介绍完了。

将后台数据展示到前端页面

我们这里假定已经在数据库中已经存有一些数据(实际上就是前面已经存入的数据),如果存在一个叫newbee的人,就直接将他的数据修改回填到我们的HTML页面上来;如果没有就直接添加这个人的信息。(直接添加数据这种方式在前面就已经介绍完了,这里主要介绍前面一种如何将已经存在的信息进行回填的情况)

打开liuyan/views.py文件,将里面所有的信息都注释或者删除掉,然后写入以下代码:

代码语言:txt
复制
from django.shortcuts import render
from .models import UserMessage
# Create your views here.
def getstart(request):
    message = None   # 开始时message是没有数据的
    all_messages = UserMessage.objects.filter(name = "newbee")  # 过滤查找是否存在我们想要的数据
    if all_messages:  # 如果存在的话,返回值是一个列表
        message = all_messages[0]     # 取出返回值的第一个元素
      return render(request, 'start.html',{
            "my_message": message   # 将返回值显示给HTML页面
        })

注意:字典里面的"my_message": message是一个键值对,my_message这个变量可以随意命名,但是后面的message则是你前面返回的值。光这样还是不够的,我们接下来准备挖坑和填坑操作。

前端页面的挖坑与填坑操作

打开start.html文件,找到里面的一系列input标签,并添加value属性,我们这里以昵称这个属性为例:

代码语言:txt
复制
 <label>
        <span>昵称 :</span>
        <input id="name" type="text" name="name" value="" class="error" placeholder="请输入您的昵称"/>
        <div class="error-msg"></div>
    </label>

并将value的值修改为value="{{ my_message.name }}",其他的几个属性也是类似,这里就不细说了:

代码语言:txt
复制
value="{{ my_message.email }}"

value="{{ my_message.address }}"

需要注意的是textarea这个标签,应该修改如下:

代码语言:txt
复制
<label>
        <span>留言 :</span>
        <textarea id="message" name="message"  placeholder="请输入你的轨迹">{{ my_message.message }}</textarea>
        <div class="error-msg"></div>
    </label>

现在我们重新运行一下这个项目,在浏览器地址中输入:http://127.0.0.1/start/,回车看一下:

数据库中存在的数据已经被回填回来了,棒棒的,至此我们这个简易留言簿的开发就到此为止了!

但是为了后面的开发需要,在这里有必要介绍一些Django用于模板渲染的常见方法。

先给大家传送官方关于Built-in template tags and filters的介绍。

Django模板语言

如果你有编程背景或者您之前使用过一些在HTML中直接插入程序代码的语言,那么现在你需要记住,Django的模版系统并不是简单的将Python嵌入到HTML中(事实上,Django不允许我们在Template中写Python的语法)。 所以设计决定了模版系统示致力于表达外观,而不是程序逻辑。

模版是纯文本文件。它可以产生任何基于文本的的格式(HTML,XML,CSV等等)。 模版包括在使用时会被值替换掉的变量和控制模版逻辑的标签

下面是一个小模版,它说明了一些基本的元素。后面的文档中会解释每个元素。

代码语言:txt
复制
{% extends "base_generic.html" %}

{% block title %}{{ section.title }}{% endblock %}

{% block content %}
<h1>{{ section.title }}</h1>

{% for story in story_list %}
<h2>
  <a href="{{ story.get_absolute_url }}">
    {{ story.headline|upper }}
  </a>
</h2>
<p>{{ story.tease|truncatewords:"100" }}</p>
{% endfor %}
{% endblock %}

为什么要使用基于文本的模版,而不是基于XML的(比如Zope的TAL)呢?我们希望Django的模版语言可以用在更多的地方,而不仅仅是XML/HTML模版。在线上世界里,我们在email、Javascript和CSV中使用它。你可以在任何基于文本的格式中使用这个模版语言。

变量

变量看起来就像是这样: {{ variable }}。

点号(.)用来访问变量的属性。从技术上来说,当模版系统遇到点(“.”),它将以这样的顺序查询:

字典查询(Dictionary lookup) 属性或方法查询(Attribute or method lookup)

数字索引查询(Numeric index lookup)

过滤器

过滤器看起来是这样的:{{ name|lower }}。这将在变量 {{ name }} 被过滤器 lower 过滤后再显示它的值,该过滤器将文本转换成小写。使用管道符号 (|)来应用过滤器。

过滤器参数包含空格的话,必须被引号包起来;例如,使用逗号和空格去连接一个列表中的元素,你需要使用 {{ list|join:”, ” }}。

常用的模版过滤器: default,如果一个变量是false或者为空,使用给定的默认值。否则,使用变量的值。例如:{{ value|default:"nothing" }}undefined length,返回值的长度。它对字符串和列表都起作用。例如:{{ value|length }}undefined filesizeformat,将该数值格式化为一个 “人类可读的” 文件容量大小 (例如 ‘13 KB’, ‘4.1 MB’, ‘102 bytes’, 等等)。例如:{{ value|filesizeformat }}标签

标签看起来像是这样的: {% tag %}。标签比变量复杂得多:有些用于在输出中创建文本,有些用于控制循环或逻辑,有些用于加载外部信息到模板中供以后的变量使用。

有些标签需要开始标签和结束标签(例如{% tag %} … tag contents … {% endtag %})。

常用的标签:

for if,elif,else

block和extend

注释

要注释模版中一行的部分内容,使用注释语法 {# #}.

例如,这个模版将被渲染为 ‘hello’:{# greeting #}hello

如果想了解更多信息,可以参考这篇文章:Django-模板(模板语言)

URL的别名设置小贴士

在我们这个留言项目中,如果我们在djangoTest/urls.py里面为'start/'添加别名:

代码语言:txt
复制
原来的路径:
path('start/', getstart)
现在的路径:
path('start/', getstart, name = "get_start")

然后在start.html中修改action地址为下面所示:

代码语言:txt
复制
<form action="{% url "get_start" %}" method="post" class="smart-green">

这样做的好处就是,如果我们改动urls.py中的'start'不需要再去修改前端代码中url的指向地址。

现在我们在djangoTest/urls.py中对URL的配置进行修改一下:

代码语言:txt
复制
urlpatterns = [
    path('admin/', admin.site.urls),
    path('start/', getstart, name="get_start"), 
    path('startt/', getstart, name="get_start")

然后我们在浏览器中输入:

代码语言:txt
复制
http://127.0.0.1/startt/

(注意我们之前的地址为

代码语言:txt
复制
http://127.0.0.1/start/

,一个是start,一个是startt)再次运行一下我们的项目:

这个地址竟然也可以访问我们的页面,还正常访问了,没有报错!!!所以小提示很有用的!

URL的根路径设置小贴士

现在我们尝试这么一个问题,我们需要在path路径做一些修改如下:path('start/', admin.site.urls),

代码语言:txt
复制
urlpatterns = [
    path('admin/', admin.site.urls),
    path('startt/', getstart, name="get_start"), # 新增加的一行,位置插到这里
    path('start/', admin.site.urls), 
代码语言:txt
复制
这样运行的话,系统会报错
WARNINGS:
?: (urls.W005) URL namespace 'admin' isn't unique. You may not be able to reverse all URLs in this namespace

所以根路径很重要的,不能随意设置,要保证它的唯一性。

至此,所有Django的基础知识我们就回顾完了,下一篇正式开始在线教育网站的项目开发!

笔记中本篇(第五篇)对应上传的仓库为:https://github.com/licheetools/djangoTest对应第五篇截止代码。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 关于博主
  • 写在前面
  • 交互实现
    • 对象关系映射ORM
      • 创建我们的models(数据库信息)
        • 在settings.py中注册我们新创建的apps
          • 关于Models的一些说明
            • 字段参数的说明
              • Meta的说明
                • models的增删改查
                  • 断点调试
                    • 采用filter可以取出特定的值
                      • 数据入库
                        • html页面提交数据并存入数据库
                          • 数据库新增数据
                            • 数据的删除
                            • 将后台数据展示到前端页面
                              • 前端页面的挖坑与填坑操作
                              • Django模板语言
                                • 变量
                                  • 过滤器
                                    • 注释
                                    • URL的别名设置小贴士
                                    • URL的根路径设置小贴士
                                    领券
                                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档