django开发实战:搭建自己的博客

创建项目

创建文件夹myblog,然后在命令行创建应用

python manage.py startapp blog
基础设置
settings.py文件设置
  1. 设置域名访问权限
myblog/settings.py
ALLOWED_HOSTS = []      #修改前
ALLOWED_HOSTS = ['*']   #修改后,表示任何域名都能访问。如果指定域名的话,在''里放入指定的域名即可
  1. 设置templates里的’DIRS’,添加模板目录templates的路径
myblog/settings.py
#修改前
'DIRS': []
#修改后
'DIRS': [os.path.join(BASE_DIR, 'templates')]
  1. 找到DATABASES设置网站数据库类型,这里我们使用默认的sqlite3
  2. 在INSTALLED_APPS添加APP应用名称。
myblog/settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    ....
    'blog.apps.BlogConfig',#注册APP应用
]
  1. 修改项目语言和时区
myblog/settings.py
#修改前为英文
LANGUAGE_CODE = 'en-us'
#修改后
LANGUAGE_CODE = 'zh-hans' #语言修改为中文
#时区,修改前
TIME_ZONE = 'UTC'
#修改后
TIME_ZONE = 'Asia/Shanghai' 
  1. 在项目根目录里创建staticmedia,两个目录。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/
在这里插入图片描述

使用富文本编辑器添加数据

为提升效率,我们可以使用富文本编辑器添加数据。

  1. 首先我们先下载DjangoUeditor包。点击下面的链接进行下载!下载完成然后解压到项目根目录里。
  2. settings.py里注册APP,在INSTALLED_APPS里添加’DjangoUeditor’,。
myblog/settings.y
INSTALLED_APPS = [
    'django.contrib.admin',
    ....
    'DjangoUeditor', #注册APP应用
]
  1. 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
]
  1. 修改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文件的引入方式
  1. 在django project中创建 static文件夹
  2. settings.py中配置要在 STATIC_URL = /static/ 下边
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'static'), 
]
  1. 前端引入
#在页面顶部:
{% 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())

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cachel wood

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值