大家好,这是皮爷给大家带来的最新的学习Python能干啥?之Django教程,从零开始,到最后成功部署上线的项目。这一节,用AdminLTE编写Dashboard。
皮爷的每一篇文章,都配置相对应的代码。这篇文章的代码Tag是Post_024
目前,当我们登录我们的CMS界面,我们看到的是这个样子:
很丑,不美观。所以这几节,我们将要开发一款真正意义上的CMS Dashboard。具体开发完成长这个样子:
我们看到,具体分为这么几个部分:
这些东西我们其实都是可以做出来的,接下来的几节课,我们就来讲讲每一个部分都是怎么实现的。
首先是用户访问统计,我们要统计每一个用户的访问请求,同时要记录每天网站访问人数,那么我们就需要创建模型了。
这个模型应该是属于全站使用,所以我们就在basefucntion/models.py
下面的创建:
class UserIP(models.Model):
ip_address = models.CharField(max_length=30)
ip_location = models.CharField(max_length=30)
end_point = models.CharField(default='/', max_length=30)
day = models.DateField(default=timezone.now)
# 网站总访问次数
class VisitNumber(models.Model):
count = models.IntegerField(default=0) # 网站访问总次数
# 单日访问量统计
class DayNumber(models.Model):
day = models.DateField(default=timezone.now)
count = models.IntegerField(default=0) # 网站访问总次数
接着,我们在base
应用下,创建一个tracking_view.py
,里面要放我们的更新方法,即最终网站访问数量的方法:
def peekpa_tracking(func):
def wrapper(request, *args, **kwargs):
tacking_info(request)
return func(request, *args, **kwargs)
return wrapper
def tacking_info(request):
update_visit_number()
update_user_ip(request)
update_day_visit_number()
def update_visit_number():
count_nums = VisitNumber.objects.filter(id=1)
if count_nums:
count_nums = count_nums[0]
count_nums.count = F('count') + 1
else:
count_nums = VisitNumber()
count_nums.count = 1
count_nums.save()
def update_user_ip(request):
if 'HTTP_X_FORWARDED_FOR' in request.META: # 获取 ip
client_ip = request.META['HTTP_X_FORWARDED_FOR']
client_ip = client_ip.split(",")[0] # 所以这里是真实的 ip
else:
client_ip = request.META['REMOTE_ADDR'] # 这里获得代理 ip
UserIP().objects.create(ip=client_ip, end_point=request.path, ip_address="TBA", day=timezone.now().date())
def update_day_visit_number():
date = timezone.now().date()
today = DayNumber.objects.filter(day=date)
if today:
temp = today[0]
temp.count += 1
else:
temp = DayNumber()
temp.dayTime = date
temp.count = 1
temp.save()
首先,这里我们要通过装饰器的方式来实现,当request进来的时候,我们做了三步处理:
然后再将request交给传入的func去做接下来该做的事儿。
我们这个时候可以在文章的detail信息做一下验证:
@peekpa_tracking
def detail(request, time_id):
这个时候,我们再去打开之前发布的任何一个文章:
访问成功之后,我们看数据库里面:
就能看到我们跟踪的信息已经存到了数据库中了。说明成功了。接下来我们就要来做Dashboard的统计工作。
我们在最开始的预览图里面看到,我们的Dashboard页面是有网站点击相关统计的内容显示的,接下来,我们就将这些东西显示出来。
如果我们要将数据显示到Dashboard上,那么就应该在Dashboard的home视图函数中,先提前将数据准备好,然后再传递给页面即可。
所以,我们的主要逻辑就应该在cms_dashboard(request)
视图方法中写。
@peekpa_login_required
def cms_dashboard(request):
context = {}
context.update(get_dashboard_top_data())
context.update(get_dashboard_visitor_ip_table())
return render(request, 'cms/home/home.html', context=context)
def get_dashboard_top_data():
post_num = Post.objects.all().count()
day_visit_ip_set = set()
day_visit_ip_list = UserIP.objects.filter(day=timezone.now().date())
if day_visit_ip_list:
for user_ip_item in day_visit_ip_list:
if user_ip_item.ip_address not in day_visit_ip_set:
day_visit_ip_set.add(user_ip_item.ip_address)
day_visit_ip_num = len(day_visit_ip_set)
day_visit_num = DayNumber.objects.filter(day=timezone.now().date())[0].count
total_visit_num = VisitNumber.objects.filter(id=1)[0].count
context = {
"post_num": post_num,
"day_visit_ip_num": day_visit_ip_num,
"day_visit_num": day_visit_num,
"total_visit_num": total_visit_num
}
return context
def get_dashboard_visitor_ip_table():
visitor_data = UserIP.objects.filter(day=timezone.now().date())
if len(visitor_data):
visitor_data = visitor_data[:7]
context = {
'visitor_data_list': visitor_data,
}
return context
可以看到,我们这里使用两个方法get_dashboard_top_data
和get_dashboard_visitor_ip_table
来分别获取顶部四个小模块的数据还有Visitor IP Table
的数据。我们拿到数据之后,就展示到前端:
接下来,我们就要完善Chart的内容了。
这里可以看到,我们的Dashboard用到了一个非常美丽的表单,这个是Chart.js,是一个非常好用的图表库。官网地址:
https://www.chartjs.org/
因为我们首先需要将值从后台传给前端,然后这个图标是个js文档,所以,我们应该在html代码中,编写一些js代码。我们的home_visit_chat.html
代码就应该变成下面这样:
<script>
$(document).ready(function () {
var ticksStyle = {
fontColor: '#495057',
fontStyle: 'bold'
}
var $visitorsChart = $('#visitors-chart')
var visitorsChart2 = new Chart($visitorsChart, {
data: {
labels: {{ date_time_list }},
datasets: [{
type: 'line',
data: {{ week_data_list }},
backgroundColor: 'transparent',
borderColor: '#007bff',
pointBorderColor: '#007bff',
pointBackgroundColor: '#007bff',
fill: true
}]
},
options: {
maintainAspectRatio: false,
tooltips: {
mode: 'index',
intersect: true
},
hover: {
mode: 'index',
intersect: true
},
legend: {
display: false
},
scales: {
yAxes: [{
// display: false,
gridLines: {
display: true,
lineWidth: '4px',
color: 'rgba(0, 0, 0, .2)',
zeroLineColor: 'transparent'
},
ticks: $.extend({
beginAtZero: false,
suggestedMax: {{ suggested_max }}
}, ticksStyle)
}],
xAxes: [{
display: true,
gridLines: {
display: false
},
ticks: ticksStyle
}]
}
}
})
})
script>
可以看到,这里面有好多数据都是需要后盾传送给前端,所以,我们将这些数据都读取出来,添加给cms_dashboard()
视图函数即可:
def get_dashboard_visitor_chart():
days_list = []
visit_list = []
max_num = 0
week_total_num = 0
for index in range(6, -1, -1):
day, format_date = get_before_date(index)
days_list.append(int(day))
day_visit_num = 0
daynumber_item = DayNumber.objects.filter(day=format_date)
if daynumber_item:
day_visit_num = daynumber_item[0].count
visit_list.append(day_visit_num)
week_total_num += day_visit_num
max_num = day_visit_num if day_visit_num > max_num else max_num
context = {
'visit_week_total_number': day_visit_num,
'date_time_list': days_list,
'week_data_list': visit_list,
'suggested_max': max_num
}
return context
这样,我们的图表就制作完成了。看一下效果:
最后一个,就是我们的文章浏览情况了。
文章阅读,我们既然已经知道了每一天的访问量,而且他们访问的地址我们也知道,所以,文章的访问我们就能够很轻易的做出来。
同样,还是在cms_dashboard
视图函数里面添加数据即可。
def get_dashboard_post_view_table():
visitor_day_data = UserIP.objects.filter(day=timezone.now().date(), end_point__contains='/detail/')
post_map = {}
post_view_table_list = []
if visitor_day_data:
for item in visitor_day_data:
post_id = item.end_point.split('/')[2]
if post_id in post_map:
post_map[post_id] += 1
else:
post_map[post_id] = 1
if post_map:
for key in post_map:
key = key
post_item = Post.objects.filter(time_id=key)
if post_item:
post_item[0].inscrease = post_map[key]
post_view_table_list.append(post_item[0])
if post_view_table_list:
post_view_table_list.sort(key=lambda x: x.inscrease, reverse=True)
context = {
'post_view_table_list': post_view_table_list,
}
return context
这里我们操作比较繁琐,主要是经历了这么几步骤:
最后,我们来看一下整体的效果:
看到整个页面分为四个板块,然后左侧还做了Monitor,里面分别对应的UserIP管理还有文章阅读详情。其实Dashboard的编写,还能更加多变灵活,关键还是要根据自己的实际需求来完成。
最后我们再来加一章节,来说一下文章统计的事儿。
细心读文章的同学肯定发现了,我们之前的文章统计的数值是不对的,那么想要实现文章统计,我们有这么几个思路:
read_num
喜加一,再存进去;这几种思路,他们的特点分别是:
既然,我们的peekpa.com也不是什么一般的小网站,这里我就选择第二种实现方式给大家看看。
这里来简单说一下思路:
当用户访问文章详情的时候,会针对用户生成一个uid,这个uid在不同的文章里面,缓存1分钟。1分钟之内用户重复访问,不算访问量。然后懒加载更新数据库。
这回,我们就要用到了middleware了。首先在Post应用下,创建一个middleware python包
,然后在里面实现一个叫做user_id
的middleware
:
class UserIDMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
uid = self.generate_uid(request)
request.uid = uid
response = self.get_response(request)
response.set_cookie(USER_KEY, uid, max_age=TEN_YEARS, httponly=True)
return response
def generate_uid(self, request):
try:
uid = request.COOKIES[USER_KEY]
except KeyError:
uid = uuid.uuid4().hex
return uid
然后,我们要在settings.py
文件里面的MIDDLEWARE
中,在第一个位置添加这个middleware:
MIDDLEWARE = [
'apps.poster.middleware.user_id.UserIDMiddleware',
]
最后,我们就在文章详情请求页里面,来加入我们上面所讲的逻辑:
@peekpa_tracking
def detail(request, time_id):
handle_visited(request, time_id)
return render(request, 'post/detail.html', context=context)
def handle_visited(request, time_id):
increase_post_view = True
uid = request.uid
pv_key = 'pv:%s:%s' % (uid, request.path)
if not cache.get(pv_key):
increase_post_view = True
cache.set(pv_key, 1, 2*60)
if increase_post_view:
Post.objects.filter(time_id=time_id).update(read_num=F('read_num') + 1)
这样,我们就完美的实现了页面访问喜加一的功能。
最后总结一下,
编写CMS的Dashboard:
cms_dashboard()
这个视图函数里面添加数据返回前端;end_point
值获取到文章id,然后再去Post里面根据ID找文章,最后展示出来;整套教程源码获取,可以关注『皮爷撸码』,回复『peekpa.com』
长按下图二维码关注,如文章对你有启发,欢迎在看与转发。