《Web接口开发与自动化测试基于Python语言》–读书笔记
第4章 Django模型
忽然意识到个严重问题,我这样详细的笔记,貌似有抄书的嫌疑,这样大家都不买书了,怕被告盗版,所以从后续章节开始,我只记录比较重要的知识点,不再做详细的抄书了,大家如果在阅读的时候有疑问可以向虫师请教,或留言给我,我们一起研究。
4.1 设计系统表
模型的基础知识:
- 每个模型是一个Python类,继承django.db.models.Model类
- 该模型的每个属性表示一个数据库表字段
- 所有这一切,已经给了你一个自动生成数据库访问的API
本例所需的模型,修改/guest/sign/models.py文件:
<span style="color:#000000"><code class="language-python"><span style="color:#880000">#! /usr/bin python</span>
<span style="color:#880000"># -*- coding:utf-8 -*-</span>
<span style="color:#000088">from</span> __future__ <span style="color:#000088">import</span> unicode_literals
<span style="color:#000088">from</span> django.db <span style="color:#000088">import</span> models
<span style="color:#880000"># Create your models here.</span>
<span style="color:#880000"># 发布会表</span>
<span style="color:#000088">class</span> <span style="color:#4f4f4f">Event</span><span style="color:#4f4f4f">(models.Model)</span>:
name = models.CharField(max_length=<span style="color:#006666">100</span>) <span style="color:#880000"># 发布会标题</span>
limit = models.IntegerField() <span style="color:#880000"># 参加人数</span>
status = models.BooleanField() <span style="color:#880000"># 状态</span>
address = models.CharField(max_length=<span style="color:#006666">200</span>) <span style="color:#880000"># 地址</span>
start_time = models.DateTimeField(<span style="color:#009900">'events time'</span>) <span style="color:#880000"># 发布会时间</span>
create_time = models.DateTimeField(auto_now=<span style="color:#000088">True</span>) <span style="color:#880000"># 创建时间(自动获取当前时间)</span>
<span style="color:#000088">def</span> <span style="color:#009900">__str__</span><span style="color:#4f4f4f">(self)</span>:
<span style="color:#000088">return</span> self.name
<span style="color:#880000"># 嘉宾表</span>
<span style="color:#000088">class</span> <span style="color:#4f4f4f">Guest</span><span style="color:#4f4f4f">(models.Model)</span>:
event = models.ForeignKey(Event) <span style="color:#880000"># 外键,关联发布会id</span>
realname = models.CharField(max_length=<span style="color:#006666">64</span>) <span style="color:#880000"># 姓名</span>
phone = models.CharField(max_length=<span style="color:#006666">16</span>) <span style="color:#880000"># 电话</span>
email = models.EmailField() <span style="color:#880000"># 邮箱</span>
sign = models.BooleanField() <span style="color:#880000"># 签到状态</span>
create_time = models.DateTimeField(auto_now=<span style="color:#000088">True</span>) <span style="color:#880000"># 创建时间(自动获取当前时间)</span>
<span style="color:#000088">class</span> <span style="color:#4f4f4f">Meta</span>:
unique_together = (<span style="color:#009900">"event"</span>, <span style="color:#009900">"phone"</span>)
<span style="color:#000088">def</span> <span style="color:#009900">__str__</span><span style="color:#4f4f4f">(self)</span>:
<span style="color:#000088">return</span> self.name</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
注意:
- Model会为每个表自动生成自增id字段无需声明;
- 嘉宾表通过event字段关联发布会表id字段,一条嘉宾信息对应某一场发布会;
- 通过发布会表id+嘉宾表phone作为联合主键,unique_together用于设置两个字段为联合主键;
- python3使用__str__()方法、python2使用__unicode__()方法,显示对应字段。
Django模型字段常用类型
类型 | 说明 |
---|---|
AutoField | 一个IntegerField类型的自动增量 |
BooleanField | 用于存放布尔类型的数据(True or False) |
CharField | 用于存放字符型的数据,需要指定长度max_length |
DateField | 用于存放日期类型的数据,格式为:YYYY-MM-DD |
DecimalField | 用于存放小数型的数据 |
EmailField | 用于存放电子邮件类型的数据 |
FilePathField | 用于存放文件路径类型的数据 |
FloatField | 用于存放浮点型的数据 |
IntegerField | 用于存放整数类型的数据,范围是:-2147483648至2147483647 |
BigIntegerField | 用于存放大整数类型的数据,最大支持:9223372036854775807 |
GenericIPAdressField | 用于存放IP地址类型的数据,同时支持IPv4、IPv6,字符串格式 |
NullBooleanField | 类似BooleanField,但是允许填写NULL |
PositiveIntegerField | 用于存放正数或0的整数类型的数据,范围是:0-2147483647 |
PositiveSmallIntegerField | 类似PositiveIntegerField,但是范围是:0-32767 |
SlugField | Slug是短标签,只包含字母、数字、下划线或字符,它通常在网址中使用,需要定义max_length |
SmallIntegerField | 类似IntegerField,但是范围是:-32768至32767 |
TextField | 用于存放文本类型的数据 |
TimeField | 用于存放时间类型的数据,格式为:HH:MM[:ss[.uuuuuu]] |
URLField | 用于存放URL地址 |
BinaryField | 用于存放原始二进制类型的数据 |
详细内容可参考官方文档:
https://docs.djangoproject.com/en/1.10/ref/models/fields/
使用如下命令进行数据库表的初始化和创建:
python manage.py makemigrations sign
python manage.py migrate
4.2 admin后台管理
将上面创建的发布会表、嘉宾表,也加入到admin后台进行图形化的管理:
修改/guest/sign/admin.py文件:
<span style="color:#000000"><code class="language-python"><span style="color:#000088">from</span> django.contrib <span style="color:#000088">import</span> admin
<span style="color:#000088">from</span> sign.models <span style="color:#000088">import</span> Event, Guest
<span style="color:#880000"># Register your models here.</span>
admin.site.register(Event)
admin.site.register(Guest)</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
通过管理页面随意增加一条发布会记录,我这里在增加一条中文记录的时候,出现了编码错误的提示:
UnicodeEncodeError at /admin/sign/event/add/
看这意思是中文编码问题,印象当中之前看Django官方文档的时候,有关于中文编码的问题,于是翻了下之前的笔记,发现是修改/guest/settings.py里的MIDDLEWARE配置,增加一条:
django.middleware.locale.LocaleMiddleware
但是这里将Django的admin管理后台的展示从英文变成了本地语言中文,对于上面遇到的错误还是没有帮助,哎,不应该呀,虫师都能在书中增加一条中文记录,没理由我这里完全按照虫师讲解的一步一步操作过来的会遇到错误啊,仔细回头查看models.py发现了一个小问题,虫师在书中也提到了只是自己当时忽略了,虫师使用的是python3,而我使用的是python2,在展示列表的函数里,虫师使用的是__str__,而我完全照搬书中的代码,也使用了__str__,这里就出错了,如果是python2,应该使用__unicode__才对,修改代码:
<span style="color:#000000"><code class="language-python"><span style="color:#880000"># 发布会表</span>
<span style="color:#000088">class</span> <span style="color:#4f4f4f">Event</span><span style="color:#4f4f4f">(models.Model)</span>:
name = models.CharField(max_length=<span style="color:#006666">100</span>) <span style="color:#880000"># 发布会标题</span>
limit = models.IntegerField() <span style="color:#880000"># 参加人数</span>
status = models.BooleanField() <span style="color:#880000"># 状态</span>
address = models.CharField(max_length=<span style="color:#006666">200</span>) <span style="color:#880000"># 地址</span>
start_time = models.DateTimeField(<span style="color:#009900">'events time'</span>) <span style="color:#880000"># 发布会时间</span>
create_time = models.DateTimeField(auto_now=<span style="color:#000088">True</span>) <span style="color:#880000"># 创建时间(自动获取当前时间)</span>
<span style="color:#880000">#def __str__(self):</span>
<span style="color:#000088">def</span> <span style="color:#009900">__unicode__</span><span style="color:#4f4f4f">(self)</span>:
<span style="color:#000088">return</span> self.name</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
再次添加中文记录,成功,问题解决,后续对于不同版本使用的不同函数,还是要注意啊!
在管理后台列表中显示更多字段:
修改/guest/sign/admin.py文件:
<span style="color:#000000"><code class="language-python"><span style="color:#880000">#! /usr/bin python</span>
<span style="color:#880000"># -*- coding:utf-8 -*-</span>
<span style="color:#000088">from</span> django.contrib <span style="color:#000088">import</span> admin
<span style="color:#000088">from</span> sign.models <span style="color:#000088">import</span> Event, Guest
<span style="color:#880000"># Register your models here.</span>
<span style="color:#880000"># 在admin管理后台展示更多字段</span>
<span style="color:#000088">class</span> <span style="color:#4f4f4f">EventAdmin</span><span style="color:#4f4f4f">(admin.ModelAdmin)</span>:
list_display = [<span style="color:#009900">'id'</span>, <span style="color:#009900">'name'</span>, <span style="color:#009900">'status'</span>, <span style="color:#009900">'address'</span>, <span style="color:#009900">'start_time'</span>]
<span style="color:#000088">class</span> <span style="color:#4f4f4f">GuestAdmin</span><span style="color:#4f4f4f">(admin.ModelAdmin)</span>:
list_display = [<span style="color:#009900">'realname'</span>, <span style="color:#009900">'phone'</span>, <span style="color:#009900">'email'</span>, <span style="color:#009900">'sign'</span>, <span style="color:#009900">'create_time'</span>, <span style="color:#009900">'event'</span>]
<span style="color:#880000"># 在admin管理后台注册发布会表、嘉宾表</span>
admin.site.register(Event, EventAdmin)
admin.site.register(Guest, GuestAdmin)</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
注意:
- EventAdmin继承admin.ModelAdmin类,其中ModelAdmin提供了很多自定义管理工具;
- list_display数组内是显示的字段名,必须存在于数据表中。
在管理后台增加搜索栏、过滤器:
还是修改/guest/sign/admin.py文件:
<span style="color:#000000"><code class="language-python"><span style="color:#880000">#! /usr/bin python</span>
<span style="color:#880000"># -*- coding:utf-8 -*-</span>
<span style="color:#000088">from</span> django.contrib <span style="color:#000088">import</span> admin
<span style="color:#000088">from</span> sign.models <span style="color:#000088">import</span> Event, Guest
<span style="color:#880000"># Register your models here.</span>
<span style="color:#000088">class</span> <span style="color:#4f4f4f">EventAdmin</span><span style="color:#4f4f4f">(admin.ModelAdmin)</span>:
list_display = [<span style="color:#009900">'id'</span>, <span style="color:#009900">'name'</span>, <span style="color:#009900">'status'</span>, <span style="color:#009900">'address'</span>, <span style="color:#009900">'start_time'</span>] <span style="color:#880000"># 在admin管理后台展示更多字段</span>
search_fields = [<span style="color:#009900">'name'</span>] <span style="color:#880000"># 在admin后台增加搜索栏</span>
list_filter = [<span style="color:#009900">'status'</span>] <span style="color:#880000"># 在admin后台增加过滤器</span>
<span style="color:#000088">class</span> <span style="color:#4f4f4f">GuestAdmin</span><span style="color:#4f4f4f">(admin.ModelAdmin)</span>:
list_display = [<span style="color:#009900">'realname'</span>, <span style="color:#009900">'phone'</span>, <span style="color:#009900">'email'</span>, <span style="color:#009900">'sign'</span>, <span style="color:#009900">'create_time'</span>, <span style="color:#009900">'event'</span>]
search_fields = [<span style="color:#009900">'realname'</span>, <span style="color:#009900">'phone'</span>]
list_filter = [<span style="color:#009900">'sign'</span>]
<span style="color:#880000"># 在admin管理后台注册发布会表、嘉宾表</span>
admin.site.register(Event, EventAdmin)
admin.site.register(Guest, GuestAdmin)</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
4.3 基本数据访问
通过如下方法对数据库中的数据进行访问:
<span style="color:#000000"><code class="language-syslog">root<span style="color:#4f4f4f">@TEST</span><span style="color:#009900">:/home/test/guest</span><span style="color:#880000"># python manage.py shell</span>
<span style="color:#009900">Python</span> <span style="color:#006666">2.7</span>.<span style="color:#006666">12</span> (default, <span style="color:#009900">Nov</span> <span style="color:#006666">19</span> <span style="color:#006666">2016</span>, <span style="color:#006666">06</span><span style="color:#009900">:</span><span style="color:#006666">48</span><span style="color:#009900">:</span><span style="color:#006666">10</span>)
[<span style="color:#009900">GCC</span> <span style="color:#006666">5.4</span>.<span style="color:#006666">0</span> <span style="color:#006666">20160609</span>] on linux2
<span style="color:#009900">Type</span> <span style="color:#009900">"help"</span>, <span style="color:#009900">"copyright"</span>, <span style="color:#009900">"credits"</span> <span style="color:#000088">or</span> <span style="color:#009900">"license"</span> <span style="color:#000088">for</span> more information.
(<span style="color:#009900">InteractiveConsole</span>)
>>> from sign.models import <span style="color:#009900">Event</span>, <span style="color:#009900">Guest</span> <span style="color:#880000"># 导入sign应用下Model中的Event类、Guest类</span>
>>> <span style="color:#009900">Event</span>.objects.all() <span style="color:#880000"># 通过objects.all()获取全部对象</span>
<<span style="color:#009900">QuerySet</span> [<<span style="color:#009900">Event</span><span style="color:#009900">:</span> 好友婚礼>]>
>>> <span style="color:#009900">Guest</span>.objects.all()
<<span style="color:#009900">QuerySet</span> [<<span style="color:#009900">Guest</span><span style="color:#009900">:</span> <span style="color:#009900">Guest</span> object>]>
>>> </code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
可以看到当我们查询Event数据表里的对象时,返回内容是我们添加的记录的name字段,而当我们查询Guest表的对象时,返回的却是对象而不是具体的字段名,这是为什么?
因为在/guest/sign/models.py文件中,我们为Event类定义了返回的字段名,但是Guest类没有定义返回的字段名,所以就造成了上述查询结果的差异。
如果我们也想让Guest在查询的时候返回一个字段名比如realname,而不是返回一个对象object,只需要同样增加如下代码:
<span style="color:#000000"><code class="language-python"><span style="color:#880000"># 嘉宾表</span>
<span style="color:#000088">class</span> <span style="color:#4f4f4f">Guest</span><span style="color:#4f4f4f">(models.Model)</span>:
……
<span style="color:#000088">def</span> <span style="color:#009900">__unicode__</span><span style="color:#4f4f4f">(self)</span>:
<span style="color:#000088">return</span> self.realname</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
再次查询Guest的结果就变为:
<span style="color:#000000"><code><span style="color:#006666">>>> </span>Guest.objects.all()
<QuerySet [<Guest: 好友>]>
<span style="color:#006666">>>> </span></code></span>
- 1
- 2
- 3
插入数据:
<span style="color:#000000"><code class="language-syslog">root<span style="color:#006666">@TEST:/home/test/guest# python manage.py shell</span>
Python <span style="color:#006666">2.7</span><span style="color:#006666">.12</span> (default, Nov <span style="color:#006666">19</span> <span style="color:#006666">2016</span>, <span style="color:#006666">06</span>:<span style="color:#006666">48</span>:<span style="color:#006666">10</span>)
[GCC <span style="color:#006666">5.4</span><span style="color:#006666">.0</span> <span style="color:#006666">20160609</span>] on linux2
Type <span style="color:#009900">"help"</span>, <span style="color:#009900">"copyright"</span>, <span style="color:#009900">"credits"</span> <span style="color:#000088">or</span> <span style="color:#009900">"license"</span> <span style="color:#000088">for</span> more information.
(InteractiveConsole)
<span style="color:#006666">>>> </span><span style="color:#000088">from</span> sign.models <span style="color:#000088">import</span> Event, Guest
<span style="color:#006666">>>> </span><span style="color:#000088">from</span> datetime <span style="color:#000088">import</span> datetime
<span style="color:#006666">>>> </span>e1 = Event(name=<span style="color:#009900">'周末聚会'</span>, limit=<span style="color:#006666">200</span>, status=<span style="color:#000088">True</span>, address=<span style="color:#009900">'北京'</span>, start_time=datetime(<span style="color:#006666">2017</span>,<span style="color:#006666">6</span>,<span style="color:#006666">10</span>,<span style="color:#006666">15</span>,<span style="color:#006666">0</span>,<span style="color:#006666">0</span>))
<span style="color:#006666">>>> </span>e1.save()
/usr/local/lib/python2<span style="color:#006666">.7</span>/dist-packages/django/db/models/fields/__init__.py:<span style="color:#006666">1430</span>: RuntimeWarning: DateTimeField Event.start_time received a naive datetime (<span style="color:#006666">2017</span>-<span style="color:#006666">06</span>-<span style="color:#006666">10</span> <span style="color:#006666">15</span>:<span style="color:#006666">00</span>:<span style="color:#006666">00</span>) <span style="color:#000088">while</span> time zone support <span style="color:#000088">is</span> active.
RuntimeWarning)
<span style="color:#006666">>>> </span></code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
这里与书中略有区别,书中是在插入数据时,指定了id=2,实际上id是数据表中自增字段,插入数据的时候也不可能先去查下id现在是多少了,所以忽略该字段,直接插入数据也是可以的。
忽略结尾时间警告信息: 修改/guest/settings.py文件,设置USE_TZ=False
上面的步骤,先是创建数据,然后调用save()方法保存至数据表中,也可以将两步合为一步:
<span style="color:#000000"><code class="language-syslog">>>> <span style="color:#000088">Event</span>.objects.<span style="color:#000088">create</span>(id=<span style="color:#006666">3</span>, name=<span style="color:#009900">'红米MAX发布会'</span>, limit=<span style="color:#006666">200</span>, status=<span style="color:#000088">True</span>, address=<span style="color:#009900">'北京会展中心'</span>, start_time=datetime(<span style="color:#006666">2016</span>,<span style="color:#006666">9</span>,<span style="color:#006666">22</span>,<span style="color:#006666">14</span>,<span style="color:#006666">0</span>,<span style="color:#006666">0</span>))
<<span style="color:#000088">Event</span>: 红米MAX发布会>
>>> Guest.objects.<span style="color:#000088">create</span>(realname=<span style="color:#009900">'Andy'</span>, phone=<span style="color:#006666">13611001101</span>, email=<span style="color:#009900">'[email protected]'</span>, sign=<span style="color:#000088">False</span>, event_id=<span style="color:#006666">3</span>)
<Guest: Andy>
>>> </code></span>
- 1
- 2
- 3
- 4
- 5
通过指定Event的id=3、Guest的event_id=3,将两者进行关联。
查询数据:
table.objects.create():一步插入数据。
table.objects.get():查询一条匹配的结果,返回结果为对象,返回结果不存在报DoesNotExist错误。
table.objects.filter():查询匹配的结果,返回结果为对象列表,返回结果不存在返回空列表[]。
<span style="color:#000000"><code class="language-syslog"><span style="color:#880000"># 使用get()查询name=红米MAX发布会的记录</span>
<span style="color:#006666">>>> </span>e1 = Event.objects.get(name=<span style="color:#009900">'红米MAX发布会'</span>)
<span style="color:#880000"># 返回的结果e1是个对象</span>
<span style="color:#006666">>>> </span>e1
<Event: 红米MAX发布会>
<span style="color:#880000"># 从e1对象获取start_time的值</span>
<span style="color:#006666">>>> </span>e1.start_time
datetime.datetime(<span style="color:#006666">2016</span>, <span style="color:#006666">9</span>, <span style="color:#006666">22</span>, <span style="color:#006666">14</span>, <span style="color:#006666">0</span>, tzinfo=<UTC>)
<span style="color:#880000"># 也可以不赋值给e1,而是直接在get()方法后加上字段名来获取对应的值</span>
<span style="color:#006666">>>> </span>Event.objects.get(name=<span style="color:#009900">'红米MAX发布会'</span>).status
<span style="color:#000088">True</span>
<span style="color:#880000"># 同理查询红米MAX发布会的地点</span>
<span style="color:#006666">>>> </span>Event.objects.get(name=<span style="color:#009900">'红米MAX发布会'</span>).address
<span style="color:#009900">u'\u5317\u4eac\u4f1a\u5c55\u4e2d\u5fc3'</span>
<span style="color:#880000"># 如果查询条件结果不存在则会报错DoesNotExist</span>
<span style="color:#006666">>>> </span>Event.objects.get(name=<span style="color:#009900">'发布会'</span>).address
Traceback (most recent call last):
File <span style="color:#009900">"<console>"</span>, line <span style="color:#006666">1</span>, <span style="color:#000088">in</span> <module>
File <span style="color:#009900">"/usr/local/lib/python2.7/dist-packages/django/db/models/manager.py"</span>, line <span style="color:#006666">85</span>, <span style="color:#000088">in</span> manager_method
<span style="color:#000088">return</span> getattr(self.get_queryset(), name)(*args, **kwargs)
File <span style="color:#009900">"/usr/local/lib/python2.7/dist-packages/django/db/models/query.py"</span>, line <span style="color:#006666">385</span>, <span style="color:#000088">in</span> get
self.model._meta.object_name
DoesNotExist: Event matching query does <span style="color:#000088">not</span> exist.
<span style="color:#880000"># 使用filter来过滤指定条件获取对象列表,注意name和contains之间是双下划线</span>
<span style="color:#006666">>>> </span>e2 = Event.objects.filter(name__contains=<span style="color:#009900">'发布会'</span>)
<span style="color:#880000"># 返回结果e2是个结果列表</span>
<span style="color:#006666">>>> </span>e2
<QuerySet [<Event: 红米MAX发布会>]>
<span style="color:#880000"># 既然是列表就可以用如下方式访问其中数据</span>
<span style="color:#006666">>>> </span>e2[<span style="color:#006666">0</span>]
<Event: 红米MAX发布会>
<span style="color:#880000"># 关联查询示例,先使用get()方法获取查询结果对象</span>
<span style="color:#006666">>>> </span>g1 = Guest.objects.get(phone=<span style="color:#009900">'13611001101'</span>)
<span style="color:#880000"># 关联查询phone为136……嘉宾所对应的发布会信息event</span>
<span style="color:#006666">>>> </span>g1.event
<Event: 红米MAX发布会>
<span style="color:#880000"># 该嘉宾对应发布会的名称</span>
<span style="color:#006666">>>> </span>g1.event.name
<span style="color:#009900">u'\u7ea2\u7c73MAX\u53d1\u5e03\u4f1a'</span>
<span style="color:#880000"># 该嘉宾对应发布会的地址</span>
<span style="color:#006666">>>> </span>g1.event.address
<span style="color:#009900">u'\u5317\u4eac\u4f1a\u5c55\u4e2d\u5fc3'</span>
<span style="color:#006666">>>> </span></code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
删除数据:
table.objects.get().delete():获取指定查询条件的结果对象并删除。
获取查询对象,调用delete()方法进行删除:
<span style="color:#000000"><code class="language-syslog"><span style="color:#880000"># 先获取查询对象,再调用delete()方法删除</span>
<span style="color:#006666">>>> </span>g2 = Guest.objects.get(phone=<span style="color:#009900">'13611001101'</span>)
<span style="color:#006666">>>> </span>g2.delete()
(<span style="color:#006666">1</span>, {<span style="color:#009900">u'sign.Guest'</span>: <span style="color:#006666">1</span>})
<span style="color:#006666">>>> </span>
<span style="color:#880000"># 不可以重复删除</span>
<span style="color:#006666">>>> </span>Guest.objects.get(phone=<span style="color:#009900">'13611001101'</span>).delete()
Traceback (most recent call last):
File <span style="color:#009900">"<console>"</span>, line <span style="color:#006666">1</span>, <span style="color:#000088">in</span> <module>
File <span style="color:#009900">"/usr/local/lib/python2.7/dist-packages/django/db/models/manager.py"</span>, line <span style="color:#006666">85</span>, <span style="color:#000088">in</span> manager_method
<span style="color:#000088">return</span> getattr(self.get_queryset(), name)(*args, **kwargs)
File <span style="color:#009900">"/usr/local/lib/python2.7/dist-packages/django/db/models/query.py"</span>, line <span style="color:#006666">385</span>, <span style="color:#000088">in</span> get
self.model._meta.object_name
DoesNotExist: Guest matching query does <span style="color:#000088">not</span> exist.
<span style="color:#006666">>>> </span></code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
更新数据:
table.objects.select_for_update().filter().update():过滤指定条件的对象列表并调用update()方法更新指定数据。
<span style="color:#000000"><code class="language-syslog"><span style="color:#880000"># 先获取查询对象,再更新指定数据,最后保存至数据表</span>
<span style="color:#006666">>>> </span>g3 = Guest.objects.get(phone=<span style="color:#009900">'13611001101'</span>)
<span style="color:#006666">>>> </span>g3.realname = <span style="color:#009900">'Andy2'</span>
<span style="color:#006666">>>> </span>g3.save()
<span style="color:#006666">>>> </span>
<span style="color:#880000"># 直接使用select_for_update方法过滤指定条件对象列表再调用update方法更新数据并保存至数据表</span>
<span style="color:#006666">>>> </span>Guest.objects.select_for_update().filter(phone=<span style="color:#009900">'13611001101'</span>).update(realname=<span style="color:#009900">'Andy2'</span>)
<span style="color:#006666">1</span>
<span style="color:#006666">>>> </span></code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
4.4 SQLite管理工具
Pass
4.5 配置MySQL
安装MySQL
Pass
安装MySQL-Python驱动
如果使用Python2版本:安装MySQL-Python
如果使用Python3版本:安装PyMySQL
MySQL基本操作
- show databases; # 查看当前数据库下面的所有库
- use test; # 切换到test库
- show tables; #查看test库下面所有表
- show global variables like ‘port’; #查看MySQL端口号
- CREATE DATABASE guest CHARACTER SET utf8; #创建guest数据库
书中使用如下代码演示了如何通过pymysql库对数据库进行操作,插入数据,但是书中忽略了一个重要前提,我们从开始新建Django项目的时候,就使用的是SQLite3数据库,并没有用MySQL进行过任何操作,这如果直接按代码执行,只会提示错误没有guest表,对啊,是没有啊,上面只是在基本操作里,新建了guest库,但是没有在guest库下新建表,所以在执行插入数据的代码之前,我们应该先新建两个表:sign_event、sign_guest
<span style="color:#000000"><code class="language-sql"># 创建sign_event表
<span style="color:#000088">CREATE</span> <span style="color:#000088">TABLE</span> <span style="color:#009900">`sign_event`</span> (
<span style="color:#009900">`id`</span> <span style="color:#000088">int</span>(<span style="color:#006666">11</span>) <span style="color:#000088">NOT</span> <span style="color:#000088">NULL</span> AUTO_INCREMENT,
<span style="color:#009900">`name`</span> <span style="color:#000088">varchar</span>(<span style="color:#006666">100</span>) <span style="color:#000088">NOT</span> <span style="color:#000088">NULL</span>,
<span style="color:#009900">`limit`</span> <span style="color:#000088">integer</span>,
<span style="color:#009900">`status`</span> BOOLEAN,
<span style="color:#009900">`address`</span> <span style="color:#000088">varchar</span>(<span style="color:#006666">200</span>) <span style="color:#000088">NOT</span> <span style="color:#000088">NULL</span>,
<span style="color:#009900">`start_time`</span> DATETIME,
<span style="color:#009900">`create_time`</span> DATETIME <span style="color:#000088">DEFAULT</span> <span style="color:#000088">CURRENT_TIMESTAMP</span>,
<span style="color:#000088">PRIMARY</span> <span style="color:#000088">KEY</span> (<span style="color:#009900">`id`</span>)
)ENGINE=InnoDB <span style="color:#000088">DEFAULT</span> CHARSET=utf8;
<span style="color:#000088">alter</span> <span style="color:#000088">table</span> <span style="color:#009900">`sign_event`</span> <span style="color:#000088">add</span> index id(id);</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
<span style="color:#000000"><code class="language-sql"># 创建sign_guest表
<span style="color:#000088">CREATE</span> <span style="color:#000088">TABLE</span> <span style="color:#009900">`sign_guest`</span> (
<span style="color:#009900">`id`</span> <span style="color:#000088">int</span>(<span style="color:#006666">11</span>) <span style="color:#000088">NOT</span> <span style="color:#000088">NULL</span> AUTO_INCREMENT,
<span style="color:#009900">`event_id`</span> <span style="color:#000088">int</span>(<span style="color:#006666">11</span>) <span style="color:#000088">NOT</span> <span style="color:#000088">NULL</span>,
<span style="color:#009900">`realname`</span> <span style="color:#000088">varchar</span>(<span style="color:#006666">64</span>) <span style="color:#000088">NOT</span> <span style="color:#000088">NULL</span>,
<span style="color:#009900">`phone`</span> <span style="color:#000088">varchar</span>(<span style="color:#006666">16</span>) <span style="color:#000088">NOT</span> <span style="color:#000088">NULL</span>,
<span style="color:#009900">`email`</span> <span style="color:#000088">varchar</span>(<span style="color:#006666">254</span>) <span style="color:#000088">NOT</span> <span style="color:#000088">NULL</span>,
<span style="color:#009900">`sign`</span> BOOLEAN,
<span style="color:#009900">`create_time`</span> DATETIME <span style="color:#000088">DEFAULT</span> <span style="color:#000088">CURRENT_TIMESTAMP</span>,
<span style="color:#000088">PRIMARY</span> <span style="color:#000088">KEY</span> (<span style="color:#009900">`id`</span>),
<span style="color:#000088">FOREIGN</span> <span style="color:#000088">KEY</span> (<span style="color:#009900">`event_id`</span>) <span style="color:#000088">REFERENCES</span> sign_event(id)
)ENGINE=InnoDB <span style="color:#000088">DEFAULT</span> CHARSET=utf8;
<span style="color:#000088">alter</span> <span style="color:#000088">table</span> <span style="color:#009900">`sign_guest`</span> <span style="color:#000088">add</span> index id(id);
<span style="color:#000088">alter</span> <span style="color:#000088">table</span> <span style="color:#009900">`sign_guest`</span> <span style="color:#000088">add</span> <span style="color:#000088">unique</span>(event_id, phone);</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
<span style="color:#000000"><code class="language-python"><span style="color:#880000">#! /usr/bin python</span>
<span style="color:#880000"># -*- coding: utf-8 -*-</span>
<span style="color:#000088">from</span> pymysql <span style="color:#000088">import</span> cursors, connect
<span style="color:#880000"># 连接数据库</span>
conn = connect(host=<span style="color:#009900">'127.0.0.1'</span>,
user=<span style="color:#009900">'root'</span>,
password=<span style="color:#009900">'nsfocus'</span>,
db=<span style="color:#009900">'guest'</span>,
charset=<span style="color:#009900">'utf8mb4'</span>,
cursorclass=cursors.DictCursor)
<span style="color:#000088">try</span>:
<span style="color:#000088">with</span> conn.cursor() <span style="color:#000088">as</span> cursor:
<span style="color:#880000"># 创建发布会数据</span>
sql = <span style="color:#009900">'INSERT INTO sign_event (name, `limit`, status, address, start_time, create_time) VALUES ("红米MAX发布会", 200, 1, "北京会展中心", "2016-09-22 14:00:00", NOW());'</span>
cursor.execute(sql)
<span style="color:#880000"># 提交事务</span>
conn.commit()
<span style="color:#880000"># 创建嘉宾数据</span>
sql = <span style="color:#009900">'INSERT INTO sign_guest (realname, phone, email, `sign`, event_id, create_time) VALUES ("Tom", 18800110002, "[email protected]", 0, 1, NOW());'</span>
cursor.execute(sql)
<span style="color:#880000"># 提交事务</span>
conn.commit()
<span style="color:#000088">with</span> conn.cursor() <span style="color:#000088">as</span> cursor:
<span style="color:#880000"># 查询刚刚添加的嘉宾</span>
sql = <span style="color:#009900">'SELECT realname, phone, email, sign FROM sign_guest WHERE phone=%s'</span>
cursor.execute(sql, (<span style="color:#009900">'18800110002'</span>,))
result = cursor.fetchone()
<span style="color:#000088">print</span> result
<span style="color:#000088">finally</span>:
conn.close()</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
在这个过程中遇到一些问题:
我们安装了MySQL数据库后,虽然创建了guest数据库,但是并没有创建发布会表、嘉宾表,所以如果按书中直接执行此py文件,一定会报错,提示guest表不存在!!!
如何解决这个问题,很简单,参考之前models.py文件里的设置,先创建好两个数据表event、guest,再来执行这个py文件就不会出错了!
引申出两个问题:
- 如何使MySQL服务端不只是监听本地127.0.0.1这个地址?
- 这就需要修改配置文件/etc/mysql/mysql.conf.d/mysqld.cnf,将其中的bind-address由127.0.0.1修改为0.0.0.0,重启MySQL服务即可/etc/init.d/mysql restart;
- 如果通过远程来访问MySQL服务端?
- 对MySQL实在不熟,发现用起来很多基础知识都不懂,查了好半天的资料才找到问题根本,原本以为在配置文件里修改各什么安全设置就能搞定,然而并不是这么回事,这是由于root用户在mysql数据库中存储的host字段的限制;
- 首先在本地登录MySQL数据库:mysql -u root -p,然后切换至mysql数据库:use mysql;,查看user表中root帐号的记录:select * from user where user=’root’;,可以发现host字段的值为localhost,这就是为什么远程主机无法使用root帐号来访问的原因了;
- 解决办法就是给host字段增加远程主机的IP:grant all privileges on *.* to root@”远程主机IP地址” identified by “root帐号对应的密码”;,这就相当于给远程IP赋予了所有的权限,包括远程访问的权限,然后输入:flush privileges;,这相当于是重新加载一下mysql权限;
- 至此,就又可以从本地访问也能从远程主机访问了。
pymysql里的几个重要函数:
- connect():建立数据库连接;
- cursor():获取数据库操作游标;
- execute():执行SQL语句;
- commit():提交数据库执行;
- close():关闭数据库连接;
在Django中配置MyDQL
修改配置文件/guest/settings.py:
<span style="color:#000000"><code class="language-python">DATABASES = {
<span style="color:#009900">'default'</span>: {
<span style="color:#009900">'ENGINE'</span>: <span style="color:#009900">'django.db.backends.mysql'</span>,
<span style="color:#009900">'HOST'</span>: <span style="color:#009900">'127.0.0.1'</span>,
<span style="color:#009900">'PORT'</span>: <span style="color:#009900">'3306'</span>,
<span style="color:#009900">'NAME'</span>: <span style="color:#009900">'guest'</span>,
<span style="color:#009900">'USER'</span>: <span style="color:#009900">'root'</span>,
<span style="color:#009900">'PASSWORD'</span>: <span style="color:#009900">'123456'</span>,
<span style="color:#009900">'OPTIONS'</span>: {
<span style="color:#009900">'init_command'</span>: <span style="color:#009900">"SET sql_mode='STRICT_TRANS_TABLES'"</span>,
},
}
}</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
注意:需要先把原数据库注释掉。
虫师的是在本章节,才讲解了如何将SQLite3里的数据同步至MySQL里,因为并不能这样复制数据,但是可以使用:
python manage.py migrate
命令来重新执行数据库同步,是数据模型重新在MySQL数据库中生成表。这也就是上面我提到的虫师缺少的部分,只不过我上面是用笨方法手工重建MySQL的数据表,而这里是使用数据同步命令。
但是在执行此命令的时候也会遇到问题,即:“如何让Django通过PyMySQL来连接数据库”?
需要在/guest/__init__.py中加入如下代码:
<span style="color:#000000"><code class="language-python"><span style="color:#000088">import</span> pymysql
pymysql.install_as_MySQLdb()</code></span>
- 1
- 2
- 3
再次执行migrate命令就不会出错了,由于更换了MySQL数据库,所以admin后台的超级管理员的账号也要重建。
MySQL管理工具
- Navicat
- SQLyog
至此第4章的全部内容都结束了。本章的内容主要围绕Django的Model层,也就是数据层做简要介绍。主要知识点就是model.py以及数据在管理后台admin.py里如何展示。