按照《Python编程:从入门到实践》这本书的项目三所编写的web应用程序
python+Django的web应用程序(二)Django入门
创建应用程序
这次先写一个程序练练手。
首先,要确保你的虚拟环境处于激活状态,并且Django服务正在运行。
如果没有,那么先激活虚拟环境,在项目文件夹(learning_log)中打开cmd
输入命令:
ll_env\Scripts\activate
执行结果:
然后,运行Django服务
命令如下:
python manage.py runserver
执行结果:
注:
退出Django服务: ctrl + c
退出虚拟环境: deacvivate
保持当前运行着runserver的cmd窗口,再另打开一个cmd窗口,切换到manage.py所在的目录,激活虚拟环境。再执行如下指令来创建应用程序:
python manage.py startapp learning_logs
执行结果:
看项目文件多了什么
打开新增的文件
没问题,和书上说的一模一样
定义模型
打开models.py文件
打开后
需要我们创建自己的模型。
这个模型会告诉Django如何处理应用程序中存储的数据。
模型就是类,在编程的世界里万物皆为类。类包含属性和方法。
接下来,我们创建一个存储主题的模型。这个模型包含一个容纳200个字符的主题名(text)和自动记录当前日期和时间的属性(date_added)。
代码如下:
from django.db import models
class Topic(models.Model):
"""用户学习主题"""
text = models.CharField(max_length = 200)
date_added = models.DateTimeField(auto_now_add = True)
def __str__(self):
"""返回模型的字符串表示"""
return self.text
方法__str__(),会返回存储在属性text中的字符串,从而显示模型的简单表示
注:如果使用的是python2,把__str__() 换成 unicode()
models中用到的方法:
-
CharField:表示由字符或文本组成的数据
max_length :设定CharField的最大长度
-
DateTimeField:记录日期和时间的数据
auto_add_now=True:会自动设置成当前日期和时间
模型中可以使用的字段还有很多,可以去官网查找:
Django模型字段参考
激活模型
将我们写的模型安装在项目中,这样我们才能使用模型
首先,打开settings.py文件
打开后如图所示
INSTALLED_APPS 是一个元组,包含了所有Django的应用程序,我们只需要将自己写的应用程序添加进这个元组。
如下图所示
注:
- 我们设置的settings.py是我们使用Django创建的项目(文件夹learning_log)
- 而我们在settings.py中添加的是创建的应用程序(文件夹learning_logs)
现在我们写的模型已经包含进Django的项目中了。下一步,我们要让Django修改数据库,用于存储与模型相关的数据。
命令如下:
python manage.py makemigrations learning_logs
执行结果:
命令makemigrations : 让Django根据我们模型的属性修改数据库,使其能够存储与我们模型相关联的数据。
从执行结果上可以看到Django创建了一个名为0001_initial.py的迁移文件。
打开看看里面长啥样
文件位置如图所示
打开后
可以看到,里面有模型里的两个属性,text和date_added。
不过怎么多出来一个id?
我不记得我有写这个属性啊?
AutoField?意思是自动生成的吗?
不过多东西总比少东西强,大不了删掉完事。
额,有点担心乱删会出事。。。。总之还是问问度娘吧。
20分钟后。。。
还是度娘给力
总结如下:
为什么命令makemigrations生成的迁移文件会多出来一个id?
- 这个id是主键(primary_key=True,这个参数值True表示这个是主键),你不设置主键,就会自动生成
- Django需要主键
- 主键是:被挑选出来,作表的行的唯一标识的候选关键字。
- 主键的作用:
- 保证实体完整性(既每个数据表都必须有主键)
- 操作更便捷
- 避免重复(数据可能存在相同,但主键一定不同)
- 自动按顺序显示表中数据记录
如果我不想用自动生成的主键,我要用我自己的主键
按照度娘的指导试一下
建好自己的主键(同其他属性一样),只需多传一个参数
primary_key=True
即可
别急着生成迁移文件
先把之前的迁移文件0001_initial.py给删了,不然会报错,报错如下:
删掉旧的迁移文件
再生成新的迁移文件(命令不变):
python manage.py makemigrations learning_logs
执行结果:
打开迁移文件看看
非常好,没有自动生成的id主键了,而是被我设置的my_id作为主键代替了。
好了,id这块搞懂了,还是把文件给还原为自动生成的id吧,我可不想后面因为我自己的改动出岔子。
复原后,下面来应用这种迁移,让Django替我们修改数据库
命令如下:
python manage.py migrate
执行结果:
最后一个OK代表learning_logs应用潜意识一切正常。
以后每次修改管理数据时,都是三步走:
- 修改models.py
- 对learning_logs调用makemigrations
python manage.py makemigrations learning_logs
- 让Django迁移项目
python manage.py migrate
Django管理网站
Django提供的管理网站(admin site)可以帮助处理模型,这个管理网站管理员可用,普通用户不能。
下面将建立管理网站,并为模型添加一些主题。
创建超级用户
超级用户:拥有所有权限(想干啥就干啥那种),用于管理Web应用程序
创建超级用户命令:
python manage.py createsuperuser
执行结果:
创建后:
1 处:
密码太短,得有8个字符才行(This password is too short. It must contain at least 8 characters.)
密码太常见(This password is too common)
密码全是数字(This password is entirely numeric)
别设密码了,直接创建账号算了(Bypass password validation and create user anyway?)
2处:和1处一样
没错,我设的密码是六个0。因为复杂的密码我老是忘。再说了,我密码简单怎么了,我乐意,不行吗?
还有,为啥不设密码可以,密码简单不行?好家伙我直呼好家伙,密码再简单那也比没密码强啊。就跟大门敞开着和拿根麻绳捆着们把手一样,有总比没有强吧。
总之,如图所示,与其忘记密码,我选择不设密码。
向管理网站注册模型
Django自动在管理网站中添加了一些模型,如User和Group,但对于我们创建的模型,必须手动进行注册。
创建应用程序learning_logs时,Django在models.py所在的目录中创建了一个名为admin.py的文件
如图所示:
打开:
注册模型需要在admin.py中添加如下代码:
from learning_logs.models import Topic
admin.site.register(Topic)
这段代码导入模型并让Django通过管理网站管理我们的模型
现在,登录管理网站:
http://localhost:8000/admin/
网站如图所示:
输入用户名:ll_admin
因为没有设置密码,所以在密码栏输入你要设置的密码。
我敲了八个0,好记。
登陆后:
添加主题
点击Topics进入主题网页
因为我什么主题都没添加,所以这里面是空的,很正常。
点击添加主题
保存后:
主题添加成功
按书上要求,添加Chess(西洋棋)和Rock Climbing(攀岩运动)这两个主题
添加完毕
定义模型Entry
要记录西洋棋和攀岩运动的任何内容,需要为用户在笔记中添加的条目定义模型。每个条目都与特定主题相关联,这种关系被称为多对一关系,即多个条目可关联到同一个主题。
在models.py中添加模型Entry的代码:
代码如下
class Entry(models.Model):
"""学到的有关某个主题的具体知识"""
topic = models.ForeignKey(Topic)
text = models.TextField()
date_added = models.DateTimeField(auto_now_add = True)
class Meta:
verbose_name_plural = 'entries'
def __str__(self):
"""返回模型的字符串表示"""
return self.text[:50] + "..."
Meta类的verbose_name_plural看书上的介绍,说实话,没看太明白。
不过这都好说,谁让咱有度娘。
5分钟后…
总结如下:
verbose_name_plural属性:指定模型的复数形式是什么
若未指定该属性, Django 会使用 verbose_name + “s”
verbose_name:给主题起一个名字
看解释后,似乎verbose_name_plural的作用就是给你的复数主题起个你定义的名字
而verbose_name是给你的主题起一个名字
猜测一下:
现在的Entry模型,我不想让他在网站管理里面显示为Entry,我要给他起一个好理解的名字。这时可以使用 verbose_name = ’进入‘ ,那么网站管理里面的Entry的名字就会变成 进入 。
而更多的Entry模型的名字使用 verbose_name_plural = ’更多进入‘ ,那么网站管理里面的其他的Entry的名字就会变成 更多进入 。
好,现在来验证一下
woc什么情况,刚才还好好的,怎么和度娘问个事的功夫就出岔子了?
看下cmd
类型错误,缺少一个必要的参数on_delete
虽然指出了是在models.py里少了个参数,但这参数填哪里啊?
书上也没有这个参数啊
淦!!!
3分钟后…
总结如下:
异常描述:
少了个参数 ‘on_delete’(TypeError: init() missing 1 required positional argument: ‘on_delete’)问题原因:
django生成迁移文件报错。django2.0以上版本,表与表之间关联的时候必须写 ’on_delete‘ 参数,不然会报错解决办法:
因为是用外键和外表关联的,所以在外键上加上 ‘on_delete’ 参数,(有主建的模型都要加,Topic的主键是自动生成的,不用加。Entry的主键是我自己设置的,所以要加上)
外键就是models.ForeignKey()
代码如下:
在models.py文件中修改Entry类中的外键
topic = models.ForeignKey(Topic, on_delete = models.CASCADE)
on_delete = models.CASCADE
级联删除,自己的表和关联的表中的数据一起删除
on_delete还有一些其他的设置,网上很多,我觉得用这个就行
好了,再次运行我们的服务
成功启动服务了
登录网站管理看看名字改了没有
唉?别说了名了,我模型都没了?
翻了下前面的笔记,发现是没有进行数据迁移以及注册,不好意思,是我自己少步骤了。
迁移模型Entry
迁移命令有两个代码
先执行命令
python manage.py makemigrations 应用名
再执行命令
python manage.py migrate
代码如下:
python manage.py makemigrations learning_logs
python manage.py migrate
在提示一下,要在项目文件夹的激活环境下:
错误示范:
正确位置:
执行命令:
执行成功
向管理网站注册Entry
修改admin.py
admin.py的位置
打开修改
好了,Entry既迁移了,也注册了。看看网站管理上正确显示没
再修改一下models.py的代码
管理网站页面变化:
Entry的显示名成功修改为 多个进入
但是只有verbose_name_plural属性起了作用,verbose_name完全没效果。
5分钟后…
总结如下:
verbose_name是在添加模型显示对应的名称
verbose_name_plural是在网站管理页面显示对应的名称
比如我这样修改:
模型添加结果如下:
由图可见,verbose_name属性实在模型添加页面显示的。
(这个添加页面所添加的东西叫做条目)
接下来按照书上要求添加条目
添加成功
Django shell
可以通过互交式终端会话以编程方式查看输入的数据,这种互交式环境称为Django shell,非常适合测试项目和排除故障。
互交式shell会话示例:
最终返回的一个列表,称之为查询集(queryset)
代码如下:
启动Python解释器
python manage.py shell
导入模块块learning_logs.models中的模型Topic
from learning_logs.models import Topic
获取模型Topic的所有实例
Topic.objects.all()
对查询集的操作
-
遍历查询集
类似遍历列表
-
通过id获取对象的属性
-
查看与主题相关联的条目
因为给模型Entry定义了属性topic,这是一个外键(ForeignKey),将条目与主题关联起来。利用这种关联,Django能够获取与特定主题相关联的所有条目。
通过外键关系获取数据,可使用相关模型的小写名称、下划线和单词set
例:条目.模型_set.all()
如下图所示:
奇怪,怎么什么都没有?
难道是因为我是用Entry外键外联的Topic,而Topic没有外键,所以程序以为没有外联数据?
总之试一试查看Entry的属性再说。
代码如下:
先遍历一下
>>> from learning_logs.models import Entry
>>> Entry.objects.all()
>>> entries = Entry.objects.all()
>>> for entry in entries:
... print(entry.id,entry)
执行结果:
可以遍历出来
好吧,其实到这里我已经看出来问题出在哪里了。不过还是吧代码写完再说吧
代码如下:
>>> e = Entry.objects.get(id=2)
>>> e.text
>>> e.date_added
执行结果:
接着写查看与主题相关联条目的代码:
e.topic_set.all()
执行结果:
属性错误:“Entry”对象没有属性“topic_set”(AttributeError: ‘Entry’ object has no attribute ‘topic_set’)
显然,模型_set.all()只查询被别人关联,不会查询出自身关联的别人
- 查看被关联的项目
只有 id:2 与 id :3 与Entry相关联,id:1没有关联,故外键关系为空
代码如下:
>>> t = Topic.objects.get(id=3)
>>>> t.entry_set.all()
执行结果:
成功查找到关联
注:
ctrl + Z 退出
每次修改模型后shell要重启