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:\CodeSpace\PythonProject\DjangoGetStarted\apps\message\models.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'\u54c8\u54c8'], u'address': [
u'\u897f\u5b89\u5e02'], u'csrfmiddlewaretoken': [
u'uIYSMOTWPJBPOPucRwd3uDaWtCzeEaem'], u'name': [
u'\u5929\u6daf\u660e\u6708\u7b19'], 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

django+xadmin在线教育平台(五)的更多相关文章

  1. django+xadmin在线教育平台(一)

    大家好,此教程为在慕学网的实战教程Python升级3.6 强力Django+杀手级Xadmin打造在线教育平台的学习笔记,不对望指正! 使用Django+Xadmin打造在线教育平台(Python2, ...

  2. django+xadmin在线教育平台(四)

    3-2 配置表单页面 必要的该说的,该了解的 前置条件: 你已经学习了前面教程.将项目的文件夹目录结构,setting配置等修改完毕与我保持一致. 本节通过Django快速的配置一个留言板页面来学习 ...

  3. django+xadmin在线教育平台(十)

    剩余app model注册 courses注册 新建courses/adminx.py: # encoding: utf-8 __author__ = 'mtianyan' __date__ = '2 ...

  4. django+xadmin在线教育平台(十五)

    7-4 课程机构列表页数据展示2 前去html中进行数据填充   mark 可以看到所有城市是通过a标签,当前选中城市为active.   mark 之后把下面的写死的城市删除掉.   mark 这时 ...

  5. django+xadmin在线教育平台(十七)

    8-1 课程列表 拷贝课程列表页到template目录 创建课程相关的urls.py Mxonline2/urls.py中声明包含到course的url中: # 课程app的url配置 url(r&q ...

  6. django+xadmin在线教育平台(六)

    4-1 使用py3.6和django1.11开发系统前注意事项 直接通过Python3.6和django最新版本来开发我们的系统的一些注意事项. 原版本: Python 2.7 & djang ...

  7. django+xadmin在线教育平台(十六)

    7-7 modelform 提交我要学习咨询1 对应表userask form会对字段先做验证,然后保存到数据库中. 可以看到我们的forms和我们的model中有很多内容是一样的.我们如何让代码重复 ...

  8. django+xadmin在线教育平台(十四)

    7-1 django templates模板继承1 机构可以筛选类别 机构可以根据所在地区进行分类 右侧我要学习功能: form表单提交 右下:授课机构排名 页面头部与底部为全局头和全局底部. Dja ...

  9. django+xadmin在线教育平台(十一)

    6-1 首页和登录页面的配置 用户访问我们的根目录,我们需要把html文件返回给用户.因此我们第一步把html文件放入template目录.   mark 在html中找到首页的html.拷贝到我们的 ...

随机推荐

  1. 练习二十:python计算皮球下落速度练习题

    问题简述:假设一个皮球从100米高度自由落下.条件,每次落地后反跳回原高度的一般,在落下 要求:算出皮球,在第十次落地时,共经过多少米?第十次反弹多高? 方法一: h,sum1 = 100,100 # ...

  2. 09.Spring Bean 注册 - BeanDefinitionRegistry

    基本概念 BeanDefinitionRegistry ,该类的作用主要是向注册表中注册 BeanDefinition 实例,完成 注册的过程. 它的接口定义如下: public interface ...

  3. Silverlight 登陆界面

    美术水平有限,不喜勿喷. 界面代码,效果如下图 <UserControl x:Class="ElecDemoTelerikSL.Login" xmlns="http ...

  4. PullToRefreshListView

    @Override protected void onRefreshing(final boolean doScroll) { /** * If we're not showing the Refre ...

  5. 你一直在用的 Spring Boot Starters 究竟是怎么回事

    Spring Boot 对比 Spring MVC 最大的优点就是使用简单,约定大于配置.不会像之前用 Spring MVC 的时候,时不时被 xml 配置文件搞的晕头转向,冷不防还因为 xml 配置 ...

  6. pat1081. Rational Sum (20)

    1081. Rational Sum (20) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue Given N ...

  7. pat1078. Hashing (25)

    1078. Hashing (25) 时间限制 100 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue The task of t ...

  8. File 元素 都有files属性

    File 元素 都有files属性 必须有 name 才能传到后台 Html data-* 存储string 值 Jquery data() 可以存储对象 ,但是执行后页面看不到,可以取到     P ...

  9. python协程与异步协程

    在前面几个博客中我们一一对应解决了消费者消费的速度跟不上生产者,浪费我们大量的时间去等待的问题,在这里,针对业务逻辑比较耗时间的问题,我们还有除了多进程之外更优的解决方式,那就是协程和异步协程.在引入 ...

  10. (转载)C#线程优先级详解

    计算机中经常会有多个任务同时运行,其中总有一些看起来更紧急,更需要优先完成.比如我们现在有两个任务,一个任务是下载一部电影,另一个任务是检测用户的输入.显然及时响应用户操作应具有更高的优先级,因为我们 ...