创建文章模块
创建文章app
在虚拟环境中,apps路径下使用如下代码:
# 进入虚拟环境
workon wsl
# 进入要创建app的路径下
cd blog/blog/apps
# 创建app
python ../../manage.py startapp articles
将articles注册进配置文件dev.py中的INSTALLED_APPS
INSTALLED_APPS = [...'articles',
]
创建数据模型,在blog/blog/apps/articles/models.py文件中添加如下代码
from django.db import modelsfrom user.models import BaseModel
from user.models import User# 创建数据模型
# 博客文章数据模型 应该有哪些字段?
#
class Articles(BaseModel): # BaseModel # 文章正文内容 TextFieldbody = models.TextField(verbose_name='正文')# 文章标题 CharFieldtitle = models.CharField(max_length=100,verbose_name='标题')# 文章封面图片 ImageFieldavatar = models.ImageField(upload_to='articles/%Y%m%d/',verbose_name='文章封面')# 文章摘要 CharFielddesc =models.CharField(max_length=255,verbose_name='文章摘要')# 文章的浏览量 IntegerFieldread_num = models.IntegerField(verbose_name='文章浏览量',default=0)# 文章的作者 外键 文章是多的 用户是一的 外键字段写在哪一方? 多的这一方author = models.ForeignKey(User,on_delete=models.CASCADE)# 文章的专栏 CharField 外键字段 专栏表 一对多 多 column = models.ForeignKey('Column',on_delete=models.CASCADE)class Meta:db_table = 'blog_articles'verbose_name = '文章'verbose_name_plural = verbose_nameclass Column(BaseModel):# 专栏的名字title = models.CharField(max_length=100, verbose_name='专栏标题')class Meta:db_table = 'blog_column'verbose_name = '专栏'verbose_name_plural = verbose_namedef __str__(self):# 打印一个对象的时候return self.title
执行数据库迁移,生成对应的数据表(在虚拟环境中,manage.py文件下)
python manage.py makemigrations
python manage.py migrate
将文章模块中的数据模型加入后台管理
在admin.py文件中添加如下代码:
from django.contrib import admin
from articles.models import Articles,Column# Register your models here.
class ArticlesAdmin(admin.ModelAdmin):list_display = ['title','author','create_time']# 想通过作者来搜索 ==》 通过作者的名字来搜索 ===》search_fields = ['title','author__username']class ColumnAdmin(admin.ModelAdmin):list_display = ['title','create_time']# 想通过作者来搜索 ==》 通过作者的名字来搜索 ===》search_fields = ['title']# 将原来的数据模型和ModelAdmin结合起来
admin.site.register(Articles,ArticlesAdmin)
admin.site.register(Column,ColumnAdmin)
在apps.py文件中添加如下代码:
from django.apps import AppConfigclass ArticlesConfig(AppConfig):name = 'articles'verbose_name = '文章管理'
在__init__.py文件中添加如下代码:
default_app_config = 'articles.apps.ArticlesConfig'
实现创建文章
写路由(总路由)
from django.contrib import admin
from django.urls import path,include
from django.conf.urls.static import static
from django.conf import settingsurlpatterns = [path('admin/', admin.site.urls),# 进行路由分发path('user/',include('user.urls')),path('password-reset',include('password_reset.urls')),path('',include('articles.urls')),
]+static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT)
在articles文件夹下创建urls.py文件,添加如下代码,用作路由分发:
from django.urls import pathfrom . import viewsapp_name = 'articles'urlpatterns = [# 创建文章path('create',views.Create.as_view(),name='create'),path('index',views.index,name='index'),
]
写视图(view.py)
from django.http import HttpResponse
from django.shortcuts import render,redirect,reversefrom user.views import LoginRequired
from articles.models import Column,Articles# 继承LoginRequired 只有用户登录了以后才能访问
class Create(LoginRequired):# 展示创建文章的html页面def get(self,requests):# 先查出来所有的专栏,展示在html页面中,让用户去勾选columns = Column.objects.all()return render(requests,'articles/create.html',locals())# 实现创建文章的功能逻辑def post(self,requests):# 接受请求数据title = requests.POST.get('title')desc = requests.POST.get('desc')body = requests.POST.get('body')column = requests.POST.get('column')# 用户 就是当前登录的用户author = requests.user# 封面图 文件是通过FILES接受的avatar = requests.FILES.get('avatar')# 数据入库try:Articles.objects.create(author=author,title=title,body=body,desc=desc,avatar=avatar,column_id=column)# 返回结果return redirect(reverse('articles:index'))except Exception as err:return render(requests,'articles/create.html',{'errmsg':'请选择专栏'})def index(request):return HttpResponse('首页')
在templates/目录下创建articles/create.html,并添加如下代码:
{% extends 'base.html' %}
{% block title %}创建文章{% endblock title %}
{% block content %}<div class="container"><div class="row"><div class="clo-12"><form action="" method="post" enctype="multipart/form-data">{% csrf_token %}<!--文章标题 --><div class="form-group"><label for="title">文章标签</label><input type="text" class="form-control" id="title" name="title"></div><!--文章专栏 --><div class="form-group"><label for="column">文章专栏</label><select name="column" id="column" class="form-control"><option value="none">请选择专栏</option>{% for column in columns %}<option value="{{ column.id }}">{{ column.title }}</option>{% endfor %}</select></div><!--文章摘要 --><div class="form-group"><label for="desc">文章摘要</label><input type="text" class="form-control" id="desc" name="desc"></div><!--文章图片 --><div class="form-group"><label for="avatar">文章封面</label><input type="file" class="form-control" id="avatar" name="avatar"></div><!--文章正文 --><div class="form-group"><label for="body">文章正文</label><textarea class="form-control" name="body" id="body" cols="30" rows="10"></textarea></div><!--提交按钮 --><button type="submit" class="btn btn-success">完成</button></form></div></div></div>
<!--展示错误信息 -->{% if errmsg %}<div class="alert alert-danger alert-dismissible"><strong>错误!</strong>{{ errmsg }}</div>{% endif %}
{% endblock content %}
实现修改文章
写视图(view.py)
class Update(LoginRequired):# 展示创建文章的html页面def get(self,requests,id):# 先查出来要修改的文章 展示在html中article = get_object_or_404(Articles,pk=id)# 先查出来所有的专栏,展示在html页面中,让用户去勾选columns = Column.objects.all()return render(requests,'articles/update.html',locals())# 实现创建文章的功能逻辑def post(self,requests,id):# 对指定的文章进行修改# 1. 先查出文章article = get_object_or_404(Articles, pk=id)# 2. 判断文章的作者是不是登录的用户,是则能修改,不是就不能修改if requests.user == article.author:# 接受数据article.title = requests.POST.get('title')article.desc = requests.POST.get('desc')article.body = requests.POST.get('body')column = requests.POST.get('column')avatar = requests.FILES.get('avatar')if avatar:article.avatar = avatar# 专栏是外键字段article.column =get_object_or_404(Column,pk=column)# 数据入库article.save()# 返回结果return redirect(reverse('articles:index'))return HttpResponse('不能修改其他作者的文章')
写路由(articles/urls.py)
from django.urls import path
from . import viewsapp_name = 'articles'
urlpatterns = [# 创建文章path('create',views.Create.as_view(),name='create'),path('update/<int:id>',views.Update.as_view(),name='update'),path('index',views.index,name='index'),
]
在templates/articles/文件夹下创建update.html文件,添加如下代码:
{% extends "base.html" %}
{% block title %} 更新文章 {% endblock title %}
{% block content %}
<div class="container"><div class="row"><div class="col-12"><br><form method="post" action="" enctype="multipart/form-data">{% csrf_token %}<div class="form-group"><label for="title">文章标题</label><!-- 在 value 属性中指定文本框的初始值为旧的内容,即 article 对象中的 title 字段 --><input type="text" class="form-control" id="title" name="title" value="{{ article.title }}"></div><!-- 文章栏目 --><div class="form-group"><label for="column">栏目</label><select class="form-control" id="column" name="column"><option value="none">请选择栏目..</option>{% for column in columns %}<option value="{{ column.id }}"{% if column.id == article.column.id %}selected{% endif %}>{{ column }}</option>{% endfor %}</select></div><div class="form-group"><!-- avatar --><label for="avatar">文章图片</label><!-- 有封面则展示封面 -->{% if article.avatar %}<img src="{{ article.avatar.url }}" style="max-width: 20%; border-radius: 15%;" class="col-md-4"><input type="file" class="form-control-file" name="avatar" id="avatar">{% else %}<h5 class="col-md-4">请上传文章图片</h5><input type="file" class="form-control-file" name="avatar" id="avatar">{% endif %}<!-- 有头像则展示头像 --></div><!-- 文章摘要 --><div class="form-group"><!-- 标签 --><label for="desc">文章摘要</label><!-- 文本框 --><input type="text" class="form-control" id="desc" name="desc" value="{{ article.desc }}"></div><div class="form-group"><label for="body">文章正文</label><!-- 文本域不需要 value 属性,直接在标签体中嵌入数据即可 --><textarea type="text" class="form-control" id="body" name="body" rows="12">{{ article.body }}</textarea></div><button type="submit" class="btn btn-primary">完成</button></form></div></div>
</div>
{% endblock content %}
实现删除文章
写视图(view.py)
def delete(requests,id):# 1. 先根据ID查出文章article = get_object_or_404(Articles, pk=id)# 2. 判断当前登录用户是不是作者if requests.user == article.author:# 3. 如果是作者就删除文章 数据入库article.delete()return redirect(reverse('articles:index'))# 4. 如果不是作者,就提示不能删return HttpResponse('不能删除其他作者的文章')
写路由(urls.py)
from django.urls import path
from . import viewsapp_name = 'articles'
urlpatterns = [# 创建文章path('create',views.Create.as_view(),name='create'),path('update/<int:id>',views.Update.as_view(),name='update'),path('delete/<int:id>',views.delete,name='delete'),path('index',views.index,name='index'),
]
展示所有文章
基础版本(无分页)
写视图(view.py)
def index(request):# 获取所有的文章,再展示在html页面中articles = Articles.objects.all()return render(request,'articles/index.html',locals())
写路由(总路由)
from django.urls import path,include
from django.conf.urls.static import static
from django.conf import settingsfrom articles.views import indexurlpatterns = [path('',index,name='index'),path('admin/', admin.site.urls),# 进行路由分发path('user/',include('user.urls')),path('password-reset',include('password_reset.urls')),path('',include('articles.urls')),
]+static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT)
写路由(articles/urls.py)
from django.urls import path
from . import viewsapp_name = 'articles'
urlpatterns = [# 创建文章path('create',views.Create.as_view(),name='create'),path('update/<int:id>',views.Update.as_view(),name='update'),path('delete/<int:id>',views.delete,name='delete'),# 展示所有的博文path('index',views.index,name='index'),
]
在templates/articles/文件夹下创建index.html文件并添加如下代码:
{% extends "base.html" %}
{% block title %} 博客正文 {% endblock title %}
{% block content %}<div class="container"><div class="col-12"><div class="row mt-2">{% for article in articles %}<!-- 封面图-->{% if article.avatar %}<div class="col-3"><img src="{{ article.avatar.url }}" alt="avatar" style="max-width: 100%;border-radius:20px "></div>{% endif %}<!-- 文章内容--><div class="col"><!-- 文章栏目--><button type="button" class="btn btn-sm mb-2 btn-success">{{ article.column }}</button><!-- 文章标题--><h4><b><a href="{% url 'articles:detail' article.id %}">{{ article.title }}</a></b></h4><!-- 文章摘要--><div><p style="color: gray;">{% if article.desc %}{{ article.desc }}{% else %}还没有摘要{% endif %}</p></div><!-- 其他信息--><p><span style="color: green">作者:{{ article.author }} </span><span style="color: green">浏览量:{{ article.read_num }} </span><span style="color: green">发布时间:{{ article.create_time|date:'Y-m-d' }} </span><span style="color: green">更新时间:{{ article.update_time|date:'Y-m-d' }} </span></p></div><hr style="width: 100%;">{% endfor %}</div></div></div>
{% endblock content %}
展示文章详情页
写视图(view.py)
# 查看文章详情
def detail(request,id):# 根据文章的ID 查出对应的文章展示在html页面中article = get_object_or_404(Articles, pk=id)# 没查看一次文章 就增加一次浏览量article.read_num += 1article.save()return render(request,'articles/detail.html',locals())
写视图(urls.py)
from django.urls import path
from . import viewsapp_name = 'articles'
urlpatterns = [# 创建文章path('create',views.Create.as_view(),name='create'),path('update/<int:id>',views.Update.as_view(),name='update'),path('delete/<int:id>',views.delete,name='delete'),# 展示所有的博文path('index',views.index,name='index'),# 查看博文详情path('detail/<int:id>',views.detail,name='detail'),
]
在templates/articles/文件夹下创建detail.html文件:
{% extends 'base.html' %}
{% block title %}文章详情{% endblock title %}
{% block content %}<div class="container"><div class="row"><div class="col-9"><!--标题和作者--><h1 class="mt-4 mb-4">{{ article.title }}</h1><div class="alert alert-success">作者:{{ article.author }}创建时间:{{ article.create_time|date:'Y-m-d' }}文章浏览量:{{ article.read_num }}<!--如果当前登录的用户就是作者,则展示删除文章和修改文章-->{% if request.user == article.author %}<a href="#" onclick="confirm_delete()">删除文章</a><a href="{% url 'articles:update' article.id %}">修改文章</a>{% endif %}<!--文章的专栏--><button type="button" class="btn btn-success btn-sm mb-2">{{ article.column }}</button></div><!--文章的正文--><div class="col-12"><p>{{ article.body }}</p></div></div></div></div><script>//删除文章的函数function confirm_delete(){// 调用layer弹窗组件layer.open({title:"确认删除",content:'确认删除这篇文章吗?',yes:function (index,layero){// 指定前往的urllocation.href = '{% url "articles:delete" article.id %}'},})}</script>
{% endblock content %}