一、功能需求分析

1.功能

  1. 轮播图

  2. 推荐文章列表

  3. 文章标签导航

  4. 文章列表

  5. 分页

二、模型设计

根据功能分析,我们需要如下表

1.表和字段分析

  1. 文章分类表

  2. 文章表

  3. 文章评论表

  4. 推荐文章表

  5. 轮播图表

2.模型定义

定义一个基类模型,抽取公共字段

# 在utils目录下,创建一个models.py文件,在其中定义一个基类模型
from django.db import models class BaseModel(models.Model):
"""
基类,公共字段
"""
create_time = models.DateTimeField('创建时间', auto_now_add=True)
update_time = models.DateTimeField('更新时间', auto_now=True)
is_delete = models.BooleanField('逻辑删除', default=False) class Meta:
# 抽象类,用于继承,迁移时不会创建
abstract = True

定义其他模型

# 在news目录下的models.py文件中定义如下数据模型
from django.db import models
from utils.models import BaseModel class Tag(BaseModel):
"""
文章分类标签模型
"""
name = models.CharField('标签名', max_length=64, help_text='标签名') class Meta:
ordering = ['-update_time', '-id'] # 排序
db_table = "tb_tag" # 指明数据库表名
verbose_name = "文章标签" # 在admin站点中显示的名称
verbose_name_plural = verbose_name # 显示的复数名称 def __str__(self):
return self.name class News(BaseModel):
"""
文章模型
"""
title = models.CharField('标题', max_length=150, help_text='标题')
digest = models.CharField('摘要', max_length=200, help_text='摘要')
content = models.TextField('内容', help_text='内容')
clicks = models.IntegerField('点击量', default=0, help_text='点击量')
image_url = models.URLField('图片url', default='', help_text='图片url')
tag = models.ForeignKey('Tag', on_delete=models.SET_NULL, null=True) author = models.ForeignKey('user.User', on_delete=models.SET_NULL, null=True) class Meta:
ordering = ['-update_time', '-id'] # 排序
db_table = "tb_news" # 指明数据库表名
verbose_name = "新闻" # 在admin站点中显示的名称
verbose_name_plural = verbose_name # 显示的复数名称 def __str__(self):
return self.title class Comments(BaseModel):
"""
评论模型
"""
content = models.TextField('内容', help_text='内容')
author = models.ForeignKey('user.User', on_delete=models.SET_NULL, null=True)
news = models.ForeignKey('News', on_delete=models.CASCADE) class Meta:
ordering = ['-update_time', '-id'] # 排序
db_table = "tb_comments" # 指明数据库表名
verbose_name = "评论" # 在admin站点中显示的名称
verbose_name_plural = verbose_name # 显示的复数名称 def __str__(self):
return '<评论{}>'.format(self.id) class HotNews(BaseModel):
"""
推荐文章表
"""
news = models.OneToOneField('News', on_delete=models.CASCADE)
priority = models.IntegerField('优先级', help_text='优先级') class Meta:
ordering = ['-update_time', '-id'] # 排序
db_table = "tb_hotnews" # 指明数据库表名
verbose_name = "热门新闻" # 在admin站点中显示的名称
verbose_name_plural = verbose_name # 显示的复数名称 def __str__(self):
return '<热门新闻{}>'.format(self.id) class Banner(BaseModel):
"""
轮播图
"""
image_url = models.URLField('轮播图url', help_text='轮播图url')
priority = models.IntegerField('优先级', help_text='优先级') news = models.OneToOneField('News', on_delete=models.CASCADE) class Meta:
ordering = ['priority', '-update_time', '-id'] # 排序
db_table = "tb_banner" # 指明数据库表名
verbose_name = "轮播图" # 在admin站点中显示的名称
verbose_name_plural = verbose_name # 显示的复数名称 def __str__(self):
return '<轮播图{}>'.format(self.id)

三、文章标签导航功能

1.接口设计

  1. 接口说明:

    类目 说明
    请求方法 GET
    url定义 /
    参数格式 无参数
  2. 返回结果

    返回新闻页面,直接在模板渲染

2.后端代码

# 在news/views.py文件中定义如下视图
from django.shortcuts import render from .models import Tag def index(request):
"""
新闻首页视图
:param request:
:return:
""" tags = Tag.objects.only('id', 'name').filter(is_delete=False)
return render(request, 'news/index.html',
context={
'tags': tags
})

导入tag测试数据,或者直接用Navicat软件在tb_tag表中添加数据(数据见下方代码中引号里的内容,共6个),,,因为前段设置的原因,必须要跟我的内容一样,后面会用到

# insert news tag data

INSERT INTO tb_tag(name, create_time, update_time, is_delete) values
('Python基础', now(), now(), ),
('Python高级', now(), now(), ),
('Python函数', now(), now(), ),
('PythonGUI', now(), now(), ),
('Linux教程', now(), now(), ),
('Python框架', now(), now(), );

3.前端代码

# 修改templates/news/index.html中 news-nav部分代码如:
<!-- news-nav start-->
<nav class="news-nav">
<ul class="clearfix">
<li class="active"><a href="javascript:void(0)">最新资讯</a></li>
{% for tag in tags %}
<li><a href="javascript:void(0)" data-id="{{ tag.id }}">{{ tag.name }}</a>
</li>
{% endfor %}
</ul>
</nav>
<!-- news-nav end -->

四、新闻列表功能

1.业务流程分析

  1. 判断前端传递标签分类id是否为空,是否为整数,是否超过范围

  2. 判断前端传递当前文章页数是否为空,是否为整数,是否超过范围

2.接口设计

接口说明:

类目 说明
请求方法 GET
url定义 /news/
参数格式 查询参数

参数说明:

参数名 类型 是否必须 描述
tag 整数 标签分类id
page 整数 当前文章页数

返回结果:

{
"errno": "",
"errmsg": "",
"data": {
"total_pages": ,
"news": [
{
'id': 'xxx',
"digest": "在python用import或者from...import或者from...import...as...来导入相应的模块,作用和使用方法与C语言的include头文件类似。其实就是引入...",
"title": "import方法引入模块详解",
"author": "python",
"image_url": "/media/jichujiaochen.jpeg",
"tag_name": "Python基础",
"update_time": "2018年12月17日 14:48"
},
{
'id': 'xxx'
"digest": "如果你原来是一个php程序员,你对于php函数非常了解(PS:站长原来就是一个php程序员),但是现在由于工作或者其他原因要学习python,但是p...",
"title": "给曾经是phper的程序员推荐个学习网站",
"author": "python",
"image_url": "/media/jichujiaochen.jpeg",
"tag_name": "Python基础",
"update_time": "2018年12月17日 14:48"
}
]
}
}

3.后端代码

在项目根目录下创建一个media文件夹,用于存放新闻图片以及用户上传文件。

# 在settings.py文件中添加
# 媒体文件配置
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

django在调试模式下提供静态文件服务,为了能够返回media中的媒体文件还需在根urls.py中做如下配置

# 在根urls.py中加上static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static urlpatterns = [
path('', include('news.urls')),
path('', include('verification.urls')),
path('user/', include('user.urls'))
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

导入测试数据,为了测试数据的导入,请确保表名一致

# 在xshell中导入测试数据,在xshell中通过rz命令,将tb_news_20181217.sql文件上传到虚拟机

mysql -u 用户名 -p -D 数据库名 < tb_news_20181217.sql

文件我已经放在我的文件栏里(名字是sql数据包.rar,解压后有4个文件,分别是标签表,新闻表,热门新闻表和轮播图表)

视图代码

import logging

from django.shortcuts import render
from django.views import View
from django.core.paginator import Paginator
from django.db.models import F from .models import Tag, News
from . import constants
from utils.json_res import json_response logger = logging.getLogger('django') def index(request):
"""
新闻首页视图
url: /
:param request:
:return:
""" tags = Tag.objects.only('id', 'name').filter(is_delete=False)
return render(request, 'news/index.html',
context={
'tags': tags
}) class NewsListView(View):
"""
新闻列表视图
url: /news/
args: tag, page
"""
def get(self, request):
# 1.获取参数
try:
tag_id = int(request.GET.get('tag', 0))
except Exception as e:
logger.error('标签错误:\n{}'.format(e))
tag_id = 0 try:
page = int(request.GET.get('page', 0))
except Exception as e:
logger.error('页码错误:\n{}'.format(e))
page = 1
# 使用only返回的是对象,所以传递到前端时需要迭代处理
# news_queryset = News.objects.select_related('tag', 'author').only(
# 'title', 'digest', 'image_url', 'update_time', 'tag__name', 'author__username')
# 2.获取查询集 (values返回的是字典,only返回的是对象)
############## 重要 start #################
# queryset:惰性 不会去数据库
# 构造,切片,过滤,传递的时候通常查询集不真正的去数据库查询
# 什么时候,去数据库查呢:
# 1.迭代
# 2.切片,只要不是跳着去查就不会到数据库中查询,只有中间隔着数据切片的时候才会去数据库中查询,切出一个元素的时候
# 3.照顾会在控制台打印的时候
# 4.序列化缓存,把查询集的内容存到redis,内存
# 5.使用len()方法获取长度,count
# 6.使用list()方法转换类型
# 7.bool,去判断是否为空的时候
# QuerySet的缓存
# 什么时候不缓存
# 只执行查询集的一部分
# 简单的打印不换车:Q = News.objects.all() print(Q[1]) # 不会被缓存 ############## 重要 end #################
news_queryset = News.objects.values('id', 'title', 'digest', 'image_url', 'update_time').annotate(
tag_name=F('tag__name'), author=F('author__username')) # 3.过滤
# if tag_id:
# news = news_queryset.fileter(is_delete=False, tag_id=tag_id)
# else:
# news = news_queryset.fileter(is_delete=False)
news = news_queryset.filter(is_delete=False, tag_id=tag_id) or news_queryset.filter(is_delete=False)
# 4.分页
paginator = Paginator(news, constants.PER_PAGE_NEWS_COUNT) # 见下文讲解
# 获取当前页数据 get_page 可以容错
news_info = paginator.get_page(page)
# 5.返回数据
data = {
'total_pages': paginator.num_pages, # 分了多少页
'news':list(news_info)
}
return json_response(data=data)

paginator(分页器)方法:

Paginator.get_page(number)此方法为2.0新方法。

返回Page具有给定的从1开始的索引对象,同时还处理超出范围和无效页码,如果页码不是数字,则返回第一页。如果页码为负数或大于页数,则返回最后一页。

# 2.分页解析
paginator = Paginator(docs, 5) # 每5份内容分页一次
# 2.2 拿到前段发送过来的page这个查询参数的值
page = paginator.get_page(request.GET.get('page',1))
# request.GET.get('page',1) 获取url参数,127.0.0.1:8000/?page=<value>
# 非法数值则返回1 数值为空也返回1 如 127.0.0.1:8000/?page=asdsa
# 获取当前(页码)所需要的文章列表 相当于一个容器

因为json默认不支持datetime类型数据,所以自定义json编码器(既让新闻的时间序列化)

# 在utils/json_res.py文件中添加自定义的json编码器以便能够序列化datetime数据类型
import json
import datetime
from django.http import JsonResponse from .res_code import Code # json编码器
# 自定义序列化器1,处理时间字段(老一点的版本这个就会报错)
#class MyJSONEncoder(json.JSONEncoder):
# def default(self, o):
# if isinstance(o, datetime.datetime):
# return o.astimezone().strftime('%Y-%m-%d %H:%M:%S') # 转换为本地时间 # 自定义序列化器2,处理时间字段(2.1.10django版本 DjangoJSONEncoder能够帮我们自动的实现)
class MyJSONEncoder(DjangoJSONEncoder):
def default(self, o):
if isinstance(o, datetime.datetime):
return o.astimezone().strftime('%Y-%m-%d %H:%M:%S') # 转换为本地时间 def json_response(errno=Code.OK, errmsg='', data=None, kwargs=None):
json_dict = {
'errno': errno,
'errmsg': errmsg,
'data': data
}
if kwargs and isinstance(kwargs, dict) :
json_dict.update(kwargs) return JsonResponse(json_dict, encoder=MyJSONEncoder)

定义常量

# 在news目录下constants.py中定义如下常量:

# 每页新闻数
PER_PAGE_NEWS_COUNT = 5

路由配置

from django.urls import path
from . import views
# url的命名空间
app_name = 'news' urlpatterns = [
path('', views.index, name='index'), # 将这条路由命名为index
path('news/', views.NewsListView.as_view(), name='news_list')
]

4.前端代码

前端html页面代码修改

<!-- news-contain start 清空 ul中的内容 -->
<div class="news-contain">
<ul class="news-list"> </ul>
</div>
<!-- news-contain end -->

js代码

// static/js/news/index.js
$(function () {
// 新闻列表
let $newNavLi = $('.news-nav ul li'); // 标签li
let iPage = 1; // 默认第一页
let iTotalPage = 1; // 默认总页数为1
let iCurrentTagId = 0; // 默认分类标签为0
let bIsLoadData = true; // 是否正在向后台加载数据 fn_load_content(); // 点击分类标签
$newNavLi.click(function () {
// 点击分类标签,则为点击的标签加上一个active的class属性
// 并移除其他兄弟元素上的active的class属性
$(this).addClass('active').siblings('li').removeClass('active');
// 获取绑定在data-id属性上的tag_id
let iClickTagId = $(this).children('a').attr('data-id');
if (iClickTagId !== iCurrentTagId){
iCurrentTagId = iClickTagId; // 记录当前分类id
// 重置分页参数
iPage = 1;
iTotalPage = 1;
fn_load_content()
} }); // 页面滚动加载
$(window).scroll(function () {
// 浏览器窗口高度
let showHeigtht = $(window).height();
// 整个网页高度
let pageHeight = $(document).height();
//页面可以滚动的距离
let canScrollHeight = pageHeight - showHeigtht;
// 页面滚动了多少, 整个是随着页面滚动实时变化的
let nowScroll = $(document).scrollTop();
if ((canScrollHeight - nowScroll) < 100){
if(!bIsLoadData){
bIsLoadData = true;
//判断页数,去更新新闻,小于总数才加载
if(iPage < iTotalPage){
iPage += 1;
fn_load_content(); }else {
message.showInfo('已全部加载,没有更多内容!');
$('a.btn-more').html('已全部加载,没有更多内容!')
} }
}
}); // 向后端获取新闻列表数据
function fn_load_content() {
$.ajax({
url: '/news/',
type: 'GET',
data:{
tag: iCurrentTagId,
page: iPage
},
dataType: 'json',
success: function (res) {
if(res.errno === '0'){
iTotalPage = res.data.total_pages;
if(iPage === 1){
// 第一页清空内容
$('.news-list').html('')
}
res.data.news.forEach(function (one_news) {
let content = ` <li class="news-item">
<a href="https://www.shiguangkey.com/course/2432" class="news-thumbnail"
target="_blank">
<img src="${one_news.image_url}" alt="${one_news.title}"
title="${one_news.title}">
</a>
<div class="news-content">
<h4 class="news-title"><a
href="#">${one_news.title}</a>
</h4>
<p class="news-details">${one_news.digest}</p>
<div class="news-other">
<span class="news-type">${one_news.tag_name}</span>
<span class="news-time">${one_news.update_time}</span>
<span class="news-author">${one_news.author}</span>
</div>
</div>
</li>`;
$('.news-list').append(content);
});
// $('.news-list').append($('<a href="javascript:void(0);" class="btn-more">滚动加载更多</a>'));
//数据加载完毕,设置正在加载数据变量为false,表示当前没有加载数据
bIsLoadData = false;
$('a.btn-more').html('滚动加载更多')
}else {
// 加载失败,打印错误信息
message.showError(res.errmsg)
}
},
error: function () {
message.showError('服务器超时,请重试!')
}
});
}
});

五、轮播图功能

1. 接口设计

  1. 接口说明:

类目 说明
请求方法 GET
url定义 /news/banners/
参数格式 无参数

返回结果:

{
"errno": "",
"errmsg": "OK",
"data": {
"banners": [
{
'image_url': '/media/jichujiaochen.jpeg',
'news_id': ,
'news_title': "python 算法快速排序"
},
{
"image_url": "/media/python_advanced.jpg",
"news_id": ,
"news_title": "Python 序列与映射的解包操作"
}
]
}
}

2.后端代码

视图代码

# 在news目录下views.py中创建如下视图
class NewsBannerView(View):
"""
轮播图视图
url:/news/banners/
"""
def get(self, request):
banners = Banner.objects.values('image_url', 'news_id').annotate(
news_title=F('news__title')
).filter(is_delete=False)[:constants.SHOW_BANNER_COUNT]
data = {
'banners': list(banners)
}
return json_response(data=data)

定义常量

# 在news目录下constants.py中定义如下常量
# banner页展示数量
SHOW_BANNER_COUNT = 6

路由

# news目录下urls.py中定义如下路由:
from django.urls import path
from . import views
# url的命名空间
app_name = 'news' urlpatterns = [
path('', views.index, name='index'), # 将这条路由命名为index
path('news/', views.NewsListView.as_view(), name='news_list'),
path('news/banners/', views.NewsBannerView.as_view(), name='news_banner')
]

3.前端代码

html代码

<!-- 修改templates/news/index.html中banner部分的代码如下 -->
<!-- banner start -->
<div class="banner">
<ul class="pic">
<!--淡入淡出banner--> </ul>
<a href="javascript:void(0);" class="btn prev">
<i class="PyWhich py-arrow-left"></i></a>
<a href="javascript:void(0);" class="btn next">
<i class="PyWhich py-arrow-right"></i></a>
<ul class="tab">
<!-- 按钮数量必须和图片一致 --> </ul>
</div>
<!-- banner end -->

js代码

<!-- static/js/news/index.js -->
$(function () {
// 新闻列表
let $newNavLi = $('.news-nav ul li'); // 标签li
let iPage = 1; // 默认第一页
let iTotalPage = 1; // 默认总页数为1
let iCurrentTagId = 0; // 默认分类标签为0
let bIsLoadData = true; // 是否正在向后台加载数据 fn_load_content(); // 点击分类标签
$newNavLi.click(function () {
// 点击分类标签,则为点击的标签加上一个active的class属性
// 并移除其他兄弟元素上的active的class属性
$(this).addClass('active').siblings('li').removeClass('active');
// 获取绑定在data-id属性上的tag_id
let iClickTagId = $(this).children('a').attr('data-id');
if (iClickTagId !== iCurrentTagId){
iCurrentTagId = iClickTagId; // 记录当前分类id
// 重置分页参数
iPage = 1;
iTotalPage = 1;
fn_load_content()
} }); // 页面滚动加载
$(window).scroll(function () {
// 浏览器窗口高度
let showHeigtht = $(window).height();
// 整个网页高度
let pageHeight = $(document).height();
//页面可以滚动的距离
let canScrollHeight = pageHeight - showHeigtht;
// 页面滚动了多少, 整个是随着页面滚动实时变化的
let nowScroll = $(document).scrollTop();
if ((canScrollHeight - nowScroll) < 100){
if(!bIsLoadData){
bIsLoadData = true;
//判断页数,去更新新闻,小于总数才加载
if(iPage < iTotalPage){
iPage += 1;
fn_load_content(); }else {
message.showInfo('已全部加载,没有更多内容!');
$('a.btn-more').html('已全部加载,没有更多内容!')
} }
}
}); // 向后端获取新闻列表数据
function fn_load_content() {
$.ajax({
url: '/news/',
type: 'GET',
data:{
tag: iCurrentTagId,
page: iPage
},
dataType: 'json',
success: function (res) {
if(res.errno === '0'){
iTotalPage = res.data.total_pages;
if(iPage === 1){
// 第一页清空内容
$('.news-list').html('')
}
res.data.news.forEach(function (one_news) {
let content = ` <li class="news-item">
<a href="https://www.shiguangkey.com/course/2432" class="news-thumbnail"
target="_blank">
<img src="${one_news.image_url}" alt="${one_news.title}"
title="${one_news.title}">
</a>
<div class="news-content">
<h4 class="news-title"><a
href="#">${one_news.title}</a>
</h4>
<p class="news-details">${one_news.digest}</p>
<div class="news-other">
<span class="news-type">${one_news.tag_name}</span>
<span class="news-time">${one_news.update_time}</span>
<span class="news-author">${one_news.author}</span>
</div>
</div>
</li>`;
$('.news-list').append(content);
});
// $('.news-list').append($('<a href="javascript:void(0);" class="btn-more">滚动加载更多</a>'));
//数据加载完毕,设置正在加载数据变量为false,表示当前没有加载数据
bIsLoadData = false;
$('a.btn-more').html('滚动加载更多')
}else {
// 加载失败,打印错误信息
message.showError(res.errmsg)
}
},
error: function () {
message.showError('服务器超时,请重试!')
}
}) } // 新闻轮播图功能
// 1.加载轮播图数据 function fn_load_banner()
// 2.点击导航按钮切换 用this的话必须写function()了不能用()=>
// 3.上一页,下一页
// 4.自动切换
// 5.鼠标滑入暂停自动播放 fn_load_banner(); // 先加载banner let $banner = $('.banner'); // banner容器div
let $picLi = $('.banner .pic li'); // 图片li标签
let $pre = $('.banner .prev'); // 上一张
let $next = $('.banner .next'); // 下一张
let $tabLi = $('.banner .tab li'); // 按钮
let index = 0; // 当前索引 // 导航小圆点
$tabLi.click(function () {
index = $(this).index();
$(this).addClass('active').siblings('li').removeClass('active');
$picLi.eq(index).fadeIn(1500).siblings('li').fadeOut(1500);
}); // 点击切换上一张
$pre.click(()=> {
index --;
if(index<0){
index = $tabLi.length - 1 // 最后一张
}
$tabLi.eq(index).addClass('active').siblings('li').removeClass('active');
$picLi.eq(index).fadeIn(1500).siblings('li').fadeOut(1500);
}); // 点击切换下一张
$next.click(()=>{
auto();
}); // 图片向前滑动
function auto() {
index ++;
index %= $tabLi.length;
$tabLi.eq(index).addClass('active').siblings('li').removeClass('active');
$picLi.eq(index).fadeIn(1500).siblings('li').fadeOut(1500) }
// 定时器
let timer = setInterval(auto, 2500);
$banner.hover(
()=>{
clearInterval(timer)
},
()=>{
timer = setInterval(auto, 2500);
}
);
// 定义向后端获取banner的ajax数据
function fn_load_banner() {
$
.ajax({
url: '/news/banners/',
type: 'GET',
async: false, // 同步执行,下面的代码依赖banner的加载
dataType: "json", })
.done( (res)=> {
if(res.errno === '0'){
let content = '';
let tab_content = '';
res.data.banners.forEach( (one_banner, index) =>{
if(index === 0){ // 第一页 加active属性
content = `<li style="display:block;"><a href="/news/${one_banner.news_id}/">
<img src="${one_banner.image_url}" alt="${one_banner.news_title}"></a></li>`;
tab_content = '<li class="active"></li>';
}else {
content = `<li><a href="/news/${one_banner.news_id}/"><img src="${one_banner.image_url}" alt="${one_banner.news_title}"></a></li>`;
tab_content = '<li></li>';
}
$('.pic').append(content);
$('.tab').append(tab_content)
}) }else {
message.showError(res.errmsg)
}
})
.fail(()=>{
message.showError('服务器超时,请重试!')
})
}
});

六、推荐新闻

1. 接口设计

  1. 接口说明:

类目 说明
请求方法 GET
url定义 /
参数格式 无参数

2.返回内容

返回新闻页面,直接在模板渲染

2.后端代码

视图代码

# 修改news/views.py中的index视图
def index(request):
"""
新闻首页视图
url: /
:param request:
:return:
""" tags = Tag.objects.only('id', 'name').filter(is_delete=False) hot_news = HotNews.objects.select_related('news').only('news__title', 'news__image_url', 'news_id').filter(
is_delete=False
).order_by('priority', '-news__clicks')[:constants.SHOW_HOTNEWS_COUNT]
return render(request, 'news/index.html',
context={
'tags': tags,
'hot_news': hot_news
})

定义常量

# 在news/constants.py中定义下面的常量
# 显示热门新闻条数
SHOW_HOTNEWS_COUNT = 3

3.前端代码

html代码

<!-- 修改templates/news/index.html -->
<ul class="recommend-news">
{% for item in hot_news %}
<li>
<a href="https://www.shiguangkey.com/course/2432" target="_blank">
<div class="recommend-thumbnail">
<img src="{{ item.news.image_url }}" alt="title">
</div>
<p class="info">{{ item.news.title }}</p>
</a>
</li>
{% endfor %}
</ul>
<!-- recommend-news end -->

Django项目: 5.新闻主页的更多相关文章

  1. Django项目: 6.新闻详情页

    一.功能需求分析 1.功能 新闻详情 加载评论功能 添加评论功能 二.新闻详情页 1.业务流程分析 业务流程: 判断前端传递新闻id是否为空,是否为整数,是否存在 2.接口设计 接口说明: 类目 说明 ...

  2. Django项目实践4 - Django网站管理(后台管理员)

    http://blog.csdn.net/pipisorry/article/details/45079751 上篇:Django项目实践3 - Django模型 Introduction 对于某一类 ...

  3. Django项目实践4 - Django站点管理(后台管理员)

    http://blog.csdn.net/pipisorry/article/details/45079751 上篇:Django项目实践3 - Django模型 Introduction 对于某一类 ...

  4. 潭州课堂25班:Ph201805201 django 项目 第五课 静态页面转为模板 (课堂笔记)

    一.分析静态页面   1.静态vs动态 条目 静态页面 动态页面 网站内容 固定不变 经常变动 浏览器加载速度 更快(无需向服务器发起请求) 更慢 改变网站内容 很难(修改或者创建新的html页面) ...

  5. 使用uWSGI+nginx部署Django项目

    最近使用django写了一些项目,不过部署到服务器上碰到一些问题,还有静态文件什么的一堆问题,这里总结一下碰到的问题和解决方案,总体思路是按照官方文档走的. 原文地址:http://uwsgi-doc ...

  6. django项目环境搭建

    本文转载自: https://blog.csdn.net/xiaogeldx/article/details/89038299 在码云平台创建项目 版本控制的种类 主要使用github(最主流) 国内 ...

  7. Django项目及应用的创建

    一.url解释 1url是全球资源定位符,网上的每个文件都有唯一的url地址,组成:协议.服务器名称(或IP地址).路径和文件名. 2有时候,URL以斜杠“/”结尾,而没有给出文件名,在这种情况下,U ...

  8. 第一个Django项目

    安装 pip install Django==2.0.5 命令行下创建Django项目 django-admin startproject first_project # 创建项目 cd first_ ...

  9. Nginx + uWSGI 部署Django 项目,并实现负载均衡

    一.uWSGI服务器 uWSGI是一个Web服务器,它实现了WSGI协议.uwsgi.http等协议.Nginx中HttpUwsgiModule的作用是与uWSGI服务器进行交换. 要注意 WSGI ...

随机推荐

  1. STM32F4X 关于MDK上虚拟串口调试

    1. 下载安装VSPD 自行百度安装后,利用VSPD将PC上的两个虚拟串口连接起来.如图我将COM1 和COM2连接起来. a. 点击Addr pair. 可以看到Virtual ports上将两个虚 ...

  2. 如何利用开源思想开发一个SEO友好型网

    如果你有一个网站需要去做SEO优化的时候,不要期望你的努力能立即得到回报.耐心等待并更正内容营销策略,最终会发现你的网站很受用户欢迎.下面就教你如何利用开源思维开发一个SEO友好型网站! 首先,你应该 ...

  3. python基础语法(数据类型转换)

  4. typeerror: __init__() missing 2 required positional arguments: 'inputs' and 'outputs'

    1 问题描述 使用下边这条命令去检查 TensorFlow Object Detection API是否正确安装: python object_detection\builders\model_bui ...

  5. Linux 通用数据结构说明

    device_driver include/linux/device.h struct device_driver { const char             * name; /* 驱动名称 * ...

  6. Luogu P1039 侦探推理(模拟+枚举)

    P1039 侦探推理 题意 题目描述 明明同学最近迷上了侦探漫画<柯南>并沉醉于推理游戏之中,于是他召集了一群同学玩推理游戏.游戏的内容是这样的,明明的同学们先商量好由其中的一个人充当罪犯 ...

  7. vc 识别移动硬盘 U盘,本地硬盘

    说明:有时候我们在做设备监控的时候,要识别一些链接设备,在使用函数GetDriveType的时候,U盘可以返回DRIVE_REMOVABLE,而本地硬盘硬盘和移动硬盘DRIVE_FIXED,因此还需要 ...

  8. 威胁预警|首现新型RDPMiner挖矿蠕虫 受害主机易被添加恶意账户

    近日,阿里云安全发现一种新型挖矿蠕虫RDPMiner,通过爆破Windows Server 3389端口RDP服务的方式进行挖矿木马传播,致使用户CPU占用率暴涨,机器卡顿,更被创建名为Default ...

  9. Python3.6爬虫+Djiago2.0+Mysql --数据爬取

    1.下载对应版本的python mysql 模块 我的是:pymssql-2.2.0.dev0-cp36-cp36m-win_amd64.whl 2.手动创建table create table gr ...

  10. php日期

    PHP Date() 函数 PHP date() 函数用于格式化时间/日期. 该函数可把时间戳格式化为可读性更好的日期和时间. 时间戳是一个字符序列,表示一定的事件发生的日期/时间. 语法 date( ...