一、功能需求分析

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. PAT甲级——A1125 Chain the Ropes【25】

    Given some segments of rope, you are supposed to chain them into one rope. Each time you may only fo ...

  2. QT之QStatusBar

    1.QStatusBar一般处于主窗体(QMainWindow)的左下角用于显示比较重要的状态信息.我们通常调用其showMessage()函数 QT官方显示:[slot] void QStatusB ...

  3. 普及组R4

    T3 链接:C 输入一个长度为n的数组a[i],下标从0开始(0到n-1) 保证n是2的整数次幂, 对于每个i (0 <= i < n) 求所有满足((i & j) == j)的a ...

  4. C# 中的三个高级参数 params

    params params 关键字可以指定采用数目可变的参数的方法参数. 可以发送参数声明中所指定类型的逗号分隔的参数列表或指定类型的参数数组. 还可以不发送参数. 在方法声明中的 params 关键 ...

  5. C#窗体代码相关笔记

    获取ComboBox下拉列表的所有选项值 ArrayList al = new ArrayList(); foreach (string item in this.comboBox2.Items) { ...

  6. Idea 2018.2.5创建springboot项目依赖包没有的错误

  7. (转)线程池 ExecutorService 详细介绍以及注意点区别

    线程池 ExecutorService 相信java开发都用到,这里做个简单笔记 一 Java通过Executors提供四种线程池,分别为: newCachedThreadPool创建一个可缓存线程池 ...

  8. 「题解」:[AHOI2013]作业

    问题: 作业 时间限制: 10 Sec  内存限制: 512 MB 题面 题目描述 此时己是凌晨两点,刚刚做了Codeforces的小A掏出了英语试卷.英语作业其实不算多,一个小时刚好可以做完.然后是 ...

  9. zabbix--------配置邮件报警功能---服务器上配置---------

    --------配置邮件报警功能---服务器上配置--------- [www.aa.com@ ~]# yum install mailx -y [www.aa.com@ ~]# vi /etc/ma ...

  10. js获取base64格式图片预览上传并用php保存到本地服务器指定文件夹

    html: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF ...