免费课程相关表设计

models的设计

from django.contrib.contenttypes.fields import GenericRelation
class Course(models.Model):
name = models.CharField(verbose_name="课程名", max_length=32)
title = models.CharField(verbose_name="课程简介", max_length=128, null=True, blank=True)
# 存放media文件夹下图片的相对路径:eg: media/python入门.jpeg
image = models.CharField(verbose_name="海报", max_length=64, null=True, blank=True)
# 用户连表查询,不会在数据库中产生字段
price_policy = GenericRelation(to='PricePolicy') def __str__(self):
return self.name
class Meta:
verbose_name_plural = "免费课程" class CourseDetail(models.Model):
level = models.IntegerField(default=1, choices=((0, '初级'), (1, "中级"), (2, "高级")))
movie_url = models.CharField(max_length=64)
info = models.TextField()
course = models.OneToOneField(to='Course', null=True, on_delete=models.SET_NULL, db_constraint=False)
teacher = models.OneToOneField(to='Teacher', null=True, on_delete=models.SET_NULL, db_constraint=False) def __str__(self):
return self.course.name + '的详情'
class Meta:
verbose_name_plural = "免费课程详情" class Teacher(models.Model):
name = models.CharField(max_length=32)
info = models.TextField()
image = models.CharField(max_length=64)
level = models.IntegerField(default=0, choices=((0, '初级讲师'), (1, "金牌讲师"), (2, "特约讲师")))
def __str__(self):
return self.name
class Meta:
verbose_name_plural = "讲师" class DegreeCourse(models.Model):
name = models.CharField(max_length=32)
price_policy = GenericRelation(to='PricePolicy')
def __str__(self):
return self.name
class Meta:
verbose_name_plural = "学位课程" from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey
class PricePolicy(models.Model):
day = models.IntegerField()
price = models.CharField(max_length=8)
object_id = models.IntegerField()
content_type = models.ForeignKey(to=ContentType, null=True)
# 改操作只用于ContentType连表查询,不会产生表字段, 就是关联课程表的对象
model_obj = GenericForeignKey() def __str__(self):
return "%s:(%s天 ¥:%s)" % (self.model_obj.name, self.day, self.price) class Meta:
verbose_name_plural = "价格策略"

前台路由与页面

APP.vue组件

<div id="nav">
<router-link to="/">主页</router-link>
|
<router-link to="/login">登录</router-link>
|
<router-link to="/course">免费课程</router-link>
|
<!-- 在页面中转跳路由传递参数, 传递了params参数,this.$router.params可以拿到这个参数字典 -->
<!--<router-link :to="{'name': 'degree-course', 'params': {'id': 1, 'name': 'owen'}}">学位课程</router-link>-->
<router-link :to="{'name': 'degree-course'}">学位课程</router-link>
</div>

router.js路由配置

# 在views文件夹中建立对应的组件
{
path: '/login',
name: 'login',
component: () => import('./views/Login.vue')
},
{
path: '/course',
name: 'course',
component: () => import('./views/Course.vue')
},
{
path: '/degree-course',
name: 'degree-course',
component: () => import('./views/DegreeCourse.vue')
},
{
path: '/course-detail',
name: 'course-detail',
component: () => import('./views/CourseDetail.vue')
}

项目开发视图与响应的二次封装

响应

# api.utils.py
class ApiResponse:
def __init__(self, status=0, message='ok'):
self.status = status
self.message = message
# 要返回给前台的api字典
@property
def api_dic(self):
return self.__dict__

视图

# 在api应用文件夹下创建包views
# 1.分文件管理不同的视图类,视图类继承ModelViewSet管理一系列视图函数
# 2.在__ini__文件中统一管理到 视图类 # __init__.py
from .Course import CourseView # views文件夹/Course文件/CourseView
from rest_framework.viewsets import ModelViewSet
from rest_framework.response import Response
from api.utils import ApiResponse
from api import models, objectjson class CourseView(ModelViewSet):
def get(self, request, *args, **kwargs):
api_response = ApiResponse()
course_list = models.Course.objects.all()
course_data = objectjson.CourseJson(course_list, many=True).data
api_response.results = course_data
return Response(api_response.api_dic)

免费课程首页展示

main.js配置后台请求根路径

// 后台根接口
Vue.prototype.$base_api = 'http://127.0.0.1:8000/';

views/Course.vue

<template>
<div class="course">
<h2>免费课程</h2>
<!--course_list是从后台获取,有多少条数据,就会渲染多少个子组件CourseView-->
<div v-for="(course,i) in course_list" :key="course.name+i">
<!--通过绑定属性的方式,将course传给属性course,在组件内部提高props=['course']拿到父组件的数据-->
<CourseView :course="course"></CourseView>
</div>
</div>
</template> <script>
import CourseView from "../components/CourseView"; export default {
name: "Course",
data: function () {
return {
course_list: []
}
},
components: {
CourseView: CourseView,
},
mounted: function () {
let _this = this;
this.$ajax({
method: 'get',
url: this.$base_api + 'courses/',
}).then(function (response) {
_this.course_list = response.data.results
})
}
}
</script> <style scoped> </style>

components/CourseView.vue

<template>
<div class="course-view">
<div class="box">
<h3 @click="goDetail(course.id)">{{course.name }}</h3>
<p>{{ course.title }}</p>
</div>
<img @click="goDetail(course.id)" :src="$base_api + course.image" alt="">
</div>
</template> <script>
export default {
name: "CourseView",
props: ['course'],
methods: {
goDetail: function (pk) {
//前往详情页,在方法中,router如何完成路由的跳转
this.$router.push('/course-detail');
// 业务逻辑下,路由转跳携带参数
this.$router.course_id = pk;
window.console.log(pk)
}
}
}
</script> <style scoped>
.course-view {
padding: 0 200px;
margin: 25px 0;
} .course-view .box {
float: left;
width: 380px;
} .course-view img {
width: 400px;
float: left;
} .course-view:after {
display: block;
clear: both;
content: '';
}
</style>

views/Course.vue/CourseDetail.vue

<template>
<div class="course-detail">
<h2>免费课程详情</h2>
<p>{{ detail }}</p>
</div>
</template> <script>
export default {
name: "CourseDetail",
data: function () {
return {
detail: {},
}
},
mounted: function () {
let _this = this;
this.$ajax({
method: 'get',
url: this.$base_api + 'course/' + this.$router.course_id + '/',
}).then(function (response) {
window.console.log(response);
_this.detail = response.data.results;
})
}
}
</script> <style scoped> </style>

前后台登录认证

时区国际化settings.py

TIME_ZONE = 'Asia/Shanghai'
USE_TZ = False

models.py

class User(models.Model):
username = models.CharField(max_length=32)
password = models.CharField(max_length=32) class UserToken(models.Model):
token = models.CharField(max_length=64)
user = models.OneToOneField(to='User', null=True, on_delete=models.SET_NULL, db_constraint=False)
update_time = models.DateTimeField(auto_now=True)
failed_time = models.FloatField(default=10)

objectson.py

class UserJson(serializers.ModelSerializer):
class Meta:
model = models.User
fields = '__all__' class UserTokenJson(serializers.ModelSerializer):
class Meta:
model = models.UserToken
fields = '__all__'

auth.py

from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed from api import models class LoginAuthenticate(BaseAuthentication):
def authenticate(self, request):
token = request.META.get('HTTP_TOKEN')
result = models.UserToken.objects.filter(token=token).first() # type:models.UserToken
if result:
# 最近一次登录的时间
before_time = result.update_time
# 过期时长秒数
failed_time = result.failed_time
# 当你时间往前推演到过期的时长前的最后时刻
import datetime
time_difference = datetime.datetime.now() - datetime.timedelta(seconds=failed_time)
import time
# 存在时区问题,通过国际化解决
before_time_stamp = time.mktime(before_time.timetuple()) # 拿到时间戳
time_difference_stamp = time.mktime(time_difference.timetuple())
if before_time_stamp >= time_difference_stamp:
return result.user, token
raise AuthenticationFailed('登录过期')
else:
raise AuthenticationFailed('认证失败')

前台安装操作cookie的模块

<template>
<div class="login">
<h2>登录页面</h2>
<div class="form">
<el-form :model="form" label-width="100px">
<el-form-item label="用户名">
<el-input v-model="form.username"></el-input>
</el-form-item>
<el-form-item label="密码">
<el-input type="password" v-model="form.password" autocomplete="off"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">登录</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template> <script>
export default {
name: "Login",
data: function () {
return {
form: {
username: '',
password: '',
}
}
},
methods: {
onSubmit() {
// window.console.log('aaaa');
let _this = this;
this.$ajax({
method: 'post',
url: this.$base_api + 'login/',
data: {
username: this.form.username,
password: this.form.password
}
}).then(function (response) {
window.console.log(response);
let token = response.data.token;
_this.$cookie.set('token', token);
_this.$router.push('/')
})
}
}
}
</script> <style scoped> </style>

router.js

{
path: '/login',
name: 'login',
component: () => import('./views/Login.vue')
},

登录、认证、token处理、前台cookie存储token的更多相关文章

  1. app与php后台接口登录认证、验证(seesion和token)

    简要:随着电商的不断发展,APP也层次不穷,随着科技的发展主要登录形式(微信.QQ.账号/密码):为此向大家分享一下"app与php后台接口登录认证.验证"想法和做法:希望能够帮助 ...

  2. 如何区别cookie和token?---测试cookie和token接口时先看。

    cookie 是什么? cookie--------------在浏览器中的长相?火狐浏览器 ----------------------------------------------------- ...

  3. cookie session token详解

    cookie session token详解 转自:http://www.cnblogs.com/moyand/ 发展史 1.很久很久以前,Web 基本上就是文档的浏览而已, 既然是浏览,作为服务器, ...

  4. Cookie、Token与Session介绍(非原创)

    文章大纲 一.Cookie介绍二.Token介绍三.Session介绍四.Token.Cookie与Session比较五.参考文章   一.Cookie介绍 1. Cookie是什么 cookie机制 ...

  5. cookie,session,token介绍

    本文目录 发展史 Cookie Session Token 回到目录 发展史 1.很久很久以前,Web 基本上就是文档的浏览而已, 既然是浏览,作为服务器, 不需要记录谁在某一段时间里都浏览了什么文档 ...

  6. cookie,session,token的理解

    Get  POST 区别异同点 淘宝token的 理解   过程算法 防止伪造请求  伪造相对难 简单发展史  登录的操作: 哪些人往自己的购物车中放商品,  也就是说我必须把每个人区分开,这就是一个 ...

  7. session、cookie、token

    各自应用场景考虑session.token.cookie是不是有各自的应用场景,比如传统项目适合用session和cookie单页应用适合用token分布式适合用token等等 token如果非要选择 ...

  8. 基于JWT的Token登录认证(一)

    1.JWT简介 JSON Web Token(缩写 JWT),是目前最流行的跨域认证解决方案. session登录认证方案:用户从客户端传递用户名.密码等信息,服务端认证后将信息存储在session中 ...

  9. 权限认证 cookie VS token

    权限认证 cookie VS token 我前公司的应用都是 token 授权的,现公司都是维护一个 session 确认登录状态的.那么我在这掰扯掰扯这两种权限认证的方方面面. 工作流程 先说 co ...

随机推荐

  1. 原生js实现 vue的数据双向绑定

    原生js实现一个简单的vue的数据双向绑定 vue是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时 ...

  2. SpringBoot+MyBatis整合报错Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required

    项目启动的时候报这个错误,这个问题我百度了一天,果然不出意外的还是没能解决,其中有一篇文章相对来说还是有点用的:https://blog.csdn.net/qq8693/article/details ...

  3. Golang omitempty 的用法

    原文链接:https://blog.csdn.net/skh2015java/article/details/90720692omitempty作用是在json数据结构转换时,当该字段的值为该字段类型 ...

  4. RCON 服务器命令协议

    介绍 编辑 RCON是一种允许服务器管理员远程执行Minecraft命令的协议.在1.9pre4中引入,它基本上是Minecraft的Source RCON协议的实现. 格式 编辑 响应将使用您发送的 ...

  5. 大牛浅谈Web测试基于实际测试的功能测试点总结

    今天跟大家讲解的是web测试在实际测试的功能测试点的一些小总结,希望对你们有帮助,有说的不好的地方,还请多多指教! 一.页面链接检查:测试每一个链接是否都有对应的页面,并且页面之前可以正确切换.   ...

  6. SQL分词器1.10版

    处理SQL及分词效果: select * from ( select rownum as rn,tb1.stuid,tb1.summary from ( select stuid,sum(score) ...

  7. 转载:51cto 2019好文精选

    转载地址:https://news.51cto.com/art/202001/609544.htm 01.知识科普 傻瓜都能看懂,30张图彻底理解红黑树! TCP三次握手,四次挥手,你真的懂吗? 面试 ...

  8. JVM-虚拟机执行子系统

    类的加载由JVM执行引擎来完成 早期--编译期:源代码文件*.java -> 词法分析器 -> tokens流 -> 语法分析器 -> 语法树/抽象语法树 -> 语义分析 ...

  9. 为什么互联网巨头们纷纷使用Git而放弃SVN?(内含Git核心命令与原理总结)

    写在前面 最近发现很多小伙伴对于工作中的一些基本工具的使用还不是很了解,比如:Git这个分布式的代码管理仓库,很多小伙伴就不是很了解,或者说不是很熟悉.甚至有些小伙伴都没听说过Git,就只会用个SVN ...

  10. python中使用mock模块返回数据

    mock是辅助单元测试的一个模块.它允许您用模拟对象替换您的系统的部分,并对它们已使用的方式进行断言. mock在python3中已经被集成到了unittest单元测试框架中,所以,可以直接使用. m ...