【Django】【三】模型
---------------------------------------【MySQL】--由于之前用的是sqlite,所以现在要重新来过----------start-----------------
1 数据库客户端删除数据库:
mysql> drop database 数据库名字;
【备注】如果报错:mysql errro 1010 (HY000) 参考:https://jingyan.baidu.com/article/d71306352af34613fdf475eb.html
2 清理项目中关于数据库的缓存 :删掉migrations和 __pycache__ folder
3 数据库客户端创建数据库,编码格式选择"utf-8"
mysql> CREATE DATABASE guest CHARACTER SET utf8;
4 重新执行:
python3 manage.py makemigrations app名字
python3 manage.py migrate
5. Admin 后台超级管理员账号(admin/admin123) 也需要重新创建
cmd.exe
D:\pydj\guest>python3 manage.py createsuperuser
Username (leave blank to use 'fnngj'): admin #输入登录用户名
Email address:admin@mail.com
Password:#数据登录密码
Password(again):#再次输入密码
Superuser created successfully.
6. MySQL客户端安装
win7 我用 HeidiSQL_9.4.0.5125
---------------------------------------【MySQL】--由于之前用的是sqlite,所以现在要重新来过----------end-----------------
4.1 设计系统表
Django提供了完善的模型层来创建和存取数据,它包含你所存储数据的必要字段和行为。通常,每个模型对应数据库中唯一一张表。所以,模型避免了我们直接对数据库操作。
Django模型基础知识:
- 每个模型是一个Python类,继承django.db.models.Model 类
- 该模型的每个属性表示一个数据库表字段
- 所有这一切,已经给了你一个自动生成的数据库访问的API
打开 .../sign/models.py
# -*- coding: UTF-8 -*-
from django.db import models
# Create your models here.
# 发布会表
class Event(models.Model):
name = models.CharField(max_length=100) # 发布会标题
limit = models.IntegerField() # 参加人数
status = models.BooleanField() # 状态
address = models.CharField(max_length=200) # 地址
start_time = models.DateTimeField('events time') # 发布会时间
create_time = models.DateTimeField(auto_now=True) # 创建时间(自动获取当前时间)
def __str__(self):
return self.name
# 嘉宾表
class Guest(models.Model):
event = models.ForeignKey(Event, on_delete=models.CASCADE) # 关联发布会ID
realname = models.CharField(max_length=64) # 姓名
phone = models.CharField(max_length=16) # 手机号
email = models.EmailField() # 邮箱
sign = models.BooleanField() # 签到状态
create_time = models.DateTimeField(auto_now=True) # 创建时间(默认获取当前时间)
class Meta:
unique_together = ('event', 'phone')
def __str__(self):
return self.realname
对于产品发布会来说,它是一个事件。那么时间、地点、人物等要素必不可少。数据库表将会围绕这些要素设计。
发布会表 (Event表)和嘉宾表(Guest表)的每一个字段在代码中已经做了注解。有些字段的设计需要做一个简单的说明。
首先,发布会表和嘉宾表中默认都会生成自增ID,但在创建模型类时不需要声明该字段。
其次,发布会表中增加status字段用于表示该发布会的状态是否开启,从而控制发布会是否可用。
再次,嘉宾表中通过字段event(表中字段名event_id)关联发布会ID,一条嘉宾信息一定是属于某一场发布会。ForeignKey()用来创建外键。
最后,对于一场发布会来说,因为手机号具有很强的唯一性,因此一般会选择手机号作为一位嘉宾的唯一验证信息。在嘉宾表中,除了嘉宾ID为主键外,这里通过发布会id+手机号来作为联合主键。Meta是Django模型类的一个内部类,它用于定义
一些Django模型类的行为特性。unique_together用于设置两个字段为联合主键。
__str__()方法告诉Python如何将对象以str的方式显示出来。所以,为每个模型类添加了__str__()
Django模型字段常用类型
官方参考文档 https://docs.djangoproject.com/en/3.1/ref/models/fields
数据库迁移
B0178RQ2019070018:guest wangxue$ python3 manage.py makemigrations sign
Migrations for 'sign':
sign/migrations/0001_initial.py
- Create model Event
- Create model Guest
B0178RQ2019070018:guest wangxue$ python3 manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions, sign
Running migrations:
Applying sign.0001_initial... OK
4.2 admin后台管理
admin.py
from django.contrib import admin
from sign.models import Event, Guest
# Register your models here.
admin.site.register(Event)
admin.site.register(Guest)
这些代码通知Admin管理工具为这些模块逐一提供界面。
登陆admin后台: http://127.0.0.1:8000/admin/ (admin/admin123456)
单击Events对应的add 添加一条发布会信息
如何才能显示表中更多字段呢? 继续修改../sign/admin.py
from django.contrib import admin
from sign.models import Event, Guest
# Register your models here.
class EventAdmin(admin.ModelAdmin):
list_display = ['id', 'name', 'status', 'address', 'start_time']
class GuestAdmin(admin.ModelAdmin):
list_display = ['realname', 'phone', 'email', 'sign', 'create_time', 'event']
admin.site.register(Event, EventAdmin)
admin.site.register(Guest, GuestAdmin)
Django提供了大量选项让你针对特别的模块自定义管理工具。这些选项都在ModleAdmin类中,创建EventAdmin类 ModelAdmin。 这里只自定义了一项,list_display,
它是一个字段名称的数组,用于定义要在列表中显示哪些字段。当然,这些字段名称必须是模型中的Event() 类所定义的。
修改admin.site.register(),添加 EventAdmin类。你可以这样理解,用EventAdmin选项注册Event模块。
对于Guest模块来说,操作步骤同上。保存修改的代码,重新刷新Events列表,如图
添加一条嘉宾信息,如下图
除此之外,还可以快速生成搜索栏和过滤器。重新打开../sign/admin.py 修改如下
from django.contrib import admin
from sign.models import Event, Guest
# Register your models here.
class EventAdmin(admin.ModelAdmin):
list_display = ['id', 'name', 'status', 'address', 'start_time']
search_fields = ['name'] #搜索栏
list_filter = ['status'] #过滤器
class GuestAdmin(admin.ModelAdmin):
list_display = ['realname', 'phone', 'email', 'sign', 'create_time', 'event']
search_fields = ['realname', 'phone'] # 搜索栏
list_filter = ['sign'] # 过滤器
admin.site.register(Event, EventAdmin)
admin.site.register(Guest, GuestAdmin)
访问http://127.0.0.1:8000/admin/sign/event/
4.3 基本数据访问
当需要操作数据库时,不再需要通过SQL语句。Django自动为这些模型提供了高级的API。接下来联系数据库表的操作,运行manage.py提供的shell命令
cmd.exe
B0178RQ2019070018:~ wangxue$ cd ~/Library/Python/3.7/bin/guest/
B0178RQ2019070018:guest wangxue$ python3 manage.py shell
Python 3.7.1 (v3.7.1:260ec2c36a, Oct 20 2018, 03:13:28)
[Clang 6.0 (clang-600.0.57)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from sign.models import Event, Guest
>>> Event.objects.all()
<QuerySet [<Event: 小米5发布会>]>
>>> Guest.objects.all()
<QuerySet [<Guest: snow>]>
>>>
4.3.1 插入数据
>>> from datetime import datetime
>>> e1 = Event(id=2, name='红米Pro发布会', limit=2000, status=True, address='北京水立方', start_time=datetime(2020, 6, 24, 14, 0, 0))
>>> e1.save()
/Users/wangxue/Library/Python/3.7/lib/python/site-packages/django/db/models/fields/__init__.py:1368: RuntimeWarning: DateTimeField Event.start_time received a naive datetime (2020-06-24 14:00:00) while time zone support is active.
RuntimeWarning)
>>>
因为 start_time字段需要设置日期时间,所以先导入datetime.datetime()方法。当通过save()保存插入的数据时,我们收到一行警告信息:
RuntimeWarning: DateTimeField Event.start_time received a naive datetime (2020-06-24 14:00:00) while time zone support is active.
这跟UTC有关,如果读者感兴趣可以自己搜索UTC是什么? 这里选择忽略这个问题,最简单的方式就是在../settings.py 文件中设置:USE_TZ = False
修改settings.py并保存,需要执行quit()命令退出shell模式,并重启python3 manage.py shell进入,刚才的设置才会生效。再次执行插入数据的步骤,看看警告信息是不是不见了。
>>> from sign.models import Event, Guest
>>> e2 = Event(id=3, name='realme发布会', limit=200, status=True, address='shanghai新天地', start_time=datetime(2020,8,8,15,0,0))
>>> e2.save()
>>>
如果觉得创建和保存分两步完成太麻烦,也可以通过table.objects.create() 将两步合为一步,方法如下
.....
>>> Event.objects.create(id=4, name='红米Max 发布会', limit=2000, status=True, address='北京会展中心', start_time=datetime(2016,9,22,14,0,0))
<Event: 红米Max 发布会>
>>> Guest.objects.create(realname='snow2', phone=13611001101, email='snow2@mail.com', sign=False, event_id=4)
<Guest: snow2>
需要说明的是,表的ID字段已经设置了自增,所以创建表数据可以不用指定ID,但在创建嘉宾数据时需要指定关联的发布会ID。Event表指定id=4, Guest表指定event_id=4,所以嘉宾‘snow2'对应的是‘红米Max发布会‘
4.3.2 查询数据
table.objects.get()用于从数据库表中取得一条匹配的结果,返回一个对象,如果记录不存在的话,那么它会报DoesNotExist 类型错误。
通过name='红米Max 发布会‘ 作为查询条件。
>>> from sign.models import Event, Guest
>>> Event.objects.all()
<QuerySet [<Event: 小米5发布会>, <Event: 红米Pro发布会>, <Event: realme发布会>, <Event: 红米Max 发布会>]>
>>> e1 = Event.objects.get(name='红米Max 发布会')
>>> e1
<Event: 红米Max 发布会>
>>> e1.address
'北京会展中心'
>>> e1.start_time
datetime.datetime(2016, 9, 22, 14, 0)
>>> Event.objects.get(name='红米Max 发布会').status
True
>>> Event.objects.get(name='红米Max 发布会').limit
2000
>>> Event.objects.get(name='红米Max').address
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/Users/wangxue/Library/Python/3.7/lib/python/site-packages/django/db/models/manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/Users/wangxue/Library/Python/3.7/lib/python/site-packages/django/db/models/query.py", line 417, in get
self.model._meta.object_name
sign.models.Event.DoesNotExist: Event matching query does not exist.
>>>
因为name='红米Max‘并没有完全匹配到发布会名称,所以跑出DoesNotExist异常。但更多的时候我们会使用模糊查询。
table.objects.filter() 匹配结果,返回一个对象列表,如果记录不存在,返回空列表
cmd.exe
...
>>> e2 = Event.objects.filter(name__contains='发布会')
>>> e2
<QuerySet [<Event: 小米5发布会>, <Event: 红米Pro发布会>, <Event: realme发布会>, <Event: 红米Max 发布会>]>
>>>
【备注】name__contains是双下划线
接下来通过嘉宾查询其关联的发布会信息
cmd.exe
...
>>> g = Guest.objects.get(phone=13611001101)
>>> g
<Guest: snow2>
>>> g.event
<Event: 红米Max 发布会>
>>> g.event.name
'红米Max\xa0发布会'
>>> g.event.address
'北京会展中心'
4.3.3 删除数据
cmd.exe
>>> g = Guest.objects.get(phone=13611001101)
>>> g.delete()
(1, {'sign.Guest': 1})
4.3.4 更新数据
...
>>> g = Guest.objects.get(phone=123000)
>>> g.realname='snow2'
>>> g.save()
或者
...
>>> Guest.objects.select_for_update().filter(phone='123000').update(realname='snow3')
1
4.5.3 安装PyMySQL驱动
mysql_demo.py
from pymysql import cursors, connect
# 连接数据库
conn = connect(host='127.0.0.1', user='root', password='123', db='guest', charset='utf8mb4', cursorclass=cursors.DictCursor)
try:
with conn.cursor() as cursor:
#创建嘉宾数据
sql = 'insert into sign_guest(realname, phone, email, sign, event_id, create_time) values ('snow3', 678, 'snow3@mail.com, 0, 1, NOW());'
#提交事务
conn.commit()
with conn.cursor() as cursor:
#查询添加的嘉宾
sql = 'select realname, phone, email, sign from sign_guest where phone=%s'
cursor.execute(sql, ('123000',))
result = cursor.fetchone()
print(result)
finally:
conn.close()
4.5.4 =Django中配置Mysql
.. guest/settings.py
...
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'HOST': '127.0.0.1',
'PORT': '3306',
'NAME': 'guest',
'USER': 'root',
'PASSWORD': '123',
'OPTIONS': {
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
},
}
}
cmd.exe
B0178RQ2019070018:guest wangxue$ python3 manage.py migrate
Traceback (most recent call last):
File "/Users/wangxue/Library/Python/3.7/lib/python/site-packages/django/db/backends/mysql/base.py", line 16, in <module>
import MySQLdb as Database
ModuleNotFoundError: No module named 'MySQLdb'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "manage.py", line 21, in <module>
main()
File "manage.py", line 17, in main
execute_from_command_line(sys.argv)
File "/Users/wangxue/Library/Python/3.7/lib/python/site-packages/django/core/management/__init__.py", line 401, in execute_from_command_line
utility.execute()
File "/Users/wangxue/Library/Python/3.7/lib/python/site-packages/django/core/management/__init__.py", line 377, in execute
django.setup()
File "/Users/wangxue/Library/Python/3.7/lib/python/site-packages/django/__init__.py", line 24, in setup
apps.populate(settings.INSTALLED_APPS)
File "/Users/wangxue/Library/Python/3.7/lib/python/site-packages/django/apps/registry.py", line 114, in populate
app_config.import_models()
File "/Users/wangxue/Library/Python/3.7/lib/python/site-packages/django/apps/config.py", line 211, in import_models
self.models_module = import_module(models_module_name)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/importlib/__init__.py", line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
File "<frozen importlib._bootstrap>", line 983, in _find_and_load
File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 728, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "/Users/wangxue/Library/Python/3.7/lib/python/site-packages/django/contrib/auth/models.py", line 2, in <module>
from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager
File "/Users/wangxue/Library/Python/3.7/lib/python/site-packages/django/contrib/auth/base_user.py", line 47, in <module>
class AbstractBaseUser(models.Model):
File "/Users/wangxue/Library/Python/3.7/lib/python/site-packages/django/db/models/base.py", line 121, in __new__
new_class.add_to_class('_meta', Options(meta, app_label))
File "/Users/wangxue/Library/Python/3.7/lib/python/site-packages/django/db/models/base.py", line 325, in add_to_class
value.contribute_to_class(cls, name)
File "/Users/wangxue/Library/Python/3.7/lib/python/site-packages/django/db/models/options.py", line 208, in contribute_to_class
self.db_table = truncate_name(self.db_table, connection.ops.max_name_length())
File "/Users/wangxue/Library/Python/3.7/lib/python/site-packages/django/db/__init__.py", line 28, in __getattr__
return getattr(connections[DEFAULT_DB_ALIAS], item)
File "/Users/wangxue/Library/Python/3.7/lib/python/site-packages/django/db/utils.py", line 207, in __getitem__
backend = load_backend(db['ENGINE'])
File "/Users/wangxue/Library/Python/3.7/lib/python/site-packages/django/db/utils.py", line 111, in load_backend
return import_module('%s.base' % backend_name)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/importlib/__init__.py", line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "/Users/wangxue/Library/Python/3.7/lib/python/site-packages/django/db/backends/mysql/base.py", line 21, in <module>
) from err
django.core.exceptions.ImproperlyConfigured: Error loading MySQLdb module.
Did you install mysqlclient?
B0178RQ2019070018:guest wangxue$
出错啦 这是因为Django在连接Mysql时默认MySLdb 驱动 然而我们并没有安装这个驱动,前面已经说明它不支持python3 而现在使用的是PyMySQL 如何让当前的Django通过PyMySQL 来连接mysql呢
../guest/__init__.py
import pymysql
pymysql.install_as_MySQLdb()
重新执行数据库同步
---------------------------------------【MySQL】--由于之前用的是sqlite,所以现在要重新来过----------start-----------------
1 数据库客户端删除数据库:
mysql> drop database 数据库名字;
【备注】如果报错:mysql errro 1010 (HY000) 参考:https://jingyan.baidu.com/article/d71306352af34613fdf475eb.html
2 清理项目中关于数据库的缓存 :删掉migrations和 __pycache__ folder
3 数据库客户端创建数据库,编码格式选择"utf-8"
mysql> CREATE DATABASE guest CHARACTER SET utf8;
4 重新执行:
python3 manage.py makemigrations app名字
python3 manage.py migrate
5. Admin 后台超级管理员账号(admin/admin123) 也需要重新创建
cmd.exe
D:\pydj\guest>python3 manage.py createsuperuser
Username (leave blank to use 'fnngj'): admin #输入登录用户名
Email address:admin@mail.com
Password:#数据登录密码
Password(again):#再次输入密码
Superuser created successfully.
6. MySQL客户端安装
mac pro bn -> navicat
---------------------------------------【MySQL】--由于之前用的是sqlite,所以现在要重新来过----------end-----------------