免费课程相关表设计

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. 一张图带你玩转docker

  2. Linux 将文件打包、压缩并分割成指定大小

    打包文件: tar -cvf .tar 分割文件: split -b 3G -d -a .tar .tar. //使用split命令,-b 3G 表示设置每个分割包的大小,单位还是可以k // -d ...

  3. NeoVIM安装使用

    1.What's Neovim Bram Moolenaar 在写 Vim 时还是 90 年代初,至今已经 20 多年 过去了.其中,不仅包含了大量的遗留代码,而且程序的维护.Bug 的 修复.以及新 ...

  4. Java小菜求职记-以前在Dubbo踩的坑,这次全被问到了,这下舒服了

    前传 小林求职记(五)上来就一连串的分布式缓存提问,我有点上头.... 终于,在小林的努力下,获得了王哥公司那边的offer,但是因为薪水没有谈妥,小林又重新进入了求职的旅途,在经历了多次求职过程之后 ...

  5. seo如何发外链

    http://www.wocaoseo.com/thread-228-1-1.html 在做外链方面博主并没有什么太多的经验,做为一位seo,下面武汉seo把自己做外链的大条列出来,都是经过本身实践并 ...

  6. 企业网站SEO如何选择关键词

    http://www.wocaoseo.com/thread-17-1-1.html       企业网站的关键词应该如何去选择?有很多的企业老板在网上某某企业在网上做了一个网站,一天盈利多少后,觉得 ...

  7. AD18 PCB中添加中文字符串显示乱码问题解决

    该问题是由于字符串的自体类型设置问题,AD默认是[stroke],我们点击[TrueType]即可正常显示.PS:AD18搞啥呢,默认显示输入内容不行吗,找半天!!!

  8. LeetCode 95 | 构造出所有二叉搜索树

    今天是LeetCode专题第61篇文章,我们一起来看的是LeetCode95题,Unique Binary Search Trees II(不同的二叉搜索树II). 这道题的官方难度是Medium,点 ...

  9. slua中,绑定lua文件到Monobehavior的一种方法

    slua本身并不提供如何把一个lua文件绑定到一个预制中,就像一个普通的继承自monobehavior的自定义脚本那样,而tolua的框架却采用了拙劣的做法: public class LuaBeha ...

  10. IntPtr to bytes

    byte[] managedArray = new byte[size]; Marshal.Copy(pnt, managedArray, 0, size);