日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

python 全栈开发,Day104(DRF用户认证,结算中心,django-redis)

發布時間:2024/3/13 python 62 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python 全栈开发,Day104(DRF用户认证,结算中心,django-redis) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

python 全棧開發,Day104(DRF用戶認證,結算中心,django-redis)

考試第二部分:MySQL數據庫

6.? MySQL中char和varchar的區別(1分)

char是定長,varchar是變長。 char的查詢速度比varchar要快。 View Code

?

7.? ?MySQL中varchar(50)的50表示什什么意思?(1分)

是字符長度。一個中文,也是一個字符。 View Code

?

8. left join、right join以及inner join的區別?(2分)

left join,表示左連接,以左表為基準,如果左表有不匹配的,顯示為空 right join,表示右連接,以右表為基準,如果右表有不匹配的,顯示為空 inner join,表示內連接,只顯示2個表條件符合的記錄,不匹配的不顯示 View Code

?

9. MySQL組合索引(2分)
where?子句句中有a、b、c 三個查詢條件,創建?一個組合索引 abc(a,b,c),那么如下那中情況會命 中索引:
a. where (a)
b. where (b)
c. where (c)
d. where (a,b)
e. where (b,c)
f. where (a,c)
g. where (a,b,c)

a,d,f,g 會命中索引 View Code

解釋:

索引有2個功能:加快查詢和約束。

這里的約束指的是唯一索引,聯合唯一索引。

索引遵循的原則: 最左前綴原則

你可以認為聯合索引是闖關游戲的設計例如你這個聯合索引是state/city/zipCode那么state就是第一關 city是第二關, zipCode就是第三關你必須匹配了第一關,才能匹配第二關,匹配了第一關和第二關,才能匹配第三關你不能直接到第二關的索引的格式就是第一層是state,第二層才是city索引是因為B+樹結構 所以查找快 如果單看第三列 是非排序的。 多列索引是先按照第一列進行排序,然后在第一列排好序的基礎上再對第二列排序,如果沒有第一列的話,直接訪問第二列,那第二列肯定是無序的,直接訪問后面的列就用不到索引了。 所以如果不是在前面列的基礎上而是但看后面某一列,索引是失效的。 View Code

簡而言之,只要where條件包含最左邊的字段,那么它就會用到組合索引,反之亦然!

如果創建了組合索引,但是卻沒有命中,這是浪費磁盤空間。因為索引也占用磁盤!

?

10. 假設學?生Student和教師Teacher關系模型如下:(4分) Student(學號、姓名、性別、類型、身份證號) Teacher(教師號、姓名、性別、類型、身份證號、工資)
其中,學?生表中類別為“本科生”和“研究生”兩類;性別為“男”和“女”兩類。
a. 性別為女的所有學生。

select * from Student where 性別='' View Code

b. 學生表中類別分別對應的個數。

select 類型,count(1) from Student group by 類型 View Code

c.工資少于10000的女教師的身份證和姓名。

select 身份證,姓名 from Teacher where 性別= '' and 類型='研究生' and 工資 < 10000 View Code

d.? 研究生教師平均工資、最?高和最低工資。

select AVG(工資),MAX(工資),MIN(工資) from Teacher wherer 類型='研究生' View Code

?

11. 根據如下表結構建表:(2分)

CREATE TABLE `t1` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(32) NOT NULL,`balance` decimal(10,2) NOT NULL,PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; View Code

?

12.? ? 根據如下表查詢每個?用戶第?一次下訂單的時間。(2分)

# 第一次下單時間,就是時間最早的 select name,MIN(order_time) from table group by name View Code

?

13. 有?一個訂單系統包含訂單信息、商品信息、價格信息且還要?一些狀態,如何設計表結構(2分)

#最簡單的設計 商品表 - id - 名稱 - 價格 - 描述信息訂單表 - id - 訂單號(唯一) - 商品id - 用戶id用戶表 - id - username - password View Code

?

14. 有如下表:(3分)
products(商品表) columns為 id、name、price
orders(商城訂單表) columns為 id、reservations_id、product_id、quantity(數量量)
reservations(酒店訂單表) columns為 id、user_id、price、created_at

ps:這個一個真實面試題!

應用場景:比如萬達酒店,需要訂購商品,比如紅酒,紅木家具...

?

a. 各個商品的售賣情況,需要字段:商品名、購買總數、商品收?入(單價*數量量)

SELECTproducts. NAME,sum(orders.quantity),products.price * sum(orders.quantity) FROMorders LEFT JOIN products ON products.id = orders.product_id GROUP BYorders.product_id View Code

?

b. 所有用戶在2018-01-01至2018-02-01下單次數、下單金額、商城下單次數、商城下單金額

# 注意:最后的期限要加1天。因為23:59:59也是屬于當天的 SELECTcount(1),sum(reservations.price),sum(orders.quantity),products.price * sum(orders.quantity) FROMreservations LEFT JOIN orders ON orders.reservations_id = reservations.id LEFT JOIN products ON products.id = orders.product_id WHEREreservations.created_at BETWEEN 2018-01-01 AND reservations.created_at '2018-02-02' View Code

?

c. 歷月下單用戶數:下單1次的用戶數、下單2次的用戶數、下單3次及以上的用戶數

# 下單1次的用戶數 select DATE_FORMAT(created_at,'%Y-%m'),user_id,count(1) from reservations group by DATE_FORMAT(created_at,'%Y-%m'),user_id having count(user_id) = 1;# 下單2次的用戶數 select DATE_FORMAT(created_at,'%Y-%m'),user_id,count(1) from reservations group by DATE_FORMAT(created_at,'%Y-%m'),user_id having count(user_id) = 1;# 下單3次及以上的用戶數 select DATE_FORMAT(created_at,'%Y-%m'),user_id,count(1) from reservations group by DATE_FORMAT(created_at,'%Y-%m'),user_id having count(user_id) >= 3; View Code

?

15.? 根據表寫SQL語句句:(5分)

? 查詢所有同學的學號、姓名、班級名稱。(1分)

select student.sid,student.sname,class.caption from student left jon class on class.cid = student.class_id View Code

?

? 查詢沒有學?生的所有班級。(2分)

select class.caption from student left jon class on class.cid = student.class_id where class.cid is null View Code

?

? 查詢有學?生的所有班級的名稱和學數量量。(2分)

select class.caption,count(1) from student left jon class on class.cid = student.class_id View Code

?

一、DRF用戶認證

流程圖

請求到達視圖的時候,需要進行認證。

認證是在中間件之后的。如果一旦認證失敗,則返回信息給用戶

?

啟動項目luffcity,訪問購物車

注意:要啟動redis,否則提示獲取購物車數據失敗

?

添加認證?

購物車需要登錄才能查看,登錄成功后,返回一個token

修改views目錄下的auth.py

from rest_framework.response import Response from rest_framework.views import APIView from rest_framework.viewsets import ViewSetMixin from api import models from api.utils.response import BaseResponse import uuidclass AuthView(ViewSetMixin,APIView):def login(self,request,*args,**kwargs):"""用戶登陸認證:param request::param args::param kwargs::return:"""response = BaseResponse() # 默認狀態try:user = request.data.get('username')pwd = request.data.get('password')# 驗證用戶和密碼obj = models.Account.objects.filter(username=user,password=pwd).first()if not obj:response.code = 10002response.error = '用戶名或密碼錯誤'else:uid = str(uuid.uuid4()) # 生成唯一idresponse.code = 99999response.data = uidexcept Exception as e:response.code = 10005response.error = '操作異常'return Response(response.dict) View Code

請確保已經生成了表api_account,并添加了一條記錄

如果沒有,請參考昨天的文檔!

?

測試用戶和密碼

查看返回結果

?

輸入正確的用戶名和密碼

查看返回結果,返回一個隨機碼。這個就是token

9999表示登錄成功

?

既然token已經生成了,并返回給了客戶端。那么服務器如何驗證客戶端的token是否合法呢?

答案是,服務器需要保存token。推薦加一個有效期,比如微信公眾號的token有效期為8個小時!

增加token表

修改models.py,增加token表

它和用戶表是一對一的關系!

from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation from django.contrib.contenttypes.models import ContentType from django.db.models import Q from django.utils.safestring import mark_safe from django.db import models import hashlib# ######################## 課程相關 ########################class CourseCategory(models.Model):"""課程大類, e.g 前端 后端..."""name = models.CharField(max_length=64, unique=True)def __str__(self):return "%s" % self.nameclass Meta:verbose_name_plural = "01.課程大類"class CourseSubCategory(models.Model):"""課程子類, e.g python linux """category = models.ForeignKey("CourseCategory")name = models.CharField(max_length=64, unique=True)def __str__(self):return "%s" % self.nameclass Meta:verbose_name_plural = "02.課程子類"class DegreeCourse(models.Model):"""學位課程"""name = models.CharField(max_length=128, unique=True)course_img = models.CharField(max_length=255, verbose_name="縮略圖")brief = models.TextField(verbose_name="學位課程簡介", )total_scholarship = models.PositiveIntegerField(verbose_name="總獎學金(貝里)", default=40000) # 2000 2000mentor_compensation_bonus = models.PositiveIntegerField(verbose_name="本課程的導師輔導費用(貝里)", default=15000)period = models.PositiveIntegerField(verbose_name="建議學習周期(days)", default=150) # 為了計算學位獎學金prerequisite = models.TextField(verbose_name="課程先修要求", max_length=1024)teachers = models.ManyToManyField("Teacher", verbose_name="課程講師")# 用于GenericForeignKey反向查詢, 不會生成表字段,切勿刪除# coupon = GenericRelation("Coupon")# 用于GenericForeignKey反向查詢,不會生成表字段,切勿刪除degreecourse_price_policy = GenericRelation("PricePolicy")def __str__(self):return self.nameclass Meta:verbose_name_plural = "03.學位課"class Teacher(models.Model):"""講師、導師表"""name = models.CharField(max_length=32)role_choices = ((0, '講師'), (1, '導師'))role = models.SmallIntegerField(choices=role_choices, default=0)title = models.CharField(max_length=64, verbose_name="職位、職稱")signature = models.CharField(max_length=255, help_text="導師簽名", blank=True, null=True)image = models.CharField(max_length=128)brief = models.TextField(max_length=1024)def __str__(self):return self.nameclass Meta:verbose_name_plural = "04.導師或講師"class Scholarship(models.Model):"""學位課程獎學金"""degree_course = models.ForeignKey("DegreeCourse")time_percent = models.PositiveSmallIntegerField(verbose_name="獎勵檔位(時間百分比)", help_text="只填百分值,如80,代表80%")value = models.PositiveIntegerField(verbose_name="獎學金數額")def __str__(self):return "%s:%s" % (self.degree_course, self.value)class Meta:verbose_name_plural = "05.學位課獎學金"class Course(models.Model):"""專題課/學位課模塊表"""name = models.CharField(max_length=128, unique=True)course_img = models.CharField(max_length=255)sub_category = models.ForeignKey("CourseSubCategory")course_type_choices = ((0, '付費'), (1, 'VIP專享'), (2, '學位課程'))course_type = models.SmallIntegerField(choices=course_type_choices)# 不為空;學位課的某個模塊# 為空;專題課degree_course = models.ForeignKey("DegreeCourse", blank=True, null=True, help_text="若是學位課程,此處關聯學位表")brief = models.TextField(verbose_name="課程概述", max_length=2048)level_choices = ((0, '初級'), (1, '中級'), (2, '高級'))level = models.SmallIntegerField(choices=level_choices, default=1)pub_date = models.DateField(verbose_name="發布日期", blank=True, null=True)period = models.PositiveIntegerField(verbose_name="建議學習周期(days)", default=7) # order = models.IntegerField("課程順序", help_text="從上一個課程數字往后排")attachment_path = models.CharField(max_length=128, verbose_name="課件路徑", blank=True, null=True)status_choices = ((0, '上線'), (1, '下線'), (2, '預上線'))status = models.SmallIntegerField(choices=status_choices, default=0)template_id = models.SmallIntegerField("前端模板id", default=1)coupon = GenericRelation("Coupon")# 用于GenericForeignKey反向查詢,不會生成表字段,切勿刪除price_policy = GenericRelation("PricePolicy")asked_question = GenericRelation("OftenAskedQuestion")def __str__(self):return "%s(%s)" % (self.name, self.get_course_type_display())def save(self, *args, **kwargs):if self.course_type == 2:if not self.degree_course:raise ValueError("學位課程必須關聯對應的學位表")super(Course, self).save(*args, **kwargs)class Meta:verbose_name_plural = "06.專題課或學位課模塊"class CourseDetail(models.Model):"""課程詳情頁內容"""course = models.OneToOneField("Course")hours = models.IntegerField("課時")course_slogan = models.CharField(max_length=125, blank=True, null=True)video_brief_link = models.CharField(verbose_name='課程介紹', max_length=255, blank=True, null=True)why_study = models.TextField(verbose_name="為什么學習這門課程")what_to_study_brief = models.TextField(verbose_name="我將學到哪些內容")career_improvement = models.TextField(verbose_name="此項目如何有助于我的職業生涯")prerequisite = models.TextField(verbose_name="課程先修要求", max_length=1024)recommend_courses = models.ManyToManyField("Course", related_name="recommend_by", blank=True)teachers = models.ManyToManyField("Teacher", verbose_name="課程講師")def __str__(self):return "%s" % self.courseclass Meta:verbose_name_plural = "07.課程或學位模塊詳細"class OftenAskedQuestion(models.Model):"""常見問題"""content_type = models.ForeignKey(ContentType) # 關聯course or degree_courseobject_id = models.PositiveIntegerField()content_object = GenericForeignKey('content_type', 'object_id')question = models.CharField(max_length=255)answer = models.TextField(max_length=1024)def __str__(self):return "%s-%s" % (self.content_object, self.question)class Meta:unique_together = ('content_type', 'object_id', 'question')verbose_name_plural = "08. 常見問題"class CourseOutline(models.Model):"""課程大綱"""course_detail = models.ForeignKey("CourseDetail")title = models.CharField(max_length=128)# 前端顯示順序order = models.PositiveSmallIntegerField(default=1)content = models.TextField("內容", max_length=2048)def __str__(self):return "%s" % self.titleclass Meta:unique_together = ('course_detail', 'title')verbose_name_plural = "09. 課程大綱"class CourseChapter(models.Model):"""課程章節"""course = models.ForeignKey("Course")chapter = models.SmallIntegerField(verbose_name="第幾章", default=1)name = models.CharField(max_length=128)summary = models.TextField(verbose_name="章節介紹", blank=True, null=True)pub_date = models.DateField(verbose_name="發布日期", auto_now_add=True)class Meta:unique_together = ("course", 'chapter')verbose_name_plural = "10. 課程章節"def __str__(self):return "%s:(第%s章)%s" % (self.course, self.chapter, self.name)class CourseSection(models.Model):"""課時目錄"""chapter = models.ForeignKey("CourseChapter")name = models.CharField(max_length=128)order = models.PositiveSmallIntegerField(verbose_name="課時排序", help_text="建議每個課時之間空1至2個值,以備后續插入課時")section_type_choices = ((0, '文檔'), (1, '練習'), (2, '視頻'))section_type = models.SmallIntegerField(default=2, choices=section_type_choices)section_link = models.CharField(max_length=255, blank=True, null=True, help_text="若是video,填vid,若是文檔,填link")video_time = models.CharField(verbose_name="視頻時長", blank=True, null=True, max_length=32) # 僅在前端展示使用pub_date = models.DateTimeField(verbose_name="發布時間", auto_now_add=True)free_trail = models.BooleanField("是否可試看", default=False)class Meta:unique_together = ('chapter', 'section_link')verbose_name_plural = "11. 課時"def __str__(self):return "%s-%s" % (self.chapter, self.name)class Homework(models.Model):chapter = models.ForeignKey("CourseChapter")title = models.CharField(max_length=128, verbose_name="作業題目")order = models.PositiveSmallIntegerField("作業順序", help_text="同一課程的每個作業之前的order值間隔1-2個數")homework_type_choices = ((0, '作業'), (1, '模塊通關考核'))homework_type = models.SmallIntegerField(choices=homework_type_choices, default=0)requirement = models.TextField(max_length=1024, verbose_name="作業需求")threshold = models.TextField(max_length=1024, verbose_name="踩分點")recommend_period = models.PositiveSmallIntegerField("推薦完成周期(天)", default=7)scholarship_value = models.PositiveSmallIntegerField("為該作業分配的獎學金(貝里)")note = models.TextField(blank=True, null=True)enabled = models.BooleanField(default=True, help_text="本作業如果后期不需要了,不想讓學員看到,可以設置為False")class Meta:unique_together = ("chapter", "title")verbose_name_plural = "12. 章節作業"def __str__(self):return "%s - %s" % (self.chapter, self.title)# class CourseReview(models.Model): # """課程評價""" # enrolled_course = models.OneToOneField("EnrolledCourse") # about_teacher = models.FloatField(default=0, verbose_name="講師講解是否清晰") # about_video = models.FloatField(default=0, verbose_name="內容實用") # about_course = models.FloatField(default=0, verbose_name="課程內容通俗易懂") # review = models.TextField(max_length=1024, verbose_name="評價") # disagree_number = models.IntegerField(default=0, verbose_name="踩") # agree_number = models.IntegerField(default=0, verbose_name="贊同數") # tags = models.ManyToManyField("Tags", blank=True, verbose_name="標簽") # date = models.DateTimeField(auto_now_add=True, verbose_name="評價日期") # is_recommend = models.BooleanField("熱評推薦", default=False) # hide = models.BooleanField("不在前端頁面顯示此條評價", default=False) # # def __str__(self): # return "%s-%s" % (self.enrolled_course.course, self.review) # # class Meta: # verbose_name_plural = "13. 課程評價(購買課程后才能評價)" # # # class DegreeCourseReview(models.Model): # """學位課程評價 # 為了以后可以定制單獨的評價內容,所以不與普通課程的評價混在一起,單獨建表 # """ # enrolled_course = models.ForeignKey("EnrolledDegreeCourse") # course = models.ForeignKey("Course", verbose_name="評價學位模塊", blank=True, null=True, # help_text="不填寫即代表評價整個學位課程", limit_choices_to={'course_type': 2}) # about_teacher = models.FloatField(default=0, verbose_name="講師講解是否清晰") # about_video = models.FloatField(default=0, verbose_name="視頻質量") # about_course = models.FloatField(default=0, verbose_name="課程") # review = models.TextField(max_length=1024, verbose_name="評價") # disagree_number = models.IntegerField(default=0, verbose_name="踩") # agree_number = models.IntegerField(default=0, verbose_name="贊同數") # tags = models.ManyToManyField("Tags", blank=True, verbose_name="標簽") # date = models.DateTimeField(auto_now_add=True, verbose_name="評價日期") # is_recommend = models.BooleanField("熱評推薦", default=False) # hide = models.BooleanField("不在前端頁面顯示此條評價", default=False) # # def __str__(self): # return "%s-%s" % (self.enrolled_course, self.review) # # class Meta: # verbose_name_plural = "14. 學位課評價(購買課程后才能評價)"class PricePolicy(models.Model):"""價格與有課程效期表"""content_type = models.ForeignKey(ContentType) # 關聯course or degree_courseobject_id = models.PositiveIntegerField()content_object = GenericForeignKey('content_type', 'object_id')# course = models.ForeignKey("Course")valid_period_choices = ((1, '1天'), (3, '3天'),(7, '1周'), (14, '2周'),(30, '1個月'),(60, '2個月'),(90, '3個月'),(180, '6個月'), (210, '12個月'),(540, '18個月'), (720, '24個月'),)valid_period = models.SmallIntegerField(choices=valid_period_choices)price = models.FloatField()class Meta:unique_together = ("content_type", 'object_id', "valid_period")verbose_name_plural = "15. 價格策略"def __str__(self):return "%s(%s)%s" % (self.content_object, self.get_valid_period_display(), self.price)# ################################### 優惠券相關 #################################class Coupon(models.Model):"""優惠券生成規則"""name = models.CharField(max_length=64, verbose_name="活動名稱")brief = models.TextField(blank=True, null=True, verbose_name="優惠券介紹")coupon_type_choices = ((0, '立減'), (1, '滿減券'), (2, '折扣券'))coupon_type = models.SmallIntegerField(choices=coupon_type_choices, default=0, verbose_name="券類型")money_equivalent_value = models.IntegerField(verbose_name="等值貨幣")off_percent = models.PositiveSmallIntegerField("折扣百分比", help_text="只針對折扣券,例7.9折,寫79", blank=True, null=True)minimum_consume = models.PositiveIntegerField("最低消費", default=0, help_text="僅在滿減券時填寫此字段")content_type = models.ForeignKey(ContentType, blank=True, null=True)object_id = models.PositiveIntegerField("綁定課程", blank=True, null=True, help_text="可以把優惠券跟課程綁定")content_object = GenericForeignKey('content_type', 'object_id')quantity = models.PositiveIntegerField("數量(張)", default=1)open_date = models.DateField("優惠券領取開始時間")close_date = models.DateField("優惠券領取結束時間")valid_begin_date = models.DateField(verbose_name="有效期開始時間", blank=True, null=True)valid_end_date = models.DateField(verbose_name="有效結束時間", blank=True, null=True)# coupon_valid_days = models.PositiveIntegerField(verbose_name="優惠券有效期(天)", blank=True, null=True,# help_text="自券被領時開始算起")date = models.DateTimeField(auto_now_add=True)class Meta:verbose_name_plural = "31. 優惠券生成記錄"def __str__(self):return "%s(%s)" % (self.get_coupon_type_display(), self.name)class CouponRecord(models.Model):"""優惠券發放、消費紀錄"""coupon = models.ForeignKey("Coupon")account = models.ForeignKey("Account", verbose_name="擁有者")number = models.CharField(max_length=64, unique=True)status_choices = ((0, '未使用'), (1, '已使用'), (2, '已過期'))status = models.SmallIntegerField(choices=status_choices, default=0)get_time = models.DateTimeField(verbose_name="領取時間", help_text="用戶領取時間")used_time = models.DateTimeField(blank=True, null=True, verbose_name="使用時間")# order = models.ForeignKey("Order", blank=True, null=True, verbose_name="關聯訂單") # 一個訂單可以有多個優惠券order_id = models.IntegerField(verbose_name='關聯訂單ID')class Meta:verbose_name_plural = "32. 用戶優惠券"def __str__(self):return '%s-%s-%s' % (self.account, self.number, self.status)class Account(models.Model):username = models.CharField("用戶名", max_length=64, unique=True)email = models.EmailField(verbose_name='郵箱',max_length=255,unique=True,blank=True,null=True)password = models.CharField('密碼', max_length=128)class Meta:verbose_name_plural = "33. 用戶表"class UserToken(models.Model):user = models.OneToOneField(to='Account')token = models.CharField(max_length=36)class Meta:verbose_name_plural = "34. token表" View Code

使用2個命令,生成表

python manage.py makemigrations python manage.py migrate

?

修改views目錄下的auth.py,保存token到數據庫中

from rest_framework.response import Response from rest_framework.views import APIView from rest_framework.viewsets import ViewSetMixin from api import models from api.utils.response import BaseResponse import uuidclass AuthView(ViewSetMixin,APIView):def login(self,request,*args,**kwargs):"""用戶登陸認證:param request::param args::param kwargs::return:"""response = BaseResponse() # 默認狀態try:user = request.data.get('username')pwd = request.data.get('password')# 驗證用戶和密碼obj = models.Account.objects.filter(username=user,password=pwd).first()if not obj:response.code = 10002response.error = '用戶名或密碼錯誤'else:uid = str(uuid.uuid4()) # 生成唯一id# 保存到數據庫中,update_or_create表示更新或者創建# user=obj,這個是判斷條件。當條件成立,更新token字段,值為uid# 當條件不成立時,增加一條記錄。注意:增加時,有2個字段,分別是user和tokenmodels.UserToken.objects.update_or_create(user=obj, defaults={'token': uid})response.code = 99999response.data = uidexcept Exception as e:response.code = 10005response.error = '操作異常'return Response(response.dict) View Code

再次發送POST請求,輸入正確的用戶名和密碼

查看表api_usertoken,發現和返回結果是一樣的!

再發送一次

表的數據隨之更新

?

增加認證

不光購物車會用到用戶認證,結算中心也需要用到認證,還有其他的視圖,也同樣需要登錄才能使用。

所以,這個認證類需要放到utils里面

在utils目錄中新建文件auth.py

from rest_framework.authentication import BaseAuthentication from rest_framework.exceptions import AuthenticationFailedfrom api import modelsclass LuffyAuthentication(BaseAuthentication):def authenticate(self, request):"""用戶認證:param request::return:"""# 獲取get參數中的tokentoken = request.query_params.get('token')# 判斷token是否在數據庫中token_obj = models.UserToken.objects.filter(token=token).first()if not token_obj:# 認證失敗raise AuthenticationFailed({'code':1008,'error':'認證失敗'})# 認證成功# return 必須返回2個參數,請參考源碼解析# 這里的token_obj.user,表示UserToken表中的user字段# token_obj就是UserToken表的一條記錄,也就是一個objectreturn (token_obj.user,token_obj) View Code

修改views目錄下的shoppingcart.py,導入utils下的auth模塊

from rest_framework.views import APIView from rest_framework.viewsets import ViewSetMixin from rest_framework.response import Response from api import models from api.utils.response import BaseResponse import json import redis from django.conf import settings from api.utils.auth import LuffyAuthentication# redis連接 CONN = redis.Redis(host=settings.REDIS_SERVER.get('host'),port=settings.REDIS_SERVER.get('port'))# print(settings.REDIS_SERVER.get('host')) SHOPPING_CAR = {}USER_ID = 1 # 用戶id# SHOPPING_CAR = { # 1:{ # 2:{ # 'title':'xxxx', # 'price':1, # 'price_list':[ # {'id':11,}, # {'id':22}, # {'id':33}, # ] # }, # 3:{}, # 5:{} # }, # 2:{}, # 3:{}, # }class ShoppingCartView(ViewSetMixin,APIView):# 開啟認證,指定認證類authentication_classes = [LuffyAuthentication,]def list(self, request, *args, **kwargs):"""查看購物車信息:param request::param args::param kwargs::return:"""ret = {'code':10000,'data':None,'error':None}try:# request.user和request.auth是源碼返回的# 如果自定義認證類返回了一個元組,元組里面有2個值。# 它會覆蓋上面2個值,request.user和request.authprint(request.user) # 認證類返回的第一個值print(request.auth) # 認證類返回的第二個值# 獲取tokenprint('shopping',request.query_params.get('token'))shopping_car_course_list = []# pattern = "shopping_car_%s_*" % (USER_ID,)pattern = "shopping_car_%s_%s" % (USER_ID,'*',)user_key_list = CONN.keys(pattern)for key in user_key_list:temp = {'id': CONN.hget(key, 'id').decode('utf-8'),'name': CONN.hget(key, 'name').decode('utf-8'),'img':CONN.hget(key, 'img').decode('utf-8'),'default_price_id':CONN.hget(key, 'default_price_id').decode('utf-8'),'price_policy_dict': json.loads(CONN.hget(key, 'price_policy_dict').decode('utf-8'))}shopping_car_course_list.append(temp)ret['data'] = shopping_car_course_listexcept Exception as e:# print(e)ret['code'] = 10005ret['error'] = '獲取購物車數據失敗'# print(ret)# print(json.dumps(ret))return Response(ret)def create(self, request, *args, **kwargs):"""加入購物車:param request::param args::param kwargs::return:""""""1. 接受用戶選中的課程ID和價格策略ID2. 判斷合法性- 課程是否存在?- 價格策略是否合法?3. 把商品和價格策略信息放入購物車 SHOPPING_CAR注意:用戶ID=1"""# 1.接受用戶選中的課程ID和價格策略ID"""相關問題:a. 如果讓你編寫一個API程序,你需要先做什么?- 業務需求- 統一數據傳輸格式- 表結構設計- 程序開發b. django restful framework的解析器的parser_classes的作用?根據請求中Content-Type請求頭的值,選擇指定解析對請求體中的數據進行解析。如:請求頭中含有Content-type: application/json 則內部使用的是JSONParser,JSONParser可以自動去請求體request.body中獲取請求數據,然后進行 字節轉字符串、json.loads反序列化;c. 支持多個解析器(一般只是使用JSONParser即可)"""course_id = request.data.get('courseid')policy_id = request.data.get('policyid')# 2. 判斷合法性# - 課程是否存在?# - 價格策略是否合法?# 2.1 課程是否存在?course = models.Course.objects.filter(id=course_id).first()if not course:return Response({'code': 10001, 'error': '課程不存在'})# 2.2 價格策略是否合法?price_policy_queryset = course.price_policy.all()price_policy_dict = {}for item in price_policy_queryset:temp = {'id': item.id,'price': item.price,'valid_period': item.valid_period,'valid_period_display': item.get_valid_period_display()}price_policy_dict[item.id] = tempprint(price_policy_dict,type(price_policy_dict))print(policy_id,type(policy_id))if policy_id not in price_policy_dict:return Response({'code': 10002, 'error': '傻×,價格策略別瞎改'})# 3. 把商品和價格策略信息放入購物車 SHOPPING_CAR"""購物車中要放:課程ID課程名稱課程圖片默認選中的價格策略所有價格策略{shopping_car_1_1:{id:課程IDname:課程名稱img:課程圖片defaut:默認選中的價格策略price_list:所有價格策略},}"""pattern = "shopping_car_%s_%s" % (USER_ID, '*',)keys = CONN.keys(pattern)if keys and len(keys) >= 1000:return Response({'code': 10009, 'error': '購物車東西太多,先去結算再進行購買..'})# key = "shopping_car_%s_%s" %(USER_ID,course_id,)key = "shopping_car_%s_%s" % (USER_ID, course_id,)print(key,'1111111111')CONN.hset(key, 'id', course_id)CONN.hset(key, 'name', course.name)CONN.hset(key, 'img', course.course_img)CONN.hset(key, 'default_price_id', policy_id)CONN.hset(key, 'price_policy_dict', json.dumps(price_policy_dict))CONN.expire(key, 60 * 60 * 24) # 有效期,單位秒。表示一天return Response({'code': 10000, 'data': '購買成功'})def destroy(self,request,*args,**kwargs):"""刪除購物車中的某個課程:param request::param args::param kwargs::return:"""response = BaseResponse()try:# courseid = request.GET.get('courseid')courseid = request.data.get('courseid')print(courseid)# key = "shopping_car_%s_%s" % (USER_ID,courseid)key = "shopping_car_%s_%s" % (USER_ID, courseid,)CONN.delete(key)response.data = '刪除成功'except Exception as e:response.code = 10006response.error = '刪除失敗'return Response(response.dict)def update(self,request,*args,**kwargs):"""修改用戶選中的價格策略:param request::param args::param kwargs::return:""""""1. 獲取課程ID、要修改的價格策略ID2. 校驗合法性(去redis中)"""response = BaseResponse()try:course_id = request.data.get('courseid')policy_id = str(request.data.get('policyid')) if request.data.get('policyid') else None# key = 'shopping_car_%s_%s' %(USER_ID,course_id,)key = "shopping_car_%s_%s" % (USER_ID, course_id,)if not CONN.exists(key):response.code = 10007response.error = '課程不存在'return Response(response.dict)price_policy_dict = json.loads(CONN.hget(key, 'price_policy_dict').decode('utf-8'))if policy_id not in price_policy_dict:response.code = 10008response.error = '價格策略不存在'return Response(response.dict)CONN.hset(key,'default_price_id',policy_id)CONN.expire(key, 20 * 60) # 有效期20分鐘response.data = '修改成功'except Exception as e:response.code = 10009response.error = '修改失敗'return Response(response.dict) View Code

參數說明:

CONN.expire 表示設置有效期,單位是秒。60 * 60 * 24,表示一天

?

使用postman,發送get請求

提示認證失敗

發送一個錯誤的token

提示認證失敗!注意:這里直接被認證組件攔截了,并沒有到達視圖

發送一個正確的token,從數據庫里面copy一下

返回code為10000,表示認證成功!

?查看Pycharm控制臺輸出:

Account object UserToken object shopping c8aa8609-fb14-43ea-a6cf-96b2c2469b01

上面2個值,就被自定義類覆蓋了!

?

既然得到了用戶對象,那么常量USER_ID就可以刪除了

修改shoppingcart.py

from rest_framework.views import APIView from rest_framework.viewsets import ViewSetMixin from rest_framework.response import Response from api import models from api.utils.response import BaseResponse import json import redis from django.conf import settings from api.utils.auth import LuffyAuthentication# redis連接 CONN = redis.Redis(host=settings.REDIS_SERVER.get('host'),port=settings.REDIS_SERVER.get('port'))class ShoppingCartView(ViewSetMixin,APIView):# 開啟認證,指定認證類authentication_classes = [LuffyAuthentication,]def list(self, request, *args, **kwargs):"""查看購物車信息:param request::param args::param kwargs::return:"""ret = {'code':10000,'data':None,'error':None}try:# request.user和request.auth是源碼返回的# 如果自定義認證類返回了一個元組,元組里面有2個值。# 它會覆蓋上面2個值,request.user和request.authprint(request.user) # 認證類返回的第一個值print(request.auth) # 認證類返回的第二個值# 獲取tokenprint('shopping',request.query_params.get('token'))shopping_car_course_list = []# pattern = "shopping_car_%s_*" % (request.user.id,)pattern = "shopping_car_%s_%s" % (request.user.id,'*',)user_key_list = CONN.keys(pattern)for key in user_key_list:temp = {'id': CONN.hget(key, 'id').decode('utf-8'),'name': CONN.hget(key, 'name').decode('utf-8'),'img':CONN.hget(key, 'img').decode('utf-8'),'default_price_id':CONN.hget(key, 'default_price_id').decode('utf-8'),'price_policy_dict': json.loads(CONN.hget(key, 'price_policy_dict').decode('utf-8'))}shopping_car_course_list.append(temp)ret['data'] = shopping_car_course_listexcept Exception as e:# print(e)ret['code'] = 10005ret['error'] = '獲取購物車數據失敗'# print(ret)# print(json.dumps(ret))return Response(ret)def create(self, request, *args, **kwargs):"""加入購物車:param request::param args::param kwargs::return:""""""1. 接受用戶選中的課程ID和價格策略ID2. 判斷合法性- 課程是否存在?- 價格策略是否合法?3. 把商品和價格策略信息放入購物車 SHOPPING_CAR注意:用戶ID=1"""# 1.接受用戶選中的課程ID和價格策略ID"""相關問題:a. 如果讓你編寫一個API程序,你需要先做什么?- 業務需求- 統一數據傳輸格式- 表結構設計- 程序開發b. django restful framework的解析器的parser_classes的作用?根據請求中Content-Type請求頭的值,選擇指定解析對請求體中的數據進行解析。如:請求頭中含有Content-type: application/json 則內部使用的是JSONParser,JSONParser可以自動去請求體request.body中獲取請求數據,然后進行 字節轉字符串、json.loads反序列化;c. 支持多個解析器(一般只是使用JSONParser即可)"""course_id = request.data.get('courseid')policy_id = request.data.get('policyid')# 2. 判斷合法性# - 課程是否存在?# - 價格策略是否合法?# 2.1 課程是否存在?course = models.Course.objects.filter(id=course_id).first()if not course:return Response({'code': 10001, 'error': '課程不存在'})# 2.2 價格策略是否合法?price_policy_queryset = course.price_policy.all()price_policy_dict = {}for item in price_policy_queryset:temp = {'id': item.id,'price': item.price,'valid_period': item.valid_period,'valid_period_display': item.get_valid_period_display()}price_policy_dict[item.id] = tempprint(price_policy_dict,type(price_policy_dict))print(policy_id,type(policy_id))if policy_id not in price_policy_dict:return Response({'code': 10002, 'error': '傻×,價格策略別瞎改'})# 3. 把商品和價格策略信息放入購物車 SHOPPING_CAR"""購物車中要放:課程ID課程名稱課程圖片默認選中的價格策略所有價格策略{shopping_car_1_1:{id:課程IDname:課程名稱img:課程圖片defaut:默認選中的價格策略price_list:所有價格策略},}"""pattern = "shopping_car_%s_%s" % (request.user.id, '*',)keys = CONN.keys(pattern)if keys and len(keys) >= 1000:return Response({'code': 10009, 'error': '購物車東西太多,先去結算再進行購買..'})# key = "shopping_car_%s_%s" %(request.user.id,course_id,)key = "shopping_car_%s_%s" % (request.user.id, course_id,)print(key,'1111111111')CONN.hset(key, 'id', course_id)CONN.hset(key, 'name', course.name)CONN.hset(key, 'img', course.course_img)CONN.hset(key, 'default_price_id', policy_id)CONN.hset(key, 'price_policy_dict', json.dumps(price_policy_dict))CONN.expire(key, 60 * 12 * 24) # 有效期return Response({'code': 10000, 'data': '購買成功'})def destroy(self,request,*args,**kwargs):"""刪除購物車中的某個課程:param request::param args::param kwargs::return:"""response = BaseResponse()try:# courseid = request.GET.get('courseid')courseid = request.data.get('courseid')print(courseid)# key = "shopping_car_%s_%s" % (request.user.id,courseid)key = "shopping_car_%s_%s" % (request.user.id, courseid,)CONN.delete(key)response.data = '刪除成功'except Exception as e:response.code = 10006response.error = '刪除失敗'return Response(response.dict)def update(self,request,*args,**kwargs):"""修改用戶選中的價格策略:param request::param args::param kwargs::return:""""""1. 獲取課程ID、要修改的價格策略ID2. 校驗合法性(去redis中)"""response = BaseResponse()try:course_id = request.data.get('courseid')policy_id = str(request.data.get('policyid')) if request.data.get('policyid') else None# key = 'shopping_car_%s_%s' %(request.user.id,course_id,)key = "shopping_car_%s_%s" % (request.user.id, course_id,)if not CONN.exists(key):response.code = 10007response.error = '課程不存在'return Response(response.dict)price_policy_dict = json.loads(CONN.hget(key, 'price_policy_dict').decode('utf-8'))if policy_id not in price_policy_dict:response.code = 10008response.error = '價格策略不存在'return Response(response.dict)CONN.hset(key,'default_price_id',policy_id)CONN.expire(key, 20 * 60)response.data = '修改成功'except Exception as e:response.code = 10009response.error = '修改失敗'return Response(response.dict) View Code

測試get請求

?

全局配置

假設有100個類,有98個視圖要認證。可以加到全局里面,修改settings.py

REST_FRAMEWORK = {'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.URLPathVersioning','VERSION_PARAM':'version','DEFAULT_VERSION':'v1','ALLOWED_VERSIONS':['v1','v2'],'PAGE_SIZE':20,'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination','DEFAULT_AUTHENTICATION_CLASSES':['api.utils.auth.LuffyAuthentication',] } View Code

?

那么登錄和查看課程,是不需要認證的。怎么忽略呢?

修改views目錄下的auth.py,定義認證類為空列表,表示不認證!

from rest_framework.response import Response from rest_framework.views import APIView from rest_framework.viewsets import ViewSetMixin from api import models from api.utils.response import BaseResponse import uuidclass AuthView(ViewSetMixin,APIView):authentication_classes = [] # 空列表表示不認證def login(self,request,*args,**kwargs):"""用戶登陸認證:param request::param args::param kwargs::return:"""response = BaseResponse() # 默認狀態try:user = request.data.get('username')pwd = request.data.get('password')# 驗證用戶和密碼obj = models.Account.objects.filter(username=user,password=pwd).first()if not obj:response.code = 10002response.error = '用戶名或密碼錯誤'else:uid = str(uuid.uuid4()) # 生成唯一id# 保存到數據庫中,update_or_create表示更新或者創建# user=obj,這個是判斷條件。當條件成立,更新token字段,值為uid# 當條件不成立時,增加一條記錄。注意:增加時,有2個字段,分別是user和tokenmodels.UserToken.objects.update_or_create(user=obj, defaults={'token': uid})response.code = 99999response.data = uidexcept Exception as e:response.code = 10005response.error = '操作異常'return Response(response.dict) View Code

使用postman測試登錄

查看返回結果

?

修改settings.py,注釋掉全局認證。因為這里用到的登錄認證的視圖不多

REST_FRAMEWORK = {'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.URLPathVersioning','VERSION_PARAM':'version','DEFAULT_VERSION':'v1','ALLOWED_VERSIONS':['v1','v2'],'PAGE_SIZE':20,'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',# 'DEFAULT_AUTHENTICATION_CLASSES':['api.utils.auth.LuffyAuthentication',] } View Code

?

問題:認證類為什么要繼承BaseAuthentication?

查看源碼BaseAuthentication

class BaseAuthentication(object):"""All authentication classes should extend BaseAuthentication."""def authenticate(self, request):"""Authenticate the request and return a two-tuple of (user, token)."""raise NotImplementedError(".authenticate() must be overridden.")def authenticate_header(self, request):"""Return a string to be used as the value of the `WWW-Authenticate`header in a `401 Unauthenticated` response, or `None` if theauthentication scheme should return `403 Permission Denied` responses."""pass View Code

發現,只要執行了authenticate方法,它會執行raise。它會主動報錯

為了不讓它報錯,子類繼承BaseAuthentication后,必須重寫authenticate方法,才不會報錯。

這樣做的目的,是為了約束子類,哪些方法,必須要定義!

?

二、結算中心

?

點擊去結算,會發送一次post請求。那么它該發送什么數據呢?

只需要發送課程id就可以了?為什么呢?
因為redis中有購物車相關數據!后臺根據課程id去購物車中獲取,要結算的課程就可以了!

結算中心和購物車一樣,也是一個臨時數據。它也需要放到redis中!

先來看購物車的數據結構

購物車 = {'shopping_car_1_3':{name:'',src:'xx'price_id:1,price_dict = {1:....}},'shopping_car_1_1':{...},'shopping_car_1_5':{...},} View Code

再來看結算中新的數據結構

結算中心 = {'payment_1_3':{id:3,mame:Django框架學習,price_id:1,price_priod:30,price:199,defaul_coupon_id:0,coupon_dict: { ----> 綁定了課程3的優惠券0: '請選擇課程優惠券',1:'xxx',2:'xxx',3:'xxx',4:'xxx',}},'payment_1_1':{id:1,mame:Django框架學習,price_id:1,price_priod:30,price:199,defaul_coupon_id:0,coupon_dict: { ----> 綁定了課程1的優惠券0: '請選擇課程優惠券',1:'xxx',2:'xxx',3:'xxx',4:'xxx',}}, } View Code

?

優惠券

優惠券分為2大類:綁定課程和非綁定課程

?

點擊去結算

在左下角,展示的是非綁定課程的優惠券。

在右邊的下拉菜單中,展示的是綁定課程的優惠券

?

在views目錄下,創建文件payment.py

import json import redis from django.conf import settings from rest_framework.views import APIView from rest_framework.viewsets import ViewSetMixin from rest_framework.response import Response from api.utils.auth import LuffyAuthentication from api import models from api.utils.response import BaseResponse# redis連接 CONN = redis.Redis(host=settings.REDIS_SERVER.get('host'),port=settings.REDIS_SERVER.get('port'))class PaymentView(ViewSetMixin, APIView):authentication_classes = [LuffyAuthentication, ]def create(self, request, *args, **kwargs):"""在結算中添加課程:param request::param args::param kwargs::return:"""# 1.接受用戶選擇的要結算的課程ID列表# 2.清空當前用戶request.user.id結算中心的數據# key = payment_1*# 3.循環要加入結算中的所有課程ID列表"""for course_id in 用戶提交課程ID列表:3.1 根據course_id,request.user.id去購物車中獲取商品信息:商品名稱、圖片、價格(id,周期,顯示周期,價格)3.2 根據course_id,request.user.id獲取 - 當前用戶- 當前課程- 可用的優惠券加入結算中心提示:可以使用contenttypes"""# 4.獲取當前用戶所有未綁定課程優惠券# - 未使用# - 有效期內# - 加入結算中心:glocal_coupon_用戶IDdef list(self, request, *args, **kwargs):"""查看結算中心:param request::param args::param kwargs::return:"""# 1. 根據用戶ID去結算中心獲取該用戶所有要結算課程# 2. 根據用戶ID去結算中心獲取該用戶所有可用未綁定課程的優惠券# 3. 用戶表中獲取貝里余額# 4. 以上數據構造成一個字典return Response('...')def update(self, request, *args, **kwargs):"""更新優惠券:param request::param args::param kwargs::return:"""# 1. 獲取用戶提交:# course_id=1,coupon_id=3# course_id=0,coupon_id=6# 2. course_id=1 --> 去結算中心獲取當前用戶所擁有的綁定當前課程優惠,并進行校驗# - 成功:defaul_coupon_id=3# - 否則:非法請求# 2. course_id=0 --> 去結算中心獲取當前用戶所擁有的未綁定課程優惠,并進行校驗# - 成功:defaul_coupon_id=3# - 否則:非法請求 View Code

course_id為空,表示 未綁定課程,否則為綁定課程

這里面展示的是一些業務邏輯,需要自己用代碼來填充

提示你的代碼編寫能力!

?

三、django-redis

介紹

django-redis 基于 BSD 許可, 是一個使 Django 支持 Redis cache/session 后端的全功能組件

django-redis 中文文檔,請參考

http://django-redis-chs.readthedocs.io/zh_CN/latest/

為何要用 django-redis ?

因為:

  • 持續更新
  • 本地化的 redis-py URL 符號連接字符串
  • 可擴展客戶端
  • 可擴展解析器
  • 可擴展序列器
  • 默認客戶端主/從支持
  • 完善的測試
  • 已在一些項目的生產環境中作為 cache 和 session 使用
  • 支持永不超時設置
  • 原生進入 redis 客戶端/連接池支持
  • 高可配置 ( 例如仿真緩存的異常行為 )
  • 默認支持 unix 套接字
  • 支持 Python 2.7, 3.4, 3.5 以及 3.6

?

安裝

安裝 django-redis 最簡單的方法就是用 pip :

pip install django-redis

作為 cache backend 使用配置

為了使用 django-redis , 你應該將你的 django cache setting 改成這樣:

CACHES = {"default": {"BACKEND": "django_redis.cache.RedisCache","LOCATION": "redis://127.0.0.1:6379/1","OPTIONS": {"CLIENT_CLASS": "django_redis.client.DefaultClient",}} }

?

舉例:

在上面購物車中,使用了緩存。結算中心也需要使用緩存,那么就可以定義一個全局配置。當需要使用時,導入一下配置即可!

修改settings.py,最后一行添加

# ######django-redis的配置 ################# CACHES = {"default": {"BACKEND": "django_redis.cache.RedisCache","LOCATION": "redis://192.168.218.140:6379","OPTIONS": {"CLIENT_CLASS": "django_redis.client.DefaultClient","CONNECTION_POOL_KWARGS": {"max_connections": 100},# "PASSWORD": "密碼", }} }

參數解釋:

BACKEND 表示后臺連接

OPTIONS 表示參數

CONNECTION_POOL_KWARGS 表示連接池。max_connections表示最大連接數

?

連接池,請參考鏈接:

https://baike.baidu.com/item/%E8%BF%9E%E6%8E%A5%E6%B1%A0%E6%8A%80%E6%9C%AF/523659?fr=aladdin

上面定義了100個連接池,假設100進程,都在使用連接池。當地101個訪問時,會等待。直到有空閑的進程時,才處理!

不過redis的處理是很快的,很少會出現等待的情況!

使用連接池,有很多優點:

1.減少連接創建時間
2.簡化的編程模式
3.受控的資源使用

?

使用連接池,性能會更高好!

視圖中使用

加上2行代碼,就可以了

from django_redis import get_redis_connection CONN = get_redis_connection("default")

這里的default指的是settings.py中CACHES配置項的default

?

修改views目錄下的shoppingcar.py

from rest_framework.views import APIView from rest_framework.viewsets import ViewSetMixin from rest_framework.response import Response from api import models from api.utils.response import BaseResponse import json from api.utils.auth import LuffyAuthentication from django_redis import get_redis_connectionCONN = get_redis_connection("default") # 使用redis連接池class ShoppingCartView(ViewSetMixin,APIView):# 開啟認證,指定認證類authentication_classes = [LuffyAuthentication,]def list(self, request, *args, **kwargs):"""查看購物車信息:param request::param args::param kwargs::return:"""ret = {'code':10000,'data':None,'error':None}try:# request.user和request.auth是源碼返回的# 如果自定義認證類返回了一個元組,元組里面有2個值。# 它會覆蓋上面2個值,request.user和request.authprint(request.user) # 認證類返回的第一個值print(request.auth) # 認證類返回的第二個值# 獲取tokenprint('shopping',request.query_params.get('token'))shopping_car_course_list = []# pattern = "shopping_car_%s_*" % (request.user.id,)pattern = "shopping_car_%s_%s" % (request.user.id,'*',)user_key_list = CONN.keys(pattern)for key in user_key_list:temp = {'id': CONN.hget(key, 'id').decode('utf-8'),'name': CONN.hget(key, 'name').decode('utf-8'),'img':CONN.hget(key, 'img').decode('utf-8'),'default_price_id':CONN.hget(key, 'default_price_id').decode('utf-8'),'price_policy_dict': json.loads(CONN.hget(key, 'price_policy_dict').decode('utf-8'))}shopping_car_course_list.append(temp)ret['data'] = shopping_car_course_listexcept Exception as e:# print(e)ret['code'] = 10005ret['error'] = '獲取購物車數據失敗'# print(ret)# print(json.dumps(ret))return Response(ret)def create(self, request, *args, **kwargs):"""加入購物車:param request::param args::param kwargs::return:""""""1. 接受用戶選中的課程ID和價格策略ID2. 判斷合法性- 課程是否存在?- 價格策略是否合法?3. 把商品和價格策略信息放入購物車 SHOPPING_CAR注意:用戶ID=1"""# 1.接受用戶選中的課程ID和價格策略ID"""相關問題:a. 如果讓你編寫一個API程序,你需要先做什么?- 業務需求- 統一數據傳輸格式- 表結構設計- 程序開發b. django restful framework的解析器的parser_classes的作用?根據請求中Content-Type請求頭的值,選擇指定解析對請求體中的數據進行解析。如:請求頭中含有Content-type: application/json 則內部使用的是JSONParser,JSONParser可以自動去請求體request.body中獲取請求數據,然后進行 字節轉字符串、json.loads反序列化;c. 支持多個解析器(一般只是使用JSONParser即可)"""course_id = request.data.get('courseid')policy_id = request.data.get('policyid')# 2. 判斷合法性# - 課程是否存在?# - 價格策略是否合法?# 2.1 課程是否存在?course = models.Course.objects.filter(id=course_id).first()if not course:return Response({'code': 10001, 'error': '課程不存在'})# 2.2 價格策略是否合法?price_policy_queryset = course.price_policy.all()price_policy_dict = {}for item in price_policy_queryset:temp = {'id': item.id,'price': item.price,'valid_period': item.valid_period,'valid_period_display': item.get_valid_period_display()}price_policy_dict[item.id] = tempprint(price_policy_dict,type(price_policy_dict))print(policy_id,type(policy_id))if policy_id not in price_policy_dict:return Response({'code': 10002, 'error': '傻×,價格策略別瞎改'})# 3. 把商品和價格策略信息放入購物車 SHOPPING_CAR"""購物車中要放:課程ID課程名稱課程圖片默認選中的價格策略所有價格策略{shopping_car_1_1:{id:課程IDname:課程名稱img:課程圖片defaut:默認選中的價格策略price_list:所有價格策略},}"""pattern = "shopping_car_%s_%s" % (request.user.id, '*',)keys = CONN.keys(pattern)if keys and len(keys) >= 1000:return Response({'code': 10009, 'error': '購物車東西太多,先去結算再進行購買..'})# key = "shopping_car_%s_%s" %(request.user.id,course_id,)key = "shopping_car_%s_%s" % (request.user.id, course_id,)print(key,'1111111111')CONN.hset(key, 'id', course_id)CONN.hset(key, 'name', course.name)CONN.hset(key, 'img', course.course_img)CONN.hset(key, 'default_price_id', policy_id)CONN.hset(key, 'price_policy_dict', json.dumps(price_policy_dict))CONN.expire(key, 60 * 12 * 24) # 有效期return Response({'code': 10000, 'data': '購買成功'})def destroy(self,request,*args,**kwargs):"""刪除購物車中的某個課程:param request::param args::param kwargs::return:"""response = BaseResponse()try:# courseid = request.GET.get('courseid')courseid = request.data.get('courseid')print(courseid)# key = "shopping_car_%s_%s" % (request.user.id,courseid)key = "shopping_car_%s_%s" % (request.user.id, courseid,)CONN.delete(key)response.data = '刪除成功'except Exception as e:response.code = 10006response.error = '刪除失敗'return Response(response.dict)def update(self,request,*args,**kwargs):"""修改用戶選中的價格策略:param request::param args::param kwargs::return:""""""1. 獲取課程ID、要修改的價格策略ID2. 校驗合法性(去redis中)"""response = BaseResponse()try:course_id = request.data.get('courseid')policy_id = str(request.data.get('policyid')) if request.data.get('policyid') else None# key = 'shopping_car_%s_%s' %(request.user.id,course_id,)key = "shopping_car_%s_%s" % (request.user.id, course_id,)if not CONN.exists(key):response.code = 10007response.error = '課程不存在'return Response(response.dict)price_policy_dict = json.loads(CONN.hget(key, 'price_policy_dict').decode('utf-8'))if policy_id not in price_policy_dict:response.code = 10008response.error = '價格策略不存在'return Response(response.dict)CONN.hset(key,'default_price_id',policy_id)CONN.expire(key, 20 * 60)response.data = '修改成功'except Exception as e:response.code = 10009response.error = '修改失敗'return Response(response.dict) View Code

使用postman測試訪問,要帶上正確的token

訪問正常

?

作為 session backend 使用配置

Django 默認可以使用任何 cache backend 作為 session backend, 將 django-redis 作為 session 儲存后端不用安裝任何額外的 backend

SESSION_ENGINE = "django.contrib.sessions.backends.cache" SESSION_CACHE_ALIAS = "default"

?

舉例:

修改settings.py

# ######django-redis的配置 ################# CACHES = {"default": {"BACKEND": "django_redis.cache.RedisCache","LOCATION": "redis://192.168.218.140:6379","OPTIONS": {"CLIENT_CLASS": "django_redis.client.DefaultClient","CONNECTION_POOL_KWARGS": {"max_connections": 100},# "PASSWORD": "密碼", }} }###使用redis緩存session SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 引擎 SESSION_CACHE_ALIAS = 'default' # 使用的緩存別名(默認內存緩存,也可以是memcache),此處別名依賴緩存的設置 SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在瀏覽器上時的key,即:sessionid=隨機字符串 SESSION_COOKIE_PATH = "/" # Session的cookie保存的路徑 SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名 SESSION_COOKIE_SECURE = False # 是否Https傳輸cookie SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http傳輸 SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周) SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否關閉瀏覽器使得Session過期 SESSION_SAVE_EVERY_REQUEST = False # 是否每次請求都保存Session,默認修改之后才保存 View Code

簡單來講,加上2行就可以了。下面的那些配置,是參考源碼設置的。

比如session失效時間是2周

如果需要修改,在這里指定一下,就可以了!

注意:里面的defalut就是redis配置的defalut,名字是一一對應的!

?

總結:

1. django-redis的作用- 連接redis并在redis中進行操作(含redis連接池)。2. 幫助用戶將session放到redis- django-redis的配置- session的配置 View Code

?

作業:

完整結算中心的代碼,實現以下功能:

1. 添加

2. 查看

3. 修改

注意:使用認證+django-redis?

?

修改utils目錄下的auth.py

當為GET請求時,從url中取token,否則從請求體中獲取token

from rest_framework.authentication import BaseAuthentication from rest_framework.exceptions import AuthenticationFailedfrom api import modelsclass LuffyAuthentication(BaseAuthentication):def authenticate(self, request):"""用戶認證:param request::return:"""# print(request.method)# 判斷請求方式if request.method == "GET":token = request.query_params.get('token')else:token = request.data.get('token')# print('auth',token)token_obj = models.UserToken.objects.filter(token=token).first()if not token_obj:# 認證失敗raise AuthenticationFailed({'code':1008,'error':'認證失敗'})# 認證成功# return (token_obj.user,token_obj)return (token_obj.user,token_obj) View Code

修改models.py,在用戶表增加字段

from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation from django.contrib.contenttypes.models import ContentType from django.db.models import Q from django.utils.safestring import mark_safe from django.db import models import hashlib# ######################## 課程相關 ########################class CourseCategory(models.Model):"""課程大類, e.g 前端 后端..."""name = models.CharField(max_length=64, unique=True)def __str__(self):return "%s" % self.nameclass Meta:verbose_name_plural = "01.課程大類"class CourseSubCategory(models.Model):"""課程子類, e.g python linux """category = models.ForeignKey("CourseCategory")name = models.CharField(max_length=64, unique=True)def __str__(self):return "%s" % self.nameclass Meta:verbose_name_plural = "02.課程子類"class DegreeCourse(models.Model):"""學位課程"""name = models.CharField(max_length=128, unique=True)course_img = models.CharField(max_length=255, verbose_name="縮略圖")brief = models.TextField(verbose_name="學位課程簡介", )total_scholarship = models.PositiveIntegerField(verbose_name="總獎學金(貝里)", default=40000) # 2000 2000mentor_compensation_bonus = models.PositiveIntegerField(verbose_name="本課程的導師輔導費用(貝里)", default=15000)period = models.PositiveIntegerField(verbose_name="建議學習周期(days)", default=150) # 為了計算學位獎學金prerequisite = models.TextField(verbose_name="課程先修要求", max_length=1024)teachers = models.ManyToManyField("Teacher", verbose_name="課程講師")# 用于GenericForeignKey反向查詢, 不會生成表字段,切勿刪除# coupon = GenericRelation("Coupon")# 用于GenericForeignKey反向查詢,不會生成表字段,切勿刪除degreecourse_price_policy = GenericRelation("PricePolicy")def __str__(self):return self.nameclass Meta:verbose_name_plural = "03.學位課"class Teacher(models.Model):"""講師、導師表"""name = models.CharField(max_length=32)role_choices = ((0, '講師'), (1, '導師'))role = models.SmallIntegerField(choices=role_choices, default=0)title = models.CharField(max_length=64, verbose_name="職位、職稱")signature = models.CharField(max_length=255, help_text="導師簽名", blank=True, null=True)image = models.CharField(max_length=128)brief = models.TextField(max_length=1024)def __str__(self):return self.nameclass Meta:verbose_name_plural = "04.導師或講師"class Scholarship(models.Model):"""學位課程獎學金"""degree_course = models.ForeignKey("DegreeCourse")time_percent = models.PositiveSmallIntegerField(verbose_name="獎勵檔位(時間百分比)", help_text="只填百分值,如80,代表80%")value = models.PositiveIntegerField(verbose_name="獎學金數額")def __str__(self):return "%s:%s" % (self.degree_course, self.value)class Meta:verbose_name_plural = "05.學位課獎學金"class Course(models.Model):"""專題課/學位課模塊表"""name = models.CharField(max_length=128, unique=True)course_img = models.CharField(max_length=255)sub_category = models.ForeignKey("CourseSubCategory")course_type_choices = ((0, '付費'), (1, 'VIP專享'), (2, '學位課程'))course_type = models.SmallIntegerField(choices=course_type_choices)# 不為空;學位課的某個模塊# 為空;專題課degree_course = models.ForeignKey("DegreeCourse", blank=True, null=True, help_text="若是學位課程,此處關聯學位表")brief = models.TextField(verbose_name="課程概述", max_length=2048)level_choices = ((0, '初級'), (1, '中級'), (2, '高級'))level = models.SmallIntegerField(choices=level_choices, default=1)pub_date = models.DateField(verbose_name="發布日期", blank=True, null=True)period = models.PositiveIntegerField(verbose_name="建議學習周期(days)", default=7) # order = models.IntegerField("課程順序", help_text="從上一個課程數字往后排")attachment_path = models.CharField(max_length=128, verbose_name="課件路徑", blank=True, null=True)status_choices = ((0, '上線'), (1, '下線'), (2, '預上線'))status = models.SmallIntegerField(choices=status_choices, default=0)template_id = models.SmallIntegerField("前端模板id", default=1)coupon = GenericRelation("Coupon")# 用于GenericForeignKey反向查詢,不會生成表字段,切勿刪除price_policy = GenericRelation("PricePolicy")asked_question = GenericRelation("OftenAskedQuestion")def __str__(self):return "%s(%s)" % (self.name, self.get_course_type_display())def save(self, *args, **kwargs):if self.course_type == 2:if not self.degree_course:raise ValueError("學位課程必須關聯對應的學位表")super(Course, self).save(*args, **kwargs)class Meta:verbose_name_plural = "06.專題課或學位課模塊"class CourseDetail(models.Model):"""課程詳情頁內容"""course = models.OneToOneField("Course")hours = models.IntegerField("課時")course_slogan = models.CharField(max_length=125, blank=True, null=True)video_brief_link = models.CharField(verbose_name='課程介紹', max_length=255, blank=True, null=True)why_study = models.TextField(verbose_name="為什么學習這門課程")what_to_study_brief = models.TextField(verbose_name="我將學到哪些內容")career_improvement = models.TextField(verbose_name="此項目如何有助于我的職業生涯")prerequisite = models.TextField(verbose_name="課程先修要求", max_length=1024)recommend_courses = models.ManyToManyField("Course", related_name="recommend_by", blank=True)teachers = models.ManyToManyField("Teacher", verbose_name="課程講師")def __str__(self):return "%s" % self.courseclass Meta:verbose_name_plural = "07.課程或學位模塊詳細"class OftenAskedQuestion(models.Model):"""常見問題"""content_type = models.ForeignKey(ContentType) # 關聯course or degree_courseobject_id = models.PositiveIntegerField()content_object = GenericForeignKey('content_type', 'object_id')question = models.CharField(max_length=255)answer = models.TextField(max_length=1024)def __str__(self):return "%s-%s" % (self.content_object, self.question)class Meta:unique_together = ('content_type', 'object_id', 'question')verbose_name_plural = "08. 常見問題"class CourseOutline(models.Model):"""課程大綱"""course_detail = models.ForeignKey("CourseDetail")title = models.CharField(max_length=128)# 前端顯示順序order = models.PositiveSmallIntegerField(default=1)content = models.TextField("內容", max_length=2048)def __str__(self):return "%s" % self.titleclass Meta:unique_together = ('course_detail', 'title')verbose_name_plural = "09. 課程大綱"class CourseChapter(models.Model):"""課程章節"""course = models.ForeignKey("Course")chapter = models.SmallIntegerField(verbose_name="第幾章", default=1)name = models.CharField(max_length=128)summary = models.TextField(verbose_name="章節介紹", blank=True, null=True)pub_date = models.DateField(verbose_name="發布日期", auto_now_add=True)class Meta:unique_together = ("course", 'chapter')verbose_name_plural = "10. 課程章節"def __str__(self):return "%s:(第%s章)%s" % (self.course, self.chapter, self.name)class CourseSection(models.Model):"""課時目錄"""chapter = models.ForeignKey("CourseChapter")name = models.CharField(max_length=128)order = models.PositiveSmallIntegerField(verbose_name="課時排序", help_text="建議每個課時之間空1至2個值,以備后續插入課時")section_type_choices = ((0, '文檔'), (1, '練習'), (2, '視頻'))section_type = models.SmallIntegerField(default=2, choices=section_type_choices)section_link = models.CharField(max_length=255, blank=True, null=True, help_text="若是video,填vid,若是文檔,填link")video_time = models.CharField(verbose_name="視頻時長", blank=True, null=True, max_length=32) # 僅在前端展示使用pub_date = models.DateTimeField(verbose_name="發布時間", auto_now_add=True)free_trail = models.BooleanField("是否可試看", default=False)class Meta:unique_together = ('chapter', 'section_link')verbose_name_plural = "11. 課時"def __str__(self):return "%s-%s" % (self.chapter, self.name)class Homework(models.Model):chapter = models.ForeignKey("CourseChapter")title = models.CharField(max_length=128, verbose_name="作業題目")order = models.PositiveSmallIntegerField("作業順序", help_text="同一課程的每個作業之前的order值間隔1-2個數")homework_type_choices = ((0, '作業'), (1, '模塊通關考核'))homework_type = models.SmallIntegerField(choices=homework_type_choices, default=0)requirement = models.TextField(max_length=1024, verbose_name="作業需求")threshold = models.TextField(max_length=1024, verbose_name="踩分點")recommend_period = models.PositiveSmallIntegerField("推薦完成周期(天)", default=7)scholarship_value = models.PositiveSmallIntegerField("為該作業分配的獎學金(貝里)")note = models.TextField(blank=True, null=True)enabled = models.BooleanField(default=True, help_text="本作業如果后期不需要了,不想讓學員看到,可以設置為False")class Meta:unique_together = ("chapter", "title")verbose_name_plural = "12. 章節作業"def __str__(self):return "%s - %s" % (self.chapter, self.title)# class CourseReview(models.Model): # """課程評價""" # enrolled_course = models.OneToOneField("EnrolledCourse") # about_teacher = models.FloatField(default=0, verbose_name="講師講解是否清晰") # about_video = models.FloatField(default=0, verbose_name="內容實用") # about_course = models.FloatField(default=0, verbose_name="課程內容通俗易懂") # review = models.TextField(max_length=1024, verbose_name="評價") # disagree_number = models.IntegerField(default=0, verbose_name="踩") # agree_number = models.IntegerField(default=0, verbose_name="贊同數") # tags = models.ManyToManyField("Tags", blank=True, verbose_name="標簽") # date = models.DateTimeField(auto_now_add=True, verbose_name="評價日期") # is_recommend = models.BooleanField("熱評推薦", default=False) # hide = models.BooleanField("不在前端頁面顯示此條評價", default=False) # # def __str__(self): # return "%s-%s" % (self.enrolled_course.course, self.review) # # class Meta: # verbose_name_plural = "13. 課程評價(購買課程后才能評價)" # # # class DegreeCourseReview(models.Model): # """學位課程評價 # 為了以后可以定制單獨的評價內容,所以不與普通課程的評價混在一起,單獨建表 # """ # enrolled_course = models.ForeignKey("EnrolledDegreeCourse") # course = models.ForeignKey("Course", verbose_name="評價學位模塊", blank=True, null=True, # help_text="不填寫即代表評價整個學位課程", limit_choices_to={'course_type': 2}) # about_teacher = models.FloatField(default=0, verbose_name="講師講解是否清晰") # about_video = models.FloatField(default=0, verbose_name="視頻質量") # about_course = models.FloatField(default=0, verbose_name="課程") # review = models.TextField(max_length=1024, verbose_name="評價") # disagree_number = models.IntegerField(default=0, verbose_name="踩") # agree_number = models.IntegerField(default=0, verbose_name="贊同數") # tags = models.ManyToManyField("Tags", blank=True, verbose_name="標簽") # date = models.DateTimeField(auto_now_add=True, verbose_name="評價日期") # is_recommend = models.BooleanField("熱評推薦", default=False) # hide = models.BooleanField("不在前端頁面顯示此條評價", default=False) # # def __str__(self): # return "%s-%s" % (self.enrolled_course, self.review) # # class Meta: # verbose_name_plural = "14. 學位課評價(購買課程后才能評價)"class PricePolicy(models.Model):"""價格與有課程效期表"""content_type = models.ForeignKey(ContentType) # 關聯course or degree_courseobject_id = models.PositiveIntegerField()content_object = GenericForeignKey('content_type', 'object_id')# course = models.ForeignKey("Course")valid_period_choices = ((1, '1天'), (3, '3天'),(7, '1周'), (14, '2周'),(30, '1個月'),(60, '2個月'),(90, '3個月'),(180, '6個月'), (210, '12個月'),(540, '18個月'), (720, '24個月'),)valid_period = models.SmallIntegerField(choices=valid_period_choices)price = models.FloatField()class Meta:unique_together = ("content_type", 'object_id', "valid_period")verbose_name_plural = "15. 價格策略"def __str__(self):return "%s(%s)%s" % (self.content_object, self.get_valid_period_display(), self.price)# ################################### 優惠券相關 #################################class Coupon(models.Model):"""優惠券生成規則"""name = models.CharField(max_length=64, verbose_name="活動名稱")brief = models.TextField(blank=True, null=True, verbose_name="優惠券介紹")coupon_type_choices = ((0, '立減'), (1, '滿減券'), (2, '折扣券'))coupon_type = models.SmallIntegerField(choices=coupon_type_choices, default=0, verbose_name="券類型")money_equivalent_value = models.IntegerField(verbose_name="等值貨幣")off_percent = models.PositiveSmallIntegerField("折扣百分比", help_text="只針對折扣券,例7.9折,寫79", blank=True, null=True)minimum_consume = models.PositiveIntegerField("最低消費", default=0, help_text="僅在滿減券時填寫此字段")content_type = models.ForeignKey(ContentType, blank=True, null=True)object_id = models.PositiveIntegerField("綁定課程", blank=True, null=True, help_text="可以把優惠券跟課程綁定")content_object = GenericForeignKey('content_type', 'object_id')quantity = models.PositiveIntegerField("數量(張)", default=1)open_date = models.DateField("優惠券領取開始時間")close_date = models.DateField("優惠券領取結束時間")valid_begin_date = models.DateField(verbose_name="有效期開始時間", blank=True, null=True)valid_end_date = models.DateField(verbose_name="有效結束時間", blank=True, null=True)# coupon_valid_days = models.PositiveIntegerField(verbose_name="優惠券有效期(天)", blank=True, null=True,# help_text="自券被領時開始算起")date = models.DateTimeField(auto_now_add=True)class Meta:verbose_name_plural = "31. 優惠券生成記錄"def __str__(self):return "%s(%s)" % (self.get_coupon_type_display(), self.name)class CouponRecord(models.Model):"""優惠券發放、消費紀錄"""coupon = models.ForeignKey("Coupon")account = models.ForeignKey("Account", verbose_name="擁有者")number = models.CharField(max_length=64, unique=True)status_choices = ((0, '未使用'), (1, '已使用'), (2, '已過期'))status = models.SmallIntegerField(choices=status_choices, default=0)get_time = models.DateTimeField(verbose_name="領取時間", help_text="用戶領取時間")used_time = models.DateTimeField(blank=True, null=True, verbose_name="使用時間")# order = models.ForeignKey("Order", blank=True, null=True, verbose_name="關聯訂單") # 一個訂單可以有多個優惠券order_id = models.IntegerField(verbose_name='關聯訂單ID')class Meta:verbose_name_plural = "32. 用戶優惠券"def __str__(self):return '%s-%s-%s' % (self.account, self.number, self.status)class Account(models.Model):username = models.CharField("用戶名", max_length=64, unique=True)email = models.EmailField(verbose_name='郵箱',max_length=255,unique=True,blank=True,null=True)password = models.CharField('密碼', max_length=128)balance = models.FloatField('貝里',default=0)class Meta:verbose_name_plural = "33. 用戶表"class UserToken(models.Model):user = models.OneToOneField(to='Account')token = models.CharField(max_length=36)class Meta:verbose_name_plural = "34. token表" View Code

執行2個命令,生成字段

python manage.py makemigrations python manage.py migrate

為用戶加點錢

?

修改admin.py,注冊所有表

from django.contrib import admin# Register your models here. from api import models admin.site.register(models.CourseCategory) admin.site.register(models.CourseSubCategory) admin.site.register(models.DegreeCourse) admin.site.register(models.Teacher) admin.site.register(models.Scholarship) admin.site.register(models.Course) admin.site.register(models.CourseDetail) admin.site.register(models.OftenAskedQuestion) admin.site.register(models.CourseOutline) admin.site.register(models.CourseChapter) admin.site.register(models.CourseSection) admin.site.register(models.Homework) admin.site.register(models.PricePolicy) admin.site.register(models.Coupon) admin.site.register(models.CouponRecord) admin.site.register(models.Account) View Code

進入admin后臺,添加幾條優惠券,并綁定用戶

list

修改payment.py,先做get請求的

import json import redis from django.conf import settings from rest_framework.views import APIView from rest_framework.viewsets import ViewSetMixin from rest_framework.response import Response from api.utils.auth import LuffyAuthentication from api import models from api.utils.response import BaseResponsefrom django_redis import get_redis_connectionCONN = get_redis_connection("default") # 使用redis連接池class PaymentView(ViewSetMixin, APIView):authentication_classes = [LuffyAuthentication, ]def create(self, request, *args, **kwargs):"""在結算中添加課程:param request::param args::param kwargs::return:"""# 1.接收用戶選擇的要結算的課程ID列表# 2.清空當前用戶request.user.id結算中心的數據# key = payment_1*# 3.循環要加入結算中的所有課程ID列表"""for course_id in 用戶提交課程ID列表:3.1 根據course_id,request.user.id去購物車中獲取商品信息:商品名稱、圖片、價格(id,周期,顯示周期,價格)3.2 根據course_id,request.user.id獲取 - 當前用戶- 當前課程- 可用的優惠券加入結算中心提示:可以使用contenttypes"""# 4.獲取當前用戶所有未綁定課程優惠券# - 未使用# - 有效期內# - 加入結算中心:glocal_coupon_用戶IDdef list(self, request, *args, **kwargs):"""查看結算中心:param request::param args::param kwargs::return:"""# 1. 根據用戶ID去結算中心獲取該用戶所有要結算課程course_id = request.query_params.get('course_id')print('課程id',course_id)obj = models.Course.objects.filter(id=course_id).first()print('結算課程',obj.name)# 2. 根據用戶ID去結算中心獲取該用戶所有可用未綁定課程的優惠券user_id =request.user.idprint('用戶id', user_id)obj2 = models.CouponRecord.objects.filter(account=user_id, coupon__object_id__isnull=True).first()# print(obj2.coupon.get_coupon_type_display())if obj2.coupon.coupon_type == 0:print('{}{}'.format(obj2.coupon.get_coupon_type_display(),obj2.coupon.money_equivalent_value))elif obj2.coupon.coupon_type == 1:print('滿{}減{}'.format(obj2.coupon.minimum_consume,obj2.coupon.money_equivalent_value))else:print(obj2.coupon.id)print('{}折'.format(obj2.coupon.off_percent))# 3. 用戶表中獲取貝里余額beili = models.Account.objects.filter(id=user_id).first()print('用戶貝里',beili.balance)# 4. 以上數據構造成一個字典return Response('...')def update(self, request, *args, **kwargs):"""更新優惠券:param request::param args::param kwargs::return:"""# 1. 獲取用戶提交:# course_id=1,coupon_id=3# course_id=0,coupon_id=6# 2. course_id=1 --> 去結算中心獲取當前用戶所擁有的綁定當前課程優惠,并進行校驗# - 成功:defaul_coupon_id=3# - 否則:非法請求# 3. course_id=0 --> 去結算中心獲取當前用戶所擁有的未綁定課程優惠,并進行校驗# - 成功:defaul_coupon_id=3# - 否則:非法請求 View Code

使用postman發送GET請求

查看Pycharm控制臺輸出

課程id 1 結算課程 Python開發入門7天特訓營 用戶id 1 立減10 用戶貝里 100.0

?

posted @ 2018-08-14 15:13 肖祥 閱讀( ...) 評論( ...) 編輯 收藏

總結

以上是生活随笔為你收集整理的python 全栈开发,Day104(DRF用户认证,结算中心,django-redis)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

午夜av片| 免费国产ww | 91成人破解版 | 日韩在线视频免费播放 | 天天综合网~永久入口 | 在线中文字幕一区二区 | 国产精品18久久久久vr手机版特色 | 欧美成人理伦片 | 中文字幕精品一区二区精品 | 黄av免费 | 久久久91精品国产一区二区精品 | 国产精品嫩草影院99网站 | 亚洲精品在线电影 | 欧美精品xx | 欧美激情精品一区 | 中文字幕中文字幕在线中文字幕三区 | 午夜精品久久久久久中宇69 | 特级毛片网 | 午夜婷婷在线观看 | 99热这里只有精品8 久久综合毛片 | 成人a视频片观看免费 | 欧美日韩在线电影 | 久久久久久久久久久久久久电影 | 国产福利在线免费 | 爱情影院aqdy鲁丝片二区 | 97精品久久人人爽人人爽 | 综合伊人av| 狠狠躁夜夜躁人人爽视频 | av一级二级 | 五月天亚洲综合小说网 | 国产精品激情在线观看 | 久久 地址 | 免费成人在线观看视频 | 国产精品免费在线视频 | 天天想夜夜操 | 久久久久国产一区二区三区 | 欧美成人手机版 | 久久久久国产精品免费免费搜索 | 欧美小视频在线观看 | 精品久久久久久久久久岛国gif | av日韩国产 | 在线中文字幕观看 | 免费欧美精品 | 丁香婷婷在线观看 | 国产精品 国内视频 | 久久精品三 | 久久综合成人网 | 国产日产高清dvd碟片 | 美女视频黄是免费的 | 久久久久久久久久久久国产精品 | 91麻豆产精品久久久久久 | 日韩av片无码一区二区不卡电影 | 亚洲综合在线播放 | 日韩三级久久 | 国产免费久久精品 | 97成人在线观看视频 | 亚洲精品在线国产 | 91成人免费电影 | 免费看的黄色 | 中文字幕在线观看一区 | 日本三级在线观看中文字 | 手机在线永久免费观看av片 | 日本中文在线 | 国产精品在线看 | 99久久精品国产一区二区成人 | 国产精品免费视频观看 | 在线亚洲高清视频 | 国产精品久久久久一区二区三区 | 婷婷精品国产欧美精品亚洲人人爽 | 午夜91在线 | 亚洲精品综合在线观看 | 欧美乱码精品一区二区 | 一区二区三区免费在线播放 | 成人精品国产 | 天天舔天天射天天操 | 国产黄免费看 | 国产精品成人品 | 973理论片235影院9 | 狠狠操狠狠插 | 久久精品亚洲综合专区 | 中文字幕在线免费观看视频 | 国产精品国产三级国产不产一地 | 四虎影视国产精品免费久久 | www.伊人网 | 在线观看中文字幕2021 | 亚洲综合色激情五月 | 91麻豆国产| 久青草视频在线观看 | 久久免费国产电影 | 九九电影在线 | 日韩高清不卡一区二区三区 | 久久国产精品免费观看 | 免费午夜视频在线观看 | 国产精品免费久久久久久久久久中文 | 欧美日韩国产精品久久 | 97视频中文字幕 | 亚洲最大色 | 国产手机av | 亚洲最新av在线网站 | 欧美日韩大片在线观看 | 在线观看中文字幕第一页 | 国产成人黄色片 | 国产中文字幕在线免费观看 | 精品视频免费看 | 日韩在线观看你懂的 | 波多野结衣一区 | 国产免费久久av | 亚洲精品网址在线观看 | 国产三级精品三级在线观看 | 亚洲丝袜一区 | 蜜臀av夜夜澡人人爽人人桃色 | 欧美 亚洲 另类 激情 另类 | 99精品视频一区 | 国产高清视频色在线www | 国产精品久久综合 | 日本黄色一级电影 | 国产 精品 资源 | 偷拍区另类综合在线 | 久久久久久国产精品免费 | av在线专区| 久草久草在线观看 | 国产在线观看你懂得 | 国产成人精品一区二区三区 | 日本久久高清视频 | 免费亚洲婷婷 | 国产免费一区二区三区最新 | 精品国产成人av在线免 | 免费av在 | 亚洲国产电影在线观看 | 天天干夜夜想 | 在线免费观看国产黄色 | 婷婷久草 | 久久精品二区 | 日韩成人免费在线观看 | 久久免费观看视频 | 久久久高清免费视频 | 黄色av免费电影 | 亚洲伦理电影在线 | 中文字幕乱码视频 | 久久国产精品免费 | 超碰精品在线 | 最新一区二区三区 | 日韩在线免费电影 | 国产一区视频在线 | 日韩免费网站 | 美女福利视频一区二区 | 91精品网站在线观看 | 国产亚洲精品久久久久久网站 | 久久国产欧美日韩 | 国产精久久| 综合网天天射 | 美女网站视频一区 | 国产一级免费在线 | 久久爱影视i | 五月天激情视频在线观看 | 一区免费在线 | 免费看wwwwwwwwwww的视频 久久久久久99精品 91中文字幕视频 | 成 人 免费 黄 色 视频 | 国产福利91精品 | 欧美99热| 国产91综合一区在线观看 | 成人一区影院 | 99视频在线免费播放 | 日韩欧美在线观看 | h网站免费在线观看 | 国产69久久久欧美一级 | 久久国产视频网站 | 亚洲激色| 一区二区激情 | 国产精品色在线 | 在线观看成人av | 玖玖综合网 | 九色精品在线 | 亚一亚二国产专区 | 一区二区亚洲精品 | 中文欧美字幕免费 | 成人av免费在线观看 | 久久激情五月激情 | 国产视频精品免费播放 | 99九九热只有国产精品 | 伊人午夜视频 | 久久99热这里只有精品 | 摸bbb搡bbb搡bbbb| 91精品1区2区 | 黄网av在线 | 深爱五月激情五月 | 人人澡人摸人人添学生av | 午夜影院在线观看18 | 天天操天天舔天天干 | 99热精品国产 | 亚洲电影黄色 | 中文日韩在线 | 日韩理论影院 | 亚洲成人欧美 | 最近2019年日本中文免费字幕 | 97人人艹 | 精品在线观看一区二区 | 国产精品99免视看9 国产精品毛片一区视频 | 正在播放国产91 | 人人爽人人爽av | www.夜色321.com| 国产1级视频 | 久久不卡视频 | 日韩欧美高清 | 看黄色.com| 久久久精品国产一区二区 | 免费成人av在线看 | 久久精品官网 | 中文字幕在线免费播放 | 日韩精品电影在线播放 | 久草国产在线 | 亚洲日韩欧美一区二区在线 | 中国一级片在线播放 | 国产精品女同一区二区三区久久夜 | 国产成人精品一区二区三区在线 | 久久久久久久国产精品 | 九九视频免费在线观看 | 欧美日韩国产mv | 欧美综合色 | 亚洲国产精品小视频 | 国产在线更新 | 国产高清在线一区 | 五月天久久久久 | 亚洲日韩欧美视频 | 偷拍福利视频一区二区三区 | 久久久麻豆精品一区二区 | 国产一区福利 | 国产无套精品久久久久久 | 亚洲六月丁香色婷婷综合久久 | 欧美日韩首页 | 91福利在线导航 | 不卡的一区二区三区 | 色婷婷成人 | 国产在线观看91 | 999久久久久久久久 69av视频在线观看 | 超碰97在线人人 | 欧美性生交大片免网 | 国产手机在线精品 | 一级国产视频 | 亚洲视频久久 | av福利第一导航 | 日韩在线免费 | 欧美 日韩 国产 中文字幕 | 伊人久在线 | 亚洲国产精久久久久久久 | 国产精品久久久久一区二区三区 | 国产精品 亚洲精品 | 日本一区二区三区视频在线播放 | 精品美女久久久久久免费 | 美女在线观看av | 91超碰在线播放 | 日韩精品免费在线观看 | 日韩成人精品 | 国产原厂视频在线观看 | 欧美国产日韩一区二区 | 久久久精品 | 伊人婷婷色| 国产一区二区在线播放 | 免费日韩视 | 久草在在线| 日韩精品久久久久 | av专区在线 | 国产成人三级在线观看 | 日日夜夜添 | av不卡免费在线观看 | 国产精品视频区 | 久久人人插 | www久久九| 丁香网婷婷 | 天天操天天射天天添 | 黄色毛片视频免费观看中文 | 国产成人精品午夜在线播放 | 亚洲人视频在线 | 久久er99热精品一区二区 | 久久视频免费看 | 日韩av男人的天堂 | 国产一级91 | 国产精品国产亚洲精品看不卡 | 国产玖玖视频 | 久久免费精彩视频 | 久久精品人人做人人综合老师 | 在线播放av网址 | 日韩精品在线视频 | 99国产免费网址 | 国产精品一区二区麻豆 | www.天天色.com | 欧美二区视频 | 国产精品免费观看视频 | 97精品超碰一区二区三区 | 欧美日韩午夜 | 91高清视频免费 | 成人va天堂 | 成人xxxx| 成人av资源网站 | 色.com| 国产一级淫片在线观看 | 久久国产色 | 91九色丨porny丨丰满6 | 亚洲国内精品在线 | 在线观看91精品视频 | 亚洲成熟女人毛片在线 | 国产午夜精品一区二区三区四区 | 久久成人亚洲欧美电影 | 国产精品一区二区美女视频免费看 | av不卡免费在线观看 | 91污污视频在线观看 | 日日夜夜天天久久 | 国产在线观看91 | 日韩午夜大片 | 国产精品一区二区在线观看 | 久久久久亚洲精品国产 | 国产精品日韩在线观看 | 欧美黄色特级片 | 最近的中文字幕大全免费版 | 丁香婷婷色综合亚洲电影 | 五月婷婷在线视频观看 | 色综合久久综合中文综合网 | 国产一区免费视频 | 日韩免费福利 | 国产精品专区在线 | 成人在线视频你懂的 | 五月激情六月丁香 | 成人性生交大片免费观看网站 | 在线免费观看黄色小说 | 91热视频 | 久久久久久久精 | 国产老太婆免费交性大片 | 综合久久久久久久久 | av高清在线观看 | 久草久视频 | 成人9ⅰ免费影视网站 | 免费在线观看黄网站 | 国产精品一区免费在线观看 | 亚洲视频专区在线 | 中文av影院 | 日韩在线播放视频 | 日韩免费二区 | 国产精品久久久久久超碰 | 特级aaa毛片 | 亚洲dvd| 久久综合精品国产一区二区三区 | 99精品影视| 日韩二区在线播放 | 国产精品久久久久毛片大屁完整版 | 欧美一级免费 | 亚洲精品在线视频网站 | 成年人在线观看 | 国产男女爽爽爽免费视频 | 99久久久久久国产精品 | a色视频| 日本久久不卡视频 | 免费av黄色 | 成人在线黄色电影 | 亚洲欧美国产日韩在线观看 | 最新高清无码专区 | 欧美性生爱 | 五月开心六月婷婷 | 九九精品视频在线看 | 91成人免费看片 | 黄色一集片 | 黄色av免费在线 | 国产日产精品久久久久快鸭 | 亚洲欧美视频在线观看 | www.xxxx变态.com | 日韩在线播放av | 成人动图 | 久久精品亚洲 | 精品国产人成亚洲区 | 久久久久成人精品亚洲国产 | 中国一级片在线播放 | 亚洲国产手机在线 | 99久久精品国产亚洲 | 亚洲国产成人高清精品 | 黄网站免费看 | 国产一区二区不卡视频 | 国产精品一区二区久久精品爱涩 | 正在播放日韩 | 在线国产日本 | 综合久久影院 | 国内成人精品视频 | 午夜av在线 | 91香蕉视频在线 | 亚洲精品在线国产 | 日韩精品久久久久久中文字幕8 | 天天视频亚洲 | 国产一区二区在线精品 | 欧美成人精品三级在线观看播放 | 99视频网站 | 成人黄色免费在线观看 | 成人黄色小视频 | 日韩一级片大全 | 国产综合精品久久 | 外国av网 | 国产一级片不卡 | 日韩在线观看你懂的 | 国产免费久久精品 | 久久精品亚洲一区二区三区观看模式 | 99爱在线观看 | 97在线看| 99久久久国产精品免费观看 | 国产一级二级三级视频 | 中文字幕一区2区3区 | 亚洲专区在线 | 国产精品永久在线 | 亚洲a网 | 91av在线看 | 久久综合欧美精品亚洲一区 | 超碰人人在线观看 | 亚洲高清av在线 | 欧美日韩一区二区在线观看 | 久久久久一区二区三区 | 黄色成人av在线 | 国产精品免费在线播放 | 一区二区丝袜 | 天天激情天天干 | 在线观看爱爱视频 | 免费在线观看av网址 | www五月婷婷 | 色大片免费看 | 波多野结衣精品视频 | 欧美99久久| 天天色天天骑天天射 | 久草观看 | 国产高清视频在线观看 | 伊人日日干 | 国产精品久久久免费 | 久久久免费精品 | 97在线视频免费观看 | 青青草视频精品 | 色诱亚洲精品久久久久久 | 蜜臀av性久久久久蜜臀aⅴ四虎 | 精品国产一区二区三区四区在线观看 | 丁香导航 | 日韩电影中文字幕在线观看 | 日韩在线观看中文 | 国产美腿白丝袜足在线av | av怡红院 | 久久综合精品一区 | 999久久a精品合区久久久 | 久草热久草视频 | 亚洲国产影院 | 国产一区在线视频 | 亚洲乱码精品久久久久 | 国产在线精品一区 | 免费av网址大全 | 日韩试看| 久久精品日本啪啪涩涩 | 99热手机在线观看 | 免费a视频| 六月天综合网 | 国产精品久久久久影院 | 日韩av一区二区在线播放 | 韩国精品在线观看 | 久久天天躁夜夜躁狠狠躁2022 | 国产精品涩涩屋www在线观看 | 日韩视频一二三区 | 久久免费在线视频 | 日韩视频三区 | 国产中文视 | 亚洲激情六月 | 久草在线视频精品 | 黄色免费电影网站 | 国产精品久久久区三区天天噜 | 色狠狠婷婷 | 91精品视屏 | 久久人人97超碰精品888 | 亚洲欧美一区二区三区孕妇写真 | 日韩一区二区三区高清免费看看 | 在线观看黄色国产 | 国产精品久久久一区二区 | 亚洲免费国产视频 | 国产精品乱码一区二三区 | 国产亚洲精品久久久久久久久久 | 成人午夜毛片 | 免费观看黄色12片一级视频 | 婷婷亚洲五月 | 日韩精品一区二区三区免费观看视频 | 日韩黄色中文字幕 | 午夜99| 亚洲国产三级在线观看 | 91视频免费看网站 | 91成人网在线 | 17婷婷久久www | 国产视频资源在线观看 | 久久黄色精品视频 | 日韩黄色在线观看 | 免费看片黄色 | 欧美精品视 | 在线观看深夜福利 | 亚洲一区av | 精品一区二区在线免费观看 | 久久久久亚洲最大xxxx | 国产视频 亚洲精品 | 开心激情综合网 | 九九免费精品视频在线观看 | 粉嫩aⅴ一区二区三区 | 丝袜美腿av | 黄色片网站免费 | 国产一级在线免费观看 | 综合色爱| 亚洲h在线播放在线观看h | 91亚洲精品久久久中文字幕 | 探花在线观看 | 日韩va亚洲va欧美va久久 | 免费中文字幕视频 | 日本一区二区三区免费观看 | 91精品视频免费在线观看 | 色多视频在线观看 | 精品免费观看视频 | 国产精品区一区 | 国产精品第一页在线观看 | 国产精品 欧美 日韩 | 96av视频| 久久99中文字幕 | avcom在线| 日韩大片在线免费观看 | 国内外成人在线视频 | 欧美另类交人妖 | 成人影音在线 | 97超碰在线播放 | 66av99精品福利视频在线 | 国产精品亚洲人在线观看 | 成人av高清在线观看 | 超碰资源在线 | 国产特级毛片aaaaaa高清 | 欧美日韩国产精品一区二区亚洲 | 91看片在线 | 91看片网址 | 92av视频 | 中文综合在线 | 亚洲jizzjizz日本少妇 | 免费视频网 | 99一区二区三区 | 国产在线免费av | 国产在线永久 | 日韩aⅴ视频 | 亚洲欧美视频一区二区三区 | 人人爽人人爽 | 国产精品视频在线观看 | 国产视频精品在线 | 黄色在线观看网站 | 色悠悠久久综合 | 手机在线永久免费观看av片 | 国产一区免费 | 天天综合视频在线观看 | 国产色啪 | 国产精品一区二区你懂的 | 色网站在线免费观看 | 一本一道久久a久久精品 | 激情欧美国产 | 国产精品美女毛片真酒店 | 久久 精品一区 | 久久高清国产 | 欧美 日韩 国产 中文字幕 | 国产黄色视 | 怡红院成人在线 | 精品久久久久久亚洲综合网站 | 午夜丁香视频在线观看 | 免费看黄色大全 | 久久一级电影 | 久久久久久久亚洲精品 | 天天做日日爱夜夜爽 | 亚洲精品婷婷 | 97天天综合网 | 日本性动态图 | 久久精品—区二区三区 | 曰本免费av | 久久婷婷国产色一区二区三区 | 日批网站免费观看 | 三级黄色欧美 | 黄色免费观看视频 | 亚洲在线不卡 | 久久99精品久久久久久 | 国产91精品高清一区二区三区 | 一区二区三区在线免费 | 波多野结衣视频一区 | 亚洲精品视频网站在线观看 | 日韩 在线 | 久久精精品| 天天干天天草天天爽 | av在线免费不卡 | 日韩91在线| 成人一级在线观看 | 国产高清无线码2021 | 91中文字幕永久在线 | 日日躁你夜夜躁你av蜜 | 久久久国产精品人人片99精片欧美一 | 在线不卡a | 国产一区二区久久 | 日韩a免费 | 亚洲四虎 | 国产一区国产二区在线观看 | 摸阴视频 | 国产精品嫩草影院123 | 久久久久国产精品一区二区 | 国产成人一二三 | 一区二区三区四区久久 | 欧美日韩二区在线 | 69欧美视频 | 人人草在线视频 | 色偷偷88888欧美精品久久久 | 波多野结衣视频一区二区 | 999视频网站 | 精品久久久久久久久久国产 | 一级黄色毛片 | 亚洲精品国久久99热 | 91人人爱| 精品国产区在线 | 欧美日韩激情视频8区 | 在线天堂v | 日韩精品视频网站 | 四虎在线观看视频 | 99国产在线观看 | 日本中文字幕网 | 蜜桃av久久久亚洲精品 | 国产精品精品 | 精选久久| 国产成人在线观看 | 亚洲国产日韩一区 | 日韩精品一区二区久久 | 在线观看韩日电影免费 | 四虎成人精品永久免费av | www.国产高清 | 午夜久久久久久久久久影院 | 精品99久久 | 高清久久久 | 久久在视频 | 中文字幕一区二区三区久久蜜桃 | 99精品久久久久久久久久综合 | av短片在线 | 99精品视频免费全部在线 | 午夜精品区 | 国产 日韩 欧美 中文 在线播放 | 日韩精品在线看 | 中文字幕永久在线 | 日韩网站免费观看 | 最新av在线播放 | 国产精品2018| 伊人伊成久久人综合网小说 | 久久久久久久久久久免费视频 | 中文字幕在线免费看 | av在线免费网站 | 99精品国产兔费观看久久99 | 久久国产精品第一页 | 91久久久久久久一区二区 | 99re6热在线精品视频 | 国产黄在线播放 | 精品中文字幕在线观看 | 在线播放你懂 | 91麻豆精品国产 | av在线免费播放网站 | 国产精品地址 | 欧美精品在线一区 | 500部大龄熟乱视频 欧美日本三级 | 99精品视频一区 | 欧美激情视频在线观看免费 | 久久久国际精品 | 日韩在线色 | 国产五月色婷婷六月丁香视频 | 欧美日韩国产在线 | 国内视频在线 | www.亚洲黄色 | 97精品超碰一区二区三区 | 成年人三级网站 | av短片在线 | 色综合狠狠干 | 色婷婷国产精品一区在线观看 | 探花系列在线 | 亚洲一区欧美激情 | 中文字幕观看在线 | 91九色丨porny丨丰满6 | 国产不卡毛片 | 午夜色大片在线观看 | 国产精品久久嫩一区二区免费 | 一区二区三区在线视频观看58 | 国产1区2区 | av不卡网站 | 日韩中文字幕在线 | 一级性视频 | 久久免费精品一区二区三区 | 亚洲精品2区 | 久久久精品福利视频 | 亚洲精品ww | 国产成人一区二区三区在线观看 | 久久精品视频99 | 亚洲四虎 | 99色网站 | 99久久久久久久 | 国产黄色特级片 | 天天综合导航 | 偷拍区另类综合在线 | a级国产乱理伦片在线观看 亚洲3级 | 久9在线| 日韩欧美在线综合网 | 天天碰天天操 | 欧美精品在线观看 | 亚洲亚洲精品在线观看 | 中文字幕日韩一区二区三区不卡 | 天天操天天插 | 日本不卡123区 | 久久艹艹 | 黄色片免费看 | 九九九九免费视频 | 99精品一区二区 | 国产精品久久久久久影院 | 精品一区精品二区 | 高清视频一区二区三区 | 99热在线国产精品 | 992tv人人网tv亚洲精品 | 久久精品三级 | 69国产盗摄一区二区三区五区 | 乱男乱女www7788 | 成人免费一区二区三区在线观看 | 黄色小网站免费看 | 久久久国产99久久国产一 | 久草91视频 | 一区二区三区在线观看免费视频 | 在线视频日韩精品 | 国产最新在线视频 | 狠狠的干狠狠的操 | 婷婷资源站 | 91中文字幕| 一区二区三区在线不卡 | 不卡国产视频 | 韩国av免费观看 | 最近最新mv字幕免费观看 | 91亚洲免费| 亚洲第一区在线播放 | 国产一级特黄电影 | 国产精品久久久久999 | 亚洲精品视频在线观看视频 | 中文字幕在线观 | 亚洲女欲精品久久久久久久18 | 青青久草在线视频 | 不卡的av在线播放 | 久久久久久免费网 | 911亚洲精品第一 | 丁香婷婷网| 久久999精品 | 亚洲美女免费精品视频在线观看 | 婷婷色中文字幕 | 色综合久久精品 | 国产玖玖精品视频 | 免费网站在线观看成人 | 日韩欧美在线免费 | 91一区二区三区久久久久国产乱 | 99爱国产精品 | 91亚洲国产成人久久精品网站 | 欧美日韩a视频 | 亚洲欧洲中文日韩久久av乱码 | 国产视频精品免费播放 | 91精品视频免费 | 国产日本三级 | 特级毛片在线免费观看 | 日韩在线观看免费 | 综合国产在线 | 国产手机在线精品 | 久久久久久久毛片 | 久久久久久久久网站 | 欧美天天综合网 | 国产在线视频不卡 | 91精品一区国产高清在线gif | 日韩午夜精品福利 | 黄色一级在线观看 | 日日夜夜草 | 久久久精选 | 日韩黄色一级电影 | 黄色在线观看免费 | 国产日产精品久久久久快鸭 | 91久久奴性调教 | 亚洲最大激情中文字幕 | 日韩欧美视频免费看 | 波多野结衣在线视频免费观看 | 久久久久久亚洲精品 | 国产精品第一页在线观看 | 在线观看中文字幕一区 | 中文字幕在线观看免费观看 | av片在线观看| 久草在线久草在线2 | 久久久久久久久久久成人 | 久久9视频 | 久久精品电影院 | 欧美国产日韩一区二区 | 国产精品国产三级国产aⅴ9色 | 91视频在线播放视频 | 黄色av电影在线 | 国产中文a| 日韩资源在线播放 | 欧美日韩性视频 | 婷婷成人亚洲综合国产xv88 | 天天综合中文 | 9i看片成人免费看片 | 在线观看国产一区二区 | 久久国产精品免费一区二区三区 | 亚洲国产午夜 | 在线观看国产麻豆 | 午夜精品久久久久 | 国产精品久久久久久久久久直播 | 在线观看视频免费播放 | 成人啊 v | 国产精品人成电影在线观看 | 精品国产一区二 | 四虎永久免费 | 亚洲精品大片www | 国产精品网址在线观看 | 91成版人在线观看入口 | 91av在线播放视频 | 国产在线观看免费 | 激情综合亚洲精品 | 一区二区视频欧美 | 国产手机在线观看视频 | 国产精品永久在线 | 国产精品a久久久久 | 免费观看国产精品视频 | 人成在线免费视频 | 久久免费在线观看 | 亚洲人xxx | 欧美一级片在线播放 | 亚洲高清在线精品 | 日本久久电影 | 久久这里只精品 | 日日干夜夜干 | www黄色av| 精品成人免费 | 青青色影院 | 麻豆国产精品永久免费视频 | 久久久国产一区二区 | 三级性生活视频 | 国产精品入口传媒 | 在线观看一级 | 久久久黄视频 | 一级黄色免费 | 天天爱天天色 | 日韩av中文在线 | 久日视频 | 成人资源网 | 91色视频 | www.99av| av黄色av | 插综合网 | 免费激情网| 国产精品久久99综合免费观看尤物 | 免费黄色一区 | 日韩色视频在线观看 | 欧美亚洲国产一卡 | 人人爽人人爽人人片 | 午夜999 | 西西4444www大胆无视频 | 狠狠干成人 | 超碰在线公开免费 | 手机成人在线电影 | 狠狠干狠狠久久 | 日韩电影一区二区三区在线观看 | 久插视频 | 成人看片 | 91精品国产综合久久福利 | 欧美另类z0zx | 一区二区三区在线电影 | www.五月天色 | 日韩成人精品在线观看 | 亚洲人久久久 | 热久久免费国产视频 | 亚洲最大激情中文字幕 | 日日夜夜精品视频天天综合网 | 黄色1级大片 | 91精品婷婷国产综合久久蝌蚪 | 日韩精品91偷拍在线观看 | 一级一片免费观看 | 日韩av免费观看网站 | 国产亚洲日 | 久久视频国产精品免费视频在线 | 97超视频在线观看 | 久久视频在线观看免费 | 国产精品久久久久一区二区三区 | 久久草网站| 午夜在线资源 | 美女免费网视频 | 99re热精品视频 | 香蕉视频国产在线观看 | 日本系列中文字幕 | 久草视频免费播放 | a黄色一级 | 亚洲一本视频 | 最新av中文字幕 | 亚洲精品男人天堂 | 97碰碰精品嫩模在线播放 | 看v片| 亚洲日本一区二区在线 | 福利一区在线 | 国产亚洲精品电影 | 中国成人一区 | 免费在线观看一区二区三区 | 91精品国产91热久久久做人人 | 亚洲天堂网视频 | 免费观看高清 | 中文字幕在线视频一区二区三区 | 亚洲国产合集 | 国产黄| 麻豆高清免费国产一区 | 青青河边草手机免费 | 天天艹 | 日韩成人免费在线观看 | 国产 一区二区三区 在线 | 国产精品久久99综合免费观看尤物 | 爱爱av在线 | 99久久精品久久久久久清纯 | 国产精品国产三级国产不产一地 | 亚洲一区av| 久久综合亚洲鲁鲁五月久久 | 国产高清网站 | 免费看黄色毛片 | 国产精品video爽爽爽爽 | 久久精品中文字幕一区二区三区 | 国产精品日韩久久久久 | 国产成人高清av | 99精品视频在线免费观看 | 免费看污网站 | 二区三区在线 | 91超在线| av成人在线电影 | 麻豆免费观看视频 | 日韩免费在线观看网站 | 精品在线不卡 | www久草 | 青青河边草免费视频 | 四虎在线永久免费观看 | 五月开心婷婷 | 久久精品9 | 波多野结衣一区 | 一级成人免费视频 | 国产精品国产三级国产不产一地 | 久久黄色a级片 | 黄色软件在线观看视频 | 99精品在线视频观看 | 久久综合久色欧美综合狠狠 | 久久久久国 | 欧美精品乱码99久久影院 | 天天狠狠 | 国产精品欧美一区二区 | 一区二精品 | 国产一级二级视频 | 美女又爽又黄 | 国产人成在线视频 | 国产福利精品一区二区 | 国产精品99久久久精品 | 日日夜夜精品网站 | 国产亚洲人成网站在线观看 | 日韩在线观看视频免费 | 99在线播放 | 欧美成年网站 | 日韩精品久久久久 | 国产又黄又硬又爽 | 亚洲资源片 | 欧美少妇xx | 一区二区三区三区在线 | 91丨九色丨国产丨porny精品 | 久久精品久久久精品美女 | 在线观看亚洲国产精品 | 色99中文字幕| 久久久久久久久久久电影 | 免费91麻豆精品国产自产在线观看 | 三级免费黄| 97视频人人免费看 | 日本精品二区 | 91网免费看 | 亚洲理论在线观看电影 | 成人午夜电影在线观看 | 精品二区视频 | 国产一区二区在线精品 | 国产精品欧美日韩 | 制服丝袜欧美 | 亚洲视频一区二区三区在线观看 | a视频在线播放 | 国产一区二区三区 在线 | 婷婷五月色综合 | 综合五月 | 国产91av视频在线观看 | 精精国产xxxx视频在线播放 | 91精品对白一区国产伦 | 日韩视频中文字幕在线观看 | a在线一区 | 国产精品女人久久久久久 | 国产精品黄色影片导航在线观看 | 99精品免费久久久久久久久 | 91九色视频观看 | 国产精品视频免费 | 午夜一级免费电影 | 免费日韩一级片 | 久 久久影院 | 亚洲欧美在线综合 | 国产成人久久精品一区二区三区 | 国产福利在线免费观看 | 久久 地址 | 美女精品网站 | 狠狠色丁香九九婷婷综合五月 | 国产黄色片免费 | 国产专区在线视频 | 亚洲a网 |