一、创建数据库模型
1、基本的原则如下:
每个模型在Django中的存在形式为一个Python类
每个模型都是django.db.models.Model的子类
模型里的每个类代表数据库中的一个表
模型的每个字段(属性)代表数据表的某一列
Django将自动为你生成数据库访问API
博客项目数据类型,我们需要存储六种数据:文章分类、文章、文章标签、幻灯图、推荐位、友情链接。每种数据一个表
2、博客模型代码
打开blog/models.py,输入代码:
from django.db import models
from django.contrib.auth.models import User
# 导入Django自带用户模块
# 文章分类
class Category(models.Model):
name = models.CharField('博客分类', max_length=100)
index = models.IntegerField(default=999, verbose_name='分类排序')
class Meta:
verbose_name = '博客分类'
verbose_name_plural = verbose_name
def __str__(self):
return self.name
# 文章标签
class Tag(models.Model):
name = models.CharField('文章标签', max_length=100)
class Meta:
verbose_name = '文章标签'
verbose_name_plural = verbose_name
def __str__(self):
return self.name
# 推荐位
class Tui(models.Model):
name = models.CharField('推荐位', max_length=100)
class Meta:
verbose_name = '推荐位'
verbose_name_plural = verbose_name
def __str__(self):
return self.name
# 文章
class Article(models.Model):
title = models.CharField('标题', max_length=70)
excerpt = models.TextField('摘要', max_length=200, blank=True)
category = models.ForeignKey(Category, on_delete=models.DO_NOTHING, verbose_name='分类', blank=True, null=True)
# 使用外键关联分类表与分类是一对多关系
tags = models.ManyToManyField(Tag, verbose_name='标签', blank=True)
# 使用外键关联标签表与标签是多对多关系
img = models.ImageField(upload_to='article_img/%Y/%m/%d/', verbose_name='文章图片', blank=True, null=True)
body = models.TextField()
user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='作者')
"""
文章作者,这里User是从django.contrib.auth.models导入的。
这里我们通过 ForeignKey 把文章和 User 关联了起来。
"""
views = models.PositiveIntegerField('阅读量', default=0)
tui = models.ForeignKey(Tui, on_delete=models.DO_NOTHING, verbose_name='推荐位', blank=True, null=True)
created_time = models.DateTimeField('发布时间', auto_now_add=True)
modified_time = models.DateTimeField('修改时间', auto_now=True)
class Meta:
verbose_name = '文章'
verbose_name_plural = '文章'
def __str__(self):
return self.title
# Banner
class Banner(models.Model):
text_info = models.CharField('标题', max_length=50, default='')
img = models.ImageField('轮播图', upload_to='banner/')
link_url = models.URLField('图片链接', max_length=100)
is_active = models.BooleanField('是否是active', default=False)
def __str__(self):
return self.text_info
class Meta:
verbose_name = '轮播图'
verbose_name_plural = '轮播图'
# 友情链接
class Link(models.Model):
name = models.CharField('链接名称', max_length=20)
linkurl = models.URLField('网址', max_length=100)
def __str__(self):
return self.name
class Meta:
verbose_name = '友情链接'
verbose_name_plural = '友情链接'
这里面我们多增加了一个img图片封面字段,用于上传文章封面图片的,article_img/为上传目录,%Y/%m/%d/为自动在上传的图片上加上文件上传的时间。
在迁移之前,我们先需要设置数据库,如果我们使用默认的数据库的话,就不需要设置,Django默认使用
sqlite3数据库,如果我们想使用Mysql数据库的话,则需要我们单独配置。我们打开settings.py文件,找到DATABASES,然后把它修改成如下代码:
#修改成mysql如下:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'test', #你的数据库名称
'USER': 'root', #你的数据库用户名
'PASSWORD': '445813', #你的数据库密码
'HOST': '', #你的数据库主机,留空默认为localhost
'PORT': '3306', #你的数据库端口
}}
#由于mysql默认引擎为MySQLdb,在myblog下的__init__.py文件中添加下面代码
import pymysql
pymysql.version_info = (1, 4, 6, 'final', 0) # change mysqlclient version,because python version is 3.7 and pymysql version is 0.93
pymysql.install_as_MySQLdb()
#如果找不到pymysql板块,则通过pip install pymysql进行安装。
3、数据库设置好之后,我们就依次输入下面的命令进行数据库迁移:
python manage.py makemigrations
python manage.py migrate
迁移的时候,会有如下提示:
出现这个原因是因为我们的幻灯图使用到图片字段,我们需要引入图片处理包。提示里也给了我们处理方案,输入如下命令,安装Pillow模块即可:
pip install Pillow
安装成功之后再迁移数据库
数据库迁移成功之后,程序会在blog下的migrations目录里自动生成几个000开头的文件,文件里面记录着数据库迁移记录
二、用Admin管理后台管理数据
点击Pycharm右上角的Database,然后在网站项目里选中我们的数据库文件db.sqlite3,把它拖到Database框里。
但是没有数据。刷新会报错。
Pycharm Batabase限制非常大,下面我们介绍如何使用Django自带的admin管理网站数据。django的admin后台管理它可以让我们快速便捷管理数据,我们可以在各个app目录下的admin.py文件中对其进行控制。
想要对APP应用进行管理,最基本的前提是要先在settings里对其进行注册,就是在INSTALLED_APPS里把APP名添加进去,我们在前面的文章有提到过。
注册APP应用之后,我们想要在admin后台里对数据库表进行操作,我们还得在应用APP下的admin.py文件里对数据库表先进行注册。我们的APP应用是blog,所以我们需要在blog/admin.py文件里进行注册:
from django.contrib import admin
# Register your models here.
from .models import Banner, Category, Tag, Tui, Article, Link
#导入需要管理的数据库表
@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
list_display = ('id', 'category', 'title', 'tui', 'user', 'views', 'created_time')
# 文章列表里显示想要显示的字段
list_per_page = 50
# 满50条数据就自动分页
ordering = ('created_time',)
#后台数据列表排序方式
list_display_links = ('id', 'title')
# 设置哪些字段可以点击进入编辑界面
@admin.register(Banner)
class BannerAdmin(admin.ModelAdmin):
list_display = ('id', 'text_info', 'img', 'link_url', 'is_active')
@admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
list_display = ('id', 'name', 'index')
@admin.register(Tag)
class TagAdmin(admin.ModelAdmin):
list_display = ('id', 'name')
@admin.register(Tui)
class TuiAdmin(admin.ModelAdmin):
list_display = ('id', 'name')
@admin.register(Link)
class LinkAdmin(admin.ModelAdmin):
list_display = ('id', 'name','linkurl')
登录管理后台http://127.0.0.1:8000/admin/
注册后的后台:
多出了之前我们在models里创建的表。我们可以在后台里面对这些表进行增、删、改方面的操作。
三、使用富文本编辑器添加数据
在Django admin后台添加数据的时候,文章内容文本框想发布一篇图文并茂的文章需就得手写Html代码,这十分吃力,也没法上传图片和文件。
- 首先我们先下载DjangoUeditor包。点击下面的链接进行下载!下载完成然后解压到项目根目录里。
DjangoUeditor.zip - settings.py里注册APP,在INSTALLED_APPS里添加’DjangoUeditor,’。
#myblog/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'blog.apps.BlogConfig',
'DjangoUeditor', #注册富文本编辑器APP应用
]
- myblog/urls.py里添加url。
#myblog/urls.py
from django.urls import path, include
#留意上面这行比原来多了一个include
urlpatterns = [
path('admin/', admin.site.urls),
path('ueditor/', include('DjangoUeditor.urls')), #添加DjangoUeditor的URL
]
- 修改blog/models.py里需要使用富文本编辑器渲染的字段。这里面我们要修改的是Article表里的body字段。
把原来的:blog/models.py
body = models.TextField()
修改成:blog/models.py
from DjangoUeditor.models import UEditorField #头部增加这行代码导入UEditorField
body = UEditorField('内容', width=800, height=500,
toolbars="full", imagePath="upimg/", filePath="upfile/",
upload_settings={"imageMaxSize": 1204000},
settings={}, command=None, blank=True
)
留意里面的imagePath=“upimg/”, filePath=“upfile/” 这两个是图片和文件上传的路径,我们上传文件,会自动上传到项目根目录media文件夹下对应的upimg和upfile目录里,这个目录名可以自行定义。有的人问,为什么会上传到media目录里去呢?那是因为之前我们在基础配置文章里,设置了上传文件目录media。
上面步骤完成后,我们启动项目,进入文章发布页面。提示出错:
render() got an unexpected keyword argument 'renderer'
错误图片如下:
错误页面上有提示,出错的地方是下面文件的96行。打开这个文件的93行,注释这行即可。
修改成之后,重新刷新页面,就可以看到我们的富文本编辑器正常显示。
留意,如果我们在富文本编辑器里,上传图片,在编辑器内容里不显示上传的图片。那我们还需要进行如下设置,打开myblog/urls.py文件,在里面输入如下代码:
#myblog/urls.py
....
from django.urls import path, include, re_path
#上面这行多加了一个re_path
from django.views.static import serve
#导入静态文件模块
from django.conf import settings
#导入配置文件里的文件上传配置
urlpatterns = [
path('admin/', admin.site.urls),
....
re_path('^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}),#增加此行
]
设置好了之后,图片就会正常显示。这样我们就可以用DjangoUeditor富文本编辑器发布图文并茂的文章了。
四、URL与视图函数
1.请求响应过程
请求响应过程:
浏览器->发送HTTP请求到——服务器——处理请求->返回HTTP响应——HTML->浏览器
2.Pycharm中的Django项目URL映射
1.app的url映射默认为下图:
规则说明:
urlpatterns = [
path(正则表达式, views视图函数,参数,别名),
]
括号里的参数说明:
1、一个正则表达式字符串
2、一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串
3、可选的要传递给视图函数的默认参数(字典形式)
4、一个可选的name参数(别名)
每个URL都对应一个views视图函数名,视图函数名不能相同,否则会报错。视图函数,Django中约定写在APP应用里的views.py文件里。然后在urls.py文件里通过下面的方式导入:
from APP应用名 import views
from APP应用名.vews import 函数名或类名
视图函数是一个简单的Python 函数,它接受Web请求并且返回Web响应。响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片. . . 是任何东西都可以。无论视图本身包含什么逻辑,都要返回响应。这个视图函数代码一般约定是放置在项目或应用程序目录中的views.py的文件中。
http请求中产生两个核心对象:
1、http请求---->HttpRequest对象,用户请求相关的所有信息(对象)
2、http响应---->HttpResponse对象,响应字符串
3.简单测试
打开打开bolg目录下的views.py文件,写一个hello视图函数,在里面输入:
from django.http import HttpResponse
def hello(request):
"""
写一个hello函数,通过request接收URL或者说是http请求信息,
然后给这个请求返回一个HttpResponse对象
"""
return HttpResponse('欢迎使用Django!')
request,就是HttpRequest对象。HttpResponse(“欢迎使用Django!”),就是HttpRequest对象,它向http请求响应了一段字符串对象。
我们打开myblog目录下的urls.py文件中先导入视图函数,然后构造一个URL,代码如下:
from blog import views #导入视图函数
urlpatterns = [
...
path('', views.hello), #这个是我们构造的URL
]
代码写完之后,启动项目就可以在浏览器里看到视图函数返回的字符串"欢迎使用Django!"
4.Django请求生命周期
通过URL对应关系匹配 ->找到对应的函数(或者类)->返回字符串(或者读取Html之后返回渲染的字符串)这个过程也就是我们Django请求的生命周期。
视图函数,就是围绕着HttpRequest和HttpResponse这两个对象进行的。
五、django模板
1.概念
视图会返回一个响应,响应可以是一个HTML内容的网页。我们把这样的页面按规范写好,然后都放在项目根目录下的templates文件夹里,这样的页面,我们称之为"模板"页面。
模板页面包含一些基础的HTML代码和一些特殊的语法,这些特殊的语法主要用于如何将数据动态的插入HTML页面中。
这些特殊的语法我们把它做变量、标签。变量是模板中最基本的组成单位。这些模板变量由视图函数生成的,然后通过上下文传递到模板里,然后由浏览器渲染出来。
2.变量
-
在文件myblog/urls.py里设置一个URL:
#myblog/urls.py
urlpatterns = [
…
path(’’, views.index), #’'留空,表示为首页
…
] -
在文件blog/views.py里添加一个视图函数:
blog/vews.py
#添加一个函数
def index(request):
#添加两个变量,并给它们赋值
sitename = ‘小小百度’
url = ‘www.baidu.com’
#把两个变量封装到上下文里
context = {
‘sitename’: sitename,
‘url’:url,
}
#把上下文传递到模板里
return render(request,‘index.html’,context) -
在项目根目录下templates文件夹里新建一个文件index.html,输入如下内容:
#templates/index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>MyBlog</title> </head> <body> <h3>网站名:{{ sitename }}</h3> <h3>域名:{{ url }}</h3> </body> </html>
-
Terminal窗口输入运行
python manage.py runserver
2.列表+字典显示
-
在视图函数里添加如下代码:
from django.shortcuts import render # Create your views here. #添加一个函数 def index(request): #添加两个变量,并给它们赋值 sitename = '小小百度' url = 'www.baidu.com' # 新加一个列表 myList = [ '鲁菜', '川菜', '粤菜', '苏菜', '浙菜', '闽菜', '湘菜', '徽菜', ] # 在上面基础上新加一个字典 mydict = { 'name': '企鹅', 'qq': '111111111', 'wx': '111111111', 'email': '573690349@qq.com', 'Q群': '11111111', } #把四个变量封装到上下文里 context = { 'sitename': sitename, 'url':url, 'myList': myList, # 把myList封装到context 'mydict': mydict, # 把mydict封装到context } #把上下文传递到模板里 return render(request,'index.html',context)
-
在项目根目录下templates文件夹里文件index.html,输入如下内容:
<!DOCTYPE html> <!--myblog/templates/index.html--> <html lang="en"> <head> <meta charset="UTF-8"> <title>MyBlog</title> </head> <body> <h3>网站名:{{ sitename }}</h3> <h3>域名:{{ url }}</h3> {#新下面的代码#} <div> <ul> <h4>八大菜系:</h4> {% for item in myList %} <li>{{ item }}</li> {% endfor %} </ul> </div> <!-- 新加如下代码 --> <div> <ul> <h4>Blog教程作者信息:</h4> {% for key,values in mydict.items %} <li>{{ key }}:{{ values }}</li> {% endfor %} </ul> </div> </body> </html>
-
Terminal窗口输入运行
python manage.py runserver
六.数据查询
-
从models.py里导入模型Product(也就是类名,或者说表名):
#blog/views.py #比如我信要查询所有文章,我们就要views.py文件头部把文章表从数据模型导入 from .models import Article
-
在视图函数里对要查询的Product进行声明并实例化,然后生成对象allarticle。
#blog/views.py def index(request): #对Article进行声明并实例化,然后生成对象allarticle allarticle = Article.objects.all() #把查询到的对象,封装到上下文 context = { 'allarticle': allarticle, } #把上传文传到模板页面index.html里 return render(request,'index.html',context) 注:这里我在原来的基础上,把index视图函数里的内容删除了,修改成上面的内容,下面的模板页面index.html也是如此。
-
打开templates/index.html页面,修改成下面的内容:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>MyBlog</title> </head> <body> <div> <ul> <h4>所有文章:</h4> {% for article in allarticle %} <li>{{ article.title }}</li> {% endfor %} </ul> </div> </div> </body> </html>
然后访问网站首页。就能看到我们的查询结果。
在模板里,我们可以对对象的属性进行赋值。比如模板里的{{ article.title }} 标题,就是我们通过{{ 对象.属性(字段) }}获取到对应的值。其它字段也是通过这样的方法来实现。
例如:
<!DOCTYPE html>
<!--myblog/templates/index.html-->
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MyBlog</title>
</head>
<body>
<h3>网站名:{{ sitename }}</h3>
<h3>域名:{{ url }}</h3>
{#新下面的代码#}
<div>
<ul>
<h4>八大菜系:</h4>
{% for item in myList %}
<li>{{ item }}</li>
{% endfor %}
</ul>
</div>
<!-- 新加如下代码 -->
<div>
<ul>
<h4>个人信息:</h4>
{% for key,values in mydict.items %}
<li>{{ key }}:{{ values }}</li>
{% endfor %}
</ul>
</div>
<div>
<ul>
<h4>所有文章:</h4>
{% for article in allarticle %}
<li>
标题:{{ article.title }}<br />
栏目:{{ article.category }}<br />
作者:{{ article.user }}<br />
时间:{{ article.created_time }}<br />
</li>
{% endfor %}
</ul>
</div>
</body>
</html>
从之前的文章我们可以看到,如果我们想要将数据库的数据展现到网页上,需要由视图、模型与模板共同实现,步骤如下:
-
在models.py里定义数据模型,以类的方式定义数据表的字段。在数据库创建数据表时,数据表由模型定义的类生成。
-
在视图views.py导入模型所定义的类,我们把这个类称之为数据表对象,然后在视图函数里使用Django的数据库操作方法,实现数据库操作,从而获取到数据表里的数据。
-
视图函数获取到数据之后,将数据以字典、列表或对象(上下文context)的方式传递给HTML模板,并由模板引擎接收和解析,最后生成相应的HTML网页,在浏览器里展现出来。