个人博客项目:
主要使用django2.2.3+pycharm+sqlite3完成,
注:此篇文章只是自己用来记录笔记的,若有疑问,联系13484413532
最后结果图:
s-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDc5OTEzOQ==,size_16,color_FFFFFF,t_70)
一、分析项目需求
1、能够实现用户的登录、注册、注销等功能
2、只有登录上去才可以能够修改自己的个人信息,头像等
3、登录后可以写博客,
4、首页展示点击量最高的三篇文章和按时间顺序写的文章并且点击可以查看详情
5、可以按标签浏览文章并且分页展示
然后创建django项目:blogs
更改配置文件
STATIC_URL = '/static/'
STATICFILES_DIRS = (os.path.join(BASE_DIR,'static'),) #开发中的创建静态配置
#STATIC_ROOT = os.path.join(BASE_DIR,'static') #实际中的配置
二、需要的表
1、用户表UserProfile:
创建app—>blog
在model.py文件里创建UserProfile:
from django.db import models
from django.contrib.auth.models import AbstractUser
class UserProfile(AbstractUser):
mobile = models.CharField(max_length=11,
verbose_name = '手机号码',
unique=True
)
icon = models.ImageField(upload_to='uploads/%Y/%m/%d',default='upload/orages.PNG')
email = models.EmailField()
class Meta:
db_table : 'UserProfile'
verbose_name = '用户表'
verbose_name_plural = verbose_name
我继承的是AbstractUser,并且定义为用户表
但是这里一定需要在settings.py里更改为以下:
AUTH_USER_MODEL = 'blog.UserProfile'
然后进行迁移和同步:
python manage.py makemigrations
python manage.py migration
2、用户注册表与登录表:
在app中创建一个form.py文件,定义用户注册表
#用户注册表单
class UserRegisterForm(Form):
username =forms.CharField(max_length=14,min_length=6,
error_messages={'min_length':'用户名最少6位',
'max_length':'用户名最大14位'},label='用户名')
email = forms.EmailField(max_length=30,min_length=6,error_messages={'required':'必须填写邮箱',},label='邮箱')
password = forms.CharField(max_length=14,min_length=6,error_messages={'required':'必须填写密码',},label='密码')
mobile = forms.CharField(max_length=11,min_length=10,error_messages={'required':'必须填写手机号码',},label='手机号码')
class RegisterForm(ModelForm):
class Meta:
model =UserProfile
# fields ='__all__'
#exclude = [''] 两个搭配使用意为使用除去exclude里的字段的其他字段
fields = ['username','email','password','mobile']
# def clean_username(self):
# username = self.cleaned_data.get('username')
# result = re.match(r'[a-zA-Z]\w{5}',username)
# #username 要以字母开头后面的是字母下划线或者数字加5位数
# if not result:
# raise ValidationError('用户名必需以字母开头')#如果没有匹配到就抛出异常语句
# return username
#用户登录表单
class LoginForm(Form):
username = forms.CharField(max_length=14, min_length=6,
label='用户名')
password = forms.CharField(max_length=14, min_length=6,
error_messages={'required': '必须填写密码', }, label='密码'
)
def clean_username(self):
username = self.cleaned_data.get('username')
if not UserProfile.objects.filter(username=username).exists():
raise ValidationError('!!!')
return username
不要忘记在url中配置路由:
我用的是路由分发:
urlpatterns = [
path('admin/', admin.site.urls), #后台管理的路由
path('blog/',include('blog.urls',namespace='blog')), #app---blog的路由
path('article/',include('article.urls',namespace='article')), #app--article的路由
re_path(r'^media/(?P<path>.*)$',serve,{'document_root':MEDIA_ROOT}), #静态文件的路由
re_path(r'^ckeditor/',include('ckeditor_uploader.urls')),# 富文本编辑 加载上传时默认路径
]
#blog的路由配置
urlpatterns=[
path('register',user_register,name='register'), #用户注册
path('login',user_login,name='login'), #用户登录
path('logout',user_logout,name='logout'), #用户注销
path('about',user_about,name='about'), #关于作者
path('center',user_center,name='center'), #用户中心
path('index',user_index,name='index'), #博客首页
]
然后写视图函数:
from django.contrib.auth import logout,login,authenticate
from django.contrib.auth.decorators import login_required
from django.contrib.auth.hashers import make_password, check_password
from django.http import JsonResponse
from django.shortcuts import HttpResponse, render, redirect
from django.urls import reverse
from article.models import Article
from blog.form import RegisterForm, LoginForm
from blog.models import UserProfile
# 最初页面
def user_index(request):
farticles = Article.objects.all().order_by('-click_num') #以少的点击量进行排序
darticles = Article.objects.all().order_by('-date')[:3]
return render(request, 'user/index.html',
context={'figure_article':farticles[:3],'darticle':darticles})
# 注册页面
def user_register(request):
if request.method == 'GET':
rform = RegisterForm(request.POST)
return render(request, 'user/register.html',context={"rform":rform})
else:
rform = RegisterForm(request.POST) # 使用form获取数据,
# 想要在前端使用:return render(request, 'user/register.html',context={"rform":rform})
if rform.is_valid():#进行数据的校验
# 校验成功从前端取数据
username = rform.cleaned_data.get('username')
password = rform.cleaned_data.get('password')
mobile = rform.cleaned_data.get('mobile')
email = rform.cleaned_data.get('email')
if UserProfile.objects.filter(username=username).exists():
return render(request, 'user/register.html', context={'msg': '用户名已经存在'})
else:
# 如果校验成功把数据存入数据库
password = make_password(password) # 对密码进行加密
user = UserProfile.objects.create(username=username, password=password,
email=email, mobile=mobile)
if user:
return render(request, 'user/login.html')
return render(request,'user/register.html',context={'msg':'用户名与密码最少6位最大14位,手机号码11位'})
#不使用form提交数据
# username =request.POST.get('username')
# password = request.POST.get('password')
# mobile = request.POST.get('mobile')
# email = request.POST.get('email')
# password = make_password(password) # 对密码进行加密
# user = UserProfile.objects.create(username=username, password=password,
# email=email, mobile=mobile)
# if user:
# return HttpResponse('注册成功')
# else:
# return render(request, 'user/register.html')
#用户登录
def user_login(request):
if request.method == 'GET':
return render(request,'user/login.html')
else:
lform = LoginForm(request.POST)
if lform.is_valid():
username = lform.cleaned_data.get('username')
password = lform.cleaned_data.get('password')
#进行数据库的查询
#方式1
#user = UserProfile.objects.filter(username=username).first()
# flag = check_password(password,user.password) #对密码进行解码,返回布尔值
# if flag:
# #记录登录用户名
# request.session['username'] = username
# #return redirect(reverse('index'))
#return render(request, 'index.html')
# 方式2
user = authenticate(username=username,password=password)
if user:
login(request,user)
return render(request, 'user/index.html')
return render(request, 'user/login.html',
context={'msg': '登录失败,请检查输入是否正确'})
#注销登录
def user_logout(request):
#request.session.clear() #只是删除了字典(session用字典保存)
# request.session.flush() #删除了django)_session + cookile + 字典
#
logout(request)
return render(request, 'user/index.html')
#关于我
def user_about(request):
return render(request, 'user/about.html')
#发送验证码路由,ajax发过来的请求
# def send_code(request):
# mobile = request.GET('mobile')
# #发送验证码 第三方
# json_result = utils_sendmsg(mobile)
# #取值
# status = json_result.get('code')
# data = {}
# if status == 200:
# check_code = json_result.get('obj') #obj是真正的验证码
# #使用session进行缓冲
# request.session[mobile] = check_code
# data['status'] = 200
# data['mag'] = '验证码发送成功'
# else:
# data['status'] =500
# data['mag'] = '验证码发送失败'
# return JsonResponse(data)
#忘记密码
#忘记密码
def user_forget(request):
if request.method == 'GET':
return render(request, 'user/forget.html')
#用户的个人中心,用login登录的
@login_required
def user_center(request):
user = request.user
if request.method == 'GET':
user = request.user
return render(request, 'user/center.html',context={'user':user})
else:
username =request.POST.get('username')
mobile = request.POST.get('mobile')
email = request.POST.get('email')
icon = request.FILES.get('icon')
#在数据库里更改
user.username = username
user.mobile = mobile
user.email = email
user.icon = icon
user.save()
return render(request, 'user/center.html', context={'user': user})
三、文件上传
文件上传需要创建media文件夹
使用的模型是Filefield(任何文件类型)#ImageField(只能是图片)
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR,'media')
使用时需要参数upload_to=‘路径’这个路径就是 MEDIA_ROOT指明的路径
模板中想要应用上传的文件需要在settings里的templates里加入
'django.template.context_processors.media'
添加路由
re_path(r'^media/(?P<path>.*)$',serve,{'document_root':MEDIA_ROOT}),
这样前端就可以通过{{MEDIA_URL}}来使用
四、文章表
创建app–article,在model里创建文章表和标签表
标签与文章是多对多关系
文章与作者是一对多关系
class Tag(models.Model):
name = models.CharField(max_length=50,verbose_name='标签',db_index = True)
def __str__(self):
return self.name
class Meta:
db_table = 'tag'
verbose_name = '标签表'
verbose_name_plural = verbose_name
class Article(models.Model):
title = models.CharField(max_length=100,verbose_name='标题')
desc = models.CharField(max_length=256, verbose_name='简介')
content = RichTextUploadingField(verbose_name='内容')
date = models.DateField(auto_now=True,verbose_name='发表日期')
click_num = models.IntegerField(default=0,verbose_name='点击量')
love_num = models.IntegerField(default=0,verbose_name='点赞量')
image = models.ImageField(upload_to='uploads/article/%Y/%m/&d',verbose_name='文章图片')
tags = models.ManyToManyField(Tag)
user = models.ForeignKey(to=UserProfile,on_delete=models.CASCADE)
def __str__(self):
return self.title
class Meta:
db_table = 'article'
verbose_name = '文章表'
verbose_name_plural = verbose_name
写博客是记录博客内容的表在自己创建的forms文件内,继承ModelForm
class ArticleForm(forms.ModelForm):
class Meta:
model = Article
fields = '__all__'
exclude = ['click_num','love_num','date']
为了是后台管理能够显示出来这些表,需要在admin文件里进行注册
from django.contrib import admin
from article.models import Article,Tag
admin.site.register(Article)
admin.site.register(Tag)
-------------------------------------------
from blog.models import UserProfile
admin.site.register(UserProfile)
五、URL—article
app_name = 'article'
urlpatterns = [
path('detail',article_detail,name = 'detail'), #博客内容详情
path('learn',article_learn,name = 'learn'), #浏览全部博客
path('write',article_write,name = 'write'), #写博客 ]
六、视图函数-------博客
from django.contrib.auth.decorators import login_required
from django.core.paginator import Paginator
from django.shortcuts import render
from article.forms import ArticleForm
from article.models import Article, Tag
#首页浏览 ——查看详细信息
def article_detail(request):
id = request.GET.get('id')
article = Article.objects.get(pk = id)
article.click_num+=1
article.save() #增加观看量
tags_list = article.tags.all()#查询相干文章
list_about = []#存放文章的列表
for tag in tags_list:
for article in tag.article_set.all():
if article not in list_about and len(list_about)<6:
list_about.append(article)
return render(request, 'article/detail.html', context={'article':article,
'list_about':list_about})
#分页查看所有文章 按标签分类
def article_learn(request):
tags = Tag.objects.all()
tid = request.GET.get('tid')
if tid:
tag = Tag.objects.get(pk=tid)
#articles = Article.objects.filter(tags__name=tag.name)
articles = tag.article_set.all() #如果进行标签检索
else:
articles = Article.objects.all()
paginator = Paginator(articles,4) #分页 (articles:要查询的对象列表,4:每页的个数)
page = request.GET.get('page',1) #取不到默认为1
page = paginator.get_page(page) #返回的是page对象
return render(request,'article/learn.html',
context={'page':page,'tags':tags,'tid':tid})
#写博客
@login_required
def article_write(request):
if request.method =="GET":
aform = ArticleForm()
return render(request,'article/write.html',context={'form':aform})
else:
aform = ArticleForm(request.POST)
if aform.is_valid():
data = aform.cleaned_data
article = Article()
article.title = data.get('title')
article.desc = data.get('desc')
article.content = data.get('content')
# article. click_num= data.get('click_num')
# article.love_num = data.get('love_num')
article.image = data.get('image') #没保存文章不能添加标签
article.user = data.get('user') #一对多可以直接保存
article.save()
article.tags.set(data.get('tags')) #多对多 没保存文章不能添加标签
# article.save()
return render(request, 'article/learn.html')
else:
return render(request,'article/write.html')
七、验证登录状态
1.可以利用中间件进行验证
2.因为我继承了AbstractractUser,所有可以使用@login_required装饰器来进行验证
但是一定需要在settings里面加入登录路由
#添加一个登录路由
LOGIN_URL = '/blog/login'
八、使用富文本编辑器
1.下载pip install django-ckeditor
2.在settings里的app加入
'ckeditor', # 添加ckeditor富文本编辑器
'ckeditor_uploader', # 进行文件上传
#在最后加入
CKEDITOR_UPLOAD_PATH = 'uploads/' #上传文件的路径 ’依赖MEDTA_ROOT‘
3.然后把STATICFILES_DIR改为STATIC_ROOT
4.在collectstatic #收集静态文件
5.url中加入
re_path(r'^ckeditor/',include('ckeditor_uploader.urls')),#加载上传时默认路径
6.在要使用的字段里改为 RichTextUploadingField()就可以在后台看到
7.前端要使用:
<form action="{% url 'article:write' %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.media }}
{{ form.as_p }}
<input type="submit" value="提交" >
</form>
还有一些功能未完善