Django开发简易的博客系统

博客系统主要有以下几大功能点
用户注册和登录
博主资料信息
图片墙功能
留言板功能
文章列表
文章正文内容
Admin后台管理系统

下面按照开发的逻辑从架构设计,功能配置,数据库架构设计,路由列表定义,共同模板编写等大的模块写一下开发的流程

1.总体配置

1.1项目架构设计

项目应用account实现用户注册登录和用户资料信息页
项目应用album实现图片墙功能
项目应用article实现用户的文章管理
项目应用interflow实现博客留言板的功能
媒体资源文件夹media存放用户的图片,头像等资源文件
静态资源文件夹publicStatic存放网页的CSS/JS文件和网页图片
模板文件夹templates存放模板文件
新建myadmin和myapps用于自定义admin后台系统

1.2功能配置

1.2.1 将项目应用配置到INSTALLED_APPS中,并且在MIDDLEWARE中添加LocaleMiddleware中间件
INSTALLED_APPS = [
    # 'django.contrib.admin',
    'myblog.myapps.MyAdminConfig',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'article',
    'album',
    'account',
    'interflow',
    #添加Django CKEditor
    'ckeditor',
    'ckeditor_uploader'
]
 #添加中间件LocaleMiddleware
    'django.middleware.locale.LocaleMiddleware',
1.2.2 配置TEMPLATES中设置模板文件夹 templates
TEMPLATES = [
   {
       'BACKEND': 'django.template.backends.django.DjangoTemplates',
       #将模板文件夹templates引入django
       'DIRS': [os.path.join(BASE_DIR,'templates'),],
       'APP_DIRS': True,
       'OPTIONS': {
           'context_processors': [
               'django.template.context_processors.debug',
               'django.template.context_processors.request',
               'django.contrib.auth.context_processors.auth',
               'django.contrib.messages.context_processors.messages',
           ],
       },
   },
]
1.2.3 配置数据库
DATABASES = {
  'default': {
      'ENGINE': 'django.db.backends.mysql',
      'NAME': 'blogdb',
      'USER':'root',
      'PASSWORD':'123456',
      'HOST':'127.0.0.1',
      'PORT':'3306',
  },
}
1.2.4 配置静态资源和媒体资源文件夹
#配置自定义用户模型MyUser
AUTH_USER_MODEL = 'account.MyUser'

STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR,'publicStatic')]

#设置媒体资源的保存路径
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR,'media')

# 编辑器的配置信息
CKEDITOR_UPLOAD_PATH = "article_images"
CKEDITOR_CONFIGS = {
    'default': {
        'toolbar': 'Full'
    }
}
CKEDITOR_ALLOW_NONIMAGE_FILES = False
CKEDITOR_BROWSE_SHOW_DIRS = True

1.3 数据表架构设计

从项目的架构设计得知,account的模型MyUser是项目的核心数据,他与每个项目应用的模型都存在数据关联。此处不展示所有的数据表设计过程,仅以account的models.py为例,其他数据表基本一致

from django.db import models
from django.contrib.auth.models import AbstractUser

class MyUser(AbstractUser):
    name = models.CharField('姓名',max_length=50,default='匿名用户')
    introduce = models.TextField('简介',default='暂无介绍')
    company = models.CharField('公司',max_length=100,default='暂无信息')
    profession = models.CharField('职业',max_length=100,default='暂无信息')
    address = models.CharField('住址',max_length=100,default='暂无信息')
    telephone = models.CharField('电话',max_length=11,default='暂无信息')
    wx = models.CharField('微信',max_length=50,default='暂无信息')
    qq = models.CharField('QQ',max_length=50,default='暂无信息')
    wb = models.CharField('微博', max_length=100, default='暂无信息')
    photo = models.ImageField('头像',blank=True,upload_to='image/user/')

    #设置返回值
    def __str__(self):
        return self.name

1.4 定义路由列表

from django.contrib import admin
from django.urls import path, include, re_path
from django.views.static import serve
from django.conf import settings

urlpatterns = [
    path('admin/', admin.site.urls),
    path('user/', include('account.urls')),
    path('', include('article.urls')),
    path('album/', include('album.urls')),
    path('board/', include('interflow.urls')),
    re_path('media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT}, name='media'),
    # 设置编辑器的路由信息
    path('ckeditor/', include('ckeditor_uploader.urls')),
]

1.5 编写公用模板

从项目设计得知,博主资料信息展示,图片墙功能,留言板功能和文章列表,文章正文内容的页面布局存在相同之处,因此可以将这些网页功能编写在公用的模板文件中,这里的模板文件不做展示

2.注册与登录

url.py配置

from django.urls import path
from .views import *

urlpatterns = [
    # 用户注册
    path('register.html', register, name='register'),
    # 用户登录
    path('login.html', userLogin, name='userLogin'),
    # 关于我
    path('about/<int:id>.html', about, name='about'),
]

views.py配置

from django.shortcuts import render, redirect
from .models import MyUser
from django.contrib.auth import login
from django.contrib.auth import logout
from django.contrib.auth import authenticate
from django.urls import reverse
from album.models import AlbumInfo
from article.models import ArticleTag

def register(request):
    title = '注册博客'
    pageTitle = '用户注册'
    confirmPassword = True
    button = '注册'
    urlText = '用户登录'
    urlName = 'userLogin'
    if request.method == 'POST':
        u = request.POST.get('username', '')
        p = request.POST.get('password', '')
        cp = request.POST.get('cp', '')
        if MyUser.objects.filter(username=u):
            tips = '用户已存在'
        elif cp != p:
            tips = '两次密码输入不一致'
        else:
            d = {
                'username': u, 'password': p,
                'is_superuser': 1, 'is_staff': 1
            }
            user = MyUser.objects.create_user(**d)
            user.save()
            tips = '注册成功,请登录'
            logout(request)
            return redirect(reverse('userLogin'))
    return render(request, 'user.html', locals())

def userLogin(request):
    title = '登录博客'
    pageTitle = '用户登录'
    button = '登录'
    urlText = '用户注册'
    urlName = 'register'
    if request.method == 'POST':
        u = request.POST.get('username', '')
        p = request.POST.get('password', '')
        if MyUser.objects.filter(username=u):
            user = authenticate(username=u, password=p)
            if user:
                if user.is_active:
                    login(request, user)
                kwargs = {'id': request.user.id, 'page': 1}
                return redirect(reverse('article', kwargs=kwargs))
            else:
                tips = '账号密码错误,请重新输入'
        else:
            tips = '用户不存在,请注册'
    else:
        if request.user.username:
            kwargs = {'id': request.user.id, 'page': 1}
            return redirect(reverse('article', kwargs=kwargs))
    return render(request, 'user.html', locals())


def about(request, id):
    album = AlbumInfo.objects.filter(user_id=id)
    tag = ArticleTag.objects.filter(user_id=id)
    user = MyUser.objects.filter(id=id).first()
    return render(request, 'about.html', locals())

模板文件省略

3.图片墙功能

url.py配置

from django.urls import path
from .views import *
urlpatterns = [
    # 图片墙
    path('<int:id>/<int:page>.html', album, name='album'),
]

views.py配置

from django.shortcuts import render
from django.core.paginator import Paginator
from django.core.paginator import PageNotAnInteger
from django.core.paginator import EmptyPage
from .models import AlbumInfo


def album(request, id, page):
    albumList = AlbumInfo.objects.filter(user_id=id).order_by('id')
    paginator = Paginator(albumList, 8)
    try:
        pageInfo = paginator.page(page)
    except PageNotAnInteger:
        # 如果参数page 的数据类型不是整型,就返回第一页数据
        pageInfo = paginator.page(1)
    except EmptyPage:
        # 若用户访问的页数大于实际页数,则返回最后一页的数据
        pageInfo = paginator.page(paginator.num_pages)
    return render(request, 'album.html', locals())

模板文件省略

4.留言板功能

url.py的配置

from django.urls import path
from .views import *
urlpatterns = [
    # 留言板
    path('<int:id>/<int:page>.html', board, name='board'),
]

views.py的配置

from django.shortcuts import render, redirect
from django.core.paginator import Paginator
from django.core.paginator import PageNotAnInteger
from django.core.paginator import EmptyPage
from article.models import ArticleTag
from account.models import MyUser
from album.models import AlbumInfo
from .models import Board
from django.urls import reverse


def board(request, id, page):
    album = AlbumInfo.objects.filter(user_id=id)
    tag = ArticleTag.objects.filter(user_id=id)
    user = MyUser.objects.filter(id=id).first()
    if not user:
        return redirect(reverse('register'))
    if request.method == 'GET':
        boardList = Board.objects.filter(user_id=id).order_by('-created')
        paginator = Paginator(boardList, 10)
        try:
            pageInfo = paginator.page(page)
        except PageNotAnInteger:
            # 如果参数page 的数据类型不是整型,就返回第一页数据
            pageInfo = paginator.page(1)
        except EmptyPage:
            # 若用户访问的页数大于实际页数,则返回最后一页的数据
            pageInfo = paginator.page(paginator.num_pages)
        return render(request, 'board.html', locals())
    else:
        name = request.POST.get('name')
        email = request.POST.get('email')
        content = request.POST.get('content')
        value = {'name': name, 'email': email,
                 'content': content, 'user_id': id}
        Board.objects.create(**value)
        kwargs = {'id': id, 'page': 1}
        return redirect(reverse('board', kwargs=kwargs))

模板文件省略

5.文章列表与正文

url.py的配置

from django.urls import path
from django.views.generic import RedirectView
from .views import *

urlpatterns = [
    # 首页地址自动跳转用户登录页面
    path('', RedirectView.as_view(url='user/login.html')),
    # 文章列表
    path('<int:id>/<int:page>.html', article, name='article'),
    # 文章正文内容
    path('detail/<int:id>/<int:aId>.html', detail, name='detail')
]

views.py的配置

from django.shortcuts import render, redirect
from account.models import MyUser
from album.models import AlbumInfo
from django.core.paginator import Paginator
from django.core.paginator import PageNotAnInteger
from django.core.paginator import EmptyPage
from .models import ArticleInfo, ArticleTag, Comment
from django.db.models import F
from django.urls import reverse


def article(request, id, page):
    album = AlbumInfo.objects.filter(user_id=id)
    tag = ArticleTag.objects.filter(user_id=id)
    user = MyUser.objects.filter(id=id).first()
    if not user:
        return redirect(reverse('register'))
    ats = ArticleInfo.objects.filter(author_id=id).order_by('-created')
    paginator = Paginator(ats, 10)
    try:
        pageInfo = paginator.page(page)
    except PageNotAnInteger:
        # 如果参数page 的数据类型不是整型,就返回第一页数据
        pageInfo = paginator.page(1)
    except EmptyPage:
        # 若用户访问的页数大于实际页数,则返回最后一页的数据
        pageInfo = paginator.page(paginator.num_pages)
    return render(request, 'article.html', locals())


def detail(request, id, aId):
    album = AlbumInfo.objects.filter(user_id=id)
    tag = ArticleTag.objects.filter(user_id=id)
    user = MyUser.objects.filter(id=id).first()
    if request.method == 'GET':
        ats = ArticleInfo.objects.filter(id=aId).first()
        atags = ArticleInfo.objects.get(id=aId).article_tag.all()
        cms = Comment.objects.filter(article_id=aId).order_by('-created')
        # 添加阅读量
        if not request.session.get('reading' + str(id) + str(aId), ''):
            reading = ArticleInfo.objects.filter(id=aId)
            reading.update(reading=F('reading') + 1)
            request.session['reading' + str(id) + str(aId)] = True
        return render(request, 'detail.html', locals())
    else:
        commentator = request.POST.get('name')
        email = request.POST.get('email')
        content = request.POST.get('content')
        value = {'commentator': commentator,
                 'content': content, 'article_id': aId}
        Comment.objects.create(**value)
        kwargs = {'id': id, 'aId': aId}
        return redirect(reverse('detail', kwargs=kwargs))

模板文件省略

6.后台系统与富文本编辑器

我们在每个项目应用的admin.py中定义每个模型的ModelAdmin

from django.contrib import admin
from .models import MyUser
from django.contrib.auth.admin import UserAdmin
from django.utils.translation import gettext_lazy as _


@admin.register(MyUser)
class MyUserAdmin(UserAdmin):
    list_display = ['username', 'email',
                    'name', 'introduce',
                    'company', 'profession',
                    'address', 'telephone',
                    'wx', 'qq', 'wb', 'photo']
    fieldsets = list(UserAdmin.fieldsets)
    fieldsets[1] = (_('Personal info'),
                    {'fields': ('name', 'introduce',
                                'email', 'company',
                                'profession', 'address',
                                'telephone', 'wx',
                                'qq', 'wb', 'photo')})

    def get_queryset(self, request):
        qs = super(MyUserAdmin, self).get_queryset(request)
        return qs.filter(id=request.user.id)

下一步在每个项目应用的初始化文件__init__.py中设置项目应用名称,项目应用名称将显示在Admin后台系统的首页,每个项目应用的代码如下:

from django.apps import AppConfig
import os
# 修改app在admin后台显示名称
# default_app_config的值来自apps.py的类名
default_app_config = 'account.IndexConfig'

# 获取当前app的命名
def get_current_app_name(_file):
    return os.path.split(os.path.dirname(_file))[-1]

# 重写类IndexConfig
class IndexConfig(AppConfig):
    name = get_current_app_name(__file__)
    verbose_name = '用户管理'

自定义登录界面使后台登录和博客登录变为一个界面,然后添加Django CKEditor文章编辑器并且配置,这段代码略去

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值