文章目录
创建项目
创建文件夹myblog,然后在命令行创建应用
python manage.py startapp blog
基础设置
settings.py文件设置
- 设置域名访问权限
myblog/settings.py
ALLOWED_HOSTS = [] #修改前
ALLOWED_HOSTS = ['*'] #修改后,表示任何域名都能访问。如果指定域名的话,在''里放入指定的域名即可
- 设置templates里的’
DIRS
’,添加模板目录templates的路径
myblog/settings.py
#修改前
'DIRS': []
#修改后
'DIRS': [os.path.join(BASE_DIR, 'templates')]
- 找到DATABASES设置网站数据库类型,这里我们使用默认的sqlite3
- 在INSTALLED_APPS添加APP应用名称。
myblog/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
....
'blog.apps.BlogConfig',#注册APP应用
]
- 修改项目语言和时区
myblog/settings.py
#修改前为英文
LANGUAGE_CODE = 'en-us'
#修改后
LANGUAGE_CODE = 'zh-hans' #语言修改为中文
#时区,修改前
TIME_ZONE = 'UTC'
#修改后
TIME_ZONE = 'Asia/Shanghai'
- 在项目根目录里创建
static
和media
,两个目录。static用来存放模板CSS、JS、图片等静态资源,media用来存放上传的文件
settings里找到STATIC_URL,然后在后面一行加上如下代码。
myblog/settings.py
#设置静态文件目录和名称
STATIC_URL = '/static/'
#加入下面代码
#这个是设置静态文件夹目录的路径
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static'),
)
#设置文件上传路径,图片上传、文件上传都会存放在此目录里
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
欢迎页面
- 数据库迁移
python manage.py makemigrations
python manage.py migrate
- 创建管理员账号和密码
python manage.py createsuperuser
- 启动django项目
python manage.py runserver #默认使用8000端口
python manage.py runserver 8080 #指定启动端口
python manage.py runserver 127.0.0.1:9000 #指定IP和端口
提示启动成功,然后我们在浏览器里输入:http://127.0.0.1:8000/
就可以查看到Django默认的欢迎页面!
创建数据库模型
django根据代码中定义的类来自动生成数据库表。我们写的类表示数据库的表,如果根据这个类创建的对象是数据库表里的一行数据,对象.id 对象.value是每一行里的数据。
基本的原则如下:
- 每个模型在Django中的存在形式为一个Python类
- 每个模型都是django.db.models.Model的子类
- 模型里的每个类代表数据库中的一个表
- 模型的每个字段(属性)代表数据表的某一列
- Django将自动为你生成数据库访问API
分类表结构设计:
表名:Category、分类名:name
标签表设计:
表名:Tag、标签名:name
文章表结构设计:
表名:Article、标题:title、摘要:excerpt、分类:category、标签:tags、推荐位、内容:body、创建时间:created_time、作者:user、文章封面图片img
幻灯图表结构设计:
表名:Banner、图片文本text_info、图片img、图片链接link_url、图片状态is_active。
推荐位表结构设计:
表名:Tui、推荐位名name。
友情链接表结构设计:
表名:Link、链接名name、链接网址linkurl。
其中文章和分类是一对多的关系,文章和标签是多对多的关系,文章和作者是一对多的关系,文章和推荐位是一对多关系(看自己的需求,也可以设计成多对多)。
#blog/models.py
from tabnanny import verbose
from venv import create
from click import command
from django.conf import settings
from django.db import models
# Create your models here.
from django.contrib.auth.models import User
import DjangoUeditor
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
from DjangoUeditor.models import UEditorField
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()
body = UEditorField('内容',width = 800, height=500,toolbars='full',
imagePath="upimg/",filePath="upfile/",
settings={},command=None,blank=True)
user = models.ForeignKey(User,on_delete=models.CASCADE,verbose_name='作者')
views = models.PositiveIntegerField('阅读量',default=0)
tui = models.ForeignKey(Tui,on_delete=models.DO_NOTHING,verbose_name='推荐位',blank=True,null=True)
create_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 = '友情链接'
用Admin管理后台管理数据
注册APP应用之后,我们想要在admin后台里对数据库表进行操作,需要在应用APP下的admin.py
文件里对数据库表先进行注册。在blog/admin.py
中注册。
#blog/admin.py
from csv import list_dialects
from unicodedata import category
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','create_time')
list_per_page = 50
ordering = ('create_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/
使用富文本编辑器添加数据
为提升效率,我们可以使用富文本编辑器添加数据。
- 首先我们先下载DjangoUeditor包。点击下面的链接进行下载!下载完成然后解压到项目根目录里。
- settings.py里注册APP,在INSTALLED_APPS里添加’
DjangoUeditor
’,。
myblog/settings.y
INSTALLED_APPS = [
'django.contrib.admin',
....
'DjangoUeditor', #注册APP应用
]
myblog/urls.py
里添加url。
#myblog/urls.py
from django.urls import path, include
#留意上面这行比原来多了一个include
urlpatterns = [
path('admin/', admin.site.urls),
path('', views.hello),
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
)
上面步骤完成后,我们启动项目,进入文章发布页面。提示出错:
render() got an unexpected keyword argument 'renderer'
错误提示:
F:\course\myblog\myblogvenv\lib\site-packages\django\forms\boundfield.py in as_widget, line 93
打开这个文件的93行,注释这行即可。
修改完成之后,重新刷新页面。
URL与视图函数
一些常用的模板使用方法
- django static文件的引入方式
- 在django project中创建 static文件夹
settings.py
中配置要在STATIC_URL = /static/
下边
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static'),
]
- 前端引入
#在页面顶部:
{% load static %} #django3 用这个语法
#引入CSS、JS
{% static 'xxx.css' %}
{% static 'xxx.js' %}
- 模板(template)包含、继承与
{% block %}
的用法
使用模板前,先设置TEMPLATES里的’DIRS’,添加模板目录templates的路径,这样Django才能自动找到模板页面
#修改前
'DIRS': []
#修改后
'DIRS': [os.path.join(BASE_DIR, 'templates')]
- 模板包含
如果网站所有页面的头部和尾部都一样,只有中间的部分不一样。这时我们就可以把这个页面分为三个部分,每个部分分别存放在页面head.html、index.html、footer.html
中,其中,头部head.html用来放所有页面头部相同的代码、主体部分index.html放与其它页面不相同的代码、尾部head.html放与其它页面尾部相同的代码。
templates/index.html
{% include 'head.html' %}
<div>中部</div>
{% include 'footer.html' %}
- 模板继承
把所有页面相同的代码单独提取出来放在 base.html页面里,然后在代码不同的位置,也就是主体那里用模板标签{% block content %} {% endblock %}
替换。
templates/index.html
{% extends "base.html" %}
{% block content %}
<div>中部</div>
{% endblock %}
这里面的{% extends "base.html" %}
的意思是继承 base.html页面的代码,需要留意的是,使用继承方法的话,这个代码一定要放页面的第一行。
实现模板之前的分析与准备
因为我们要实现6个页面的展现,网站首页、文章分类列表页、搜索列表页、标签列表页、文章内容展示页、单页面(联系我们)。所以我们需要在urls.py里,给每个页面都设置一个URL,并给每个URL添加一个别名:
myblog/urls.py
from blog import views
#导入blogAPP下的views
urlpatterns = [
path('admin/', admin.site.urls),#管理后台
path('', views.index, name='index'),#网站首页
path('list-<int:lid>.html', views.list, name='list'),#列表页
path('show-<int:sid>.html', views.show, name='show'),#内容页
path('tag/<tag>', views.tag, name='tags'),#标签列表页
path('s/', views.search, name='search'),#搜索列表页
path('about/', views.about, name='about'),#联系我们单页
path('ueditor/', include('DjangoUeditor.urls')),
re_path('^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}),
]
实现网站首页
我们只需要在首页视图函数里,查询出所有的文章分类名称,然后在模板页面上展示就行。
#blog/views.py
from .models import Category
#从models里导入Category类
def index(request):
allcategory = Category.objects.all()#通过Category表查出所有分类
#把查询出来的分类封装到上下文里
context = {
'allcategory': allcategory,
}
return render(request, 'index.html', context)#把上下文传到index.html页面
#templates/base.html
<nav class="nav fl">
<ul id="fix-list" class="fix-list clearfix">
<li id="menu-item-117720" class="menu-item"><a href="/">首页</a></li>
{% for category in allcategory %}
<li id="menu-item-117720" class="menu-item">
<a href="{% url 'index' %}list-{{ category.id }}.html">{{ category.name }}</a>
</li>
{% endfor %}
<li id="menu-item-117720" class="menu-item"><a href="/about/">关于博主</a></li>
</ul>
</nav>
- 首页幻灯图的实现
首先要先添加一些数据。然后在首页视图函数里查询出所有的幻灯图的数据
#blog/views.py
from blog.models import Category, Banner
#把Banner表导入
def index(request):
allcategory = Category.objects.all()
banner = Banner.objects.filter(is_active=True)[0:4]#查询所有幻灯图数据,并进行切片
context = {
'allcategory': allcategory,
'banner':banner, #把查询到的幻灯图数据封装到上下文
}
return render(request, 'index.html', context)
- 首页推荐阅读实现
我们在发布文章的时候,要先在推荐位里选择好要推荐的文章,然后再进行查询展现。
#blog/views.py
from blog.models import Category,Banner, Article
#我们查询的是进行推荐的文章,所以要导入文章Article表
def index(request):
....
tui = Article.objects.filter(tui__id=1)[:3]#查询推荐位ID为1的文章
context = {
...
'tui':tui,
}
return render(request, 'index.html', context)
- 首页最新文章实现
首页最新文章,调用的是所有分类里的最新文章,这里只调用10篇
#blog/views.py
def index(request):
...
allarticle = Article.objects.all().order_by('-id')[0:10]
context = {
...
'allarticle': allarticle,
}
return render(request, 'index.html', context)
- 热门文章排行实现
热门文章的实现有多种方式,如果你想要在上面展示自己指定的文章,你可以在后台通过再添加一个推荐位来实现,也可以查询所有文章,通过文章浏览数进行倒序展示,也可以查询数据库通过随机的方式展示。
#blog/views.py
def index(request):
...
#hot = Article.objects.all().order_by('?')[:10]#随机推荐
#hot = Article.objects.filter(tui__id=3)[:10] #通过推荐进行查询,以推荐ID是3为例
hot = Article.objects.all().order_by('views')[:10]#通过浏览数进行排序
context = {
...
'hot':hot,
}
return render(request, 'index.html', context)
- 右侧热门推荐实现
打侧的热门推荐代码在right.html里,所以我们需要修改right.html页面,这个地方我们是通过后台的推荐位ID为2实现的。
#blog/views.py
def index(request):
...
remen = Article.objects.filter(tui__id=2)[:6]
context = {
...
'remen':remen,
}
return render(request, 'index.html', context)
- 右侧所有标签实现
#blog/views.py
from blog.models import Category,Banner, Article, Tag
#导入标签表
def index(request):
...
tags = Tag.objects.all()
context = {
...
'tags':tags,
}
return render(request, 'index.html', context)
- 尾部的友情链接实现
blog/views.py
from blog.models import Category,Banner, Article, Tag, Link
#导入友情链接表Link
def index(request):
...
link = Link.objects.all()
context = {
...
'link':link,
}
return render(request, 'index.html', context)
实现文章列表
blog/views.py
#文章列表
def list(request,lid):
list = Article.objects.filter(category_id=lid)#获取通过URL传进来的lid,然后筛选出对应文章
cname = Category.objects.get(id=lid)#获取当前文章的栏目名
remen = Article.objects.filter(tui__id=2)[:6]#右侧的热门推荐
allcategory = Category.objects.all()#导航所有分类
tags = Tag.objects.all()#右侧所有文章标签
return render(request, 'list.html', locals())
实现文章内容页
blog/views.py
def show(request,sid):
show = Article.objects.get(id=sid)#查询指定ID的文章
allcategory = Category.objects.all()#导航上的分类
tags = Tag.objects.all()#右侧所有标签
remen = Article.objects.filter(tui__id=2)[:6]#右侧热门推荐
hot = Article.objects.all().order_by('?')[:10]#内容下面的您可能感兴趣的文章,随机推荐
previous_blog = Article.objects.filter(created_time__gt=show.created_time,category=show.category.id).first()
netx_blog = Article.objects.filter(created_time__lt=show.created_time,category=show.category.id).last()
show.views = show.views + 1
show.save()
return render(request, 'show.html', locals())
实现标签页面
#blog/views.py
def tag(request, tag):
list = Article.objects.filter(tags__name=tag)#通过文章标签进行查询文章
remen = Article.objects.filter(tui__id=2)[:6]
allcategory = Category.objects.all()
tname = Tag.objects.get(name=tag)#获取当前搜索的标签名
page = request.GET.get('page')
tags = Tag.objects.all()
paginator = Paginator(list, 5)
try:
list = paginator.page(page) # 获取当前页码的记录
except PageNotAnInteger:
list = paginator.page(1) # 如果用户输入的页码不是整数时,显示第1页的内容
except EmptyPage:
list = paginator.page(paginator.num_pages) # 如果用户输入的页数不在系统的页码列表中时,显示最后一页的内容
return render(request, 'tags.html', locals())
实现搜索页面
def search(request):
ss=request.GET.get('search')#获取搜索的关键词
list = Article.objects.filter(title__icontains=ss)#获取到搜索关键词通过标题进行匹配
remen = Article.objects.filter(tui__id=2)[:6]
allcategory = Category.objects.all()
page = request.GET.get('page')
tags = Tag.objects.all()
paginator = Paginator(list, 10)
try:
list = paginator.page(page) # 获取当前页码的记录
except PageNotAnInteger:
list = paginator.page(1) # 如果用户输入的页码不是整数时,显示第1页的内容
except EmptyPage:
list = paginator.page(paginator.num_pages) # 如果用户输入的页数不在系统的页码列表中时,显示最后一页的内容
return render(request, 'search.html', locals())
单页面实现与代码优化
blog/views.py
# 关于我们
def about(request):
allcategory = Category.objects.all()
return render(request, 'page.html',locals())