day 113 添加购物车接口

购物车

1,用到了django_redis存储数据,存储数据快,好管理

cmd下载redies:  pip install django_redis

 还要去settings.py中去注册

CACHES = {
   "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            "CONNECTION_POOL_KWARGS": {"max_connections": 100}
            # "PASSWORD": "密码",
        }
    },

}
View Code

 2,view文件夹里创建shopping_car.py写购物车的增删改查接口

from rest_framework.views import APIView
from rest_framework.viewsets import ViewSetMixin,ModelViewSet
from rest_framework import generics
from rest_framework.response import Response
from course.models import Course,PricePolicy

from django.core.exceptions import ObjectDoesNotExist
from course.utils.response import BaseResponse
from course.utils.exceptions import PricePolicyException

from django_redis import get_redis_connection
from course.utils.auth import LoginAuth
import redis
import json
#
# """
# 购物车
# redis 的数据结构设计
# redis = {
#     shopping_car_<user_id>_<course_id>: {
#         "id": course.id, 带用户id是为了用户查看购物车的时候需要
#         "title": course.name,
#         "img": str(course.course_img),
#         "policy_dict": {   #所有价格策略信息
#             policy_id:{    #第一个价格策略信息
#                 "period": item.valid_period, 价格策略
#                 "period_display": item.get_valid_period_display(), 价格策略中文
#                 "price":  item.price, 价格
#             },
#             policy_id2:{
#                 ....
#             }
#         },
#         "default_policy": policy_id ,选择的价格策略id
#     }
#
#
# }
# """
#
REDIS_CONN = redis.Redis(host="127.0.0.1",port=6379,decode_responses=True)#decode_responses=True把redis的byset类型取出来的时候变成字符串
SHOPPING_CAR_KEY = "shopping_car_%s_%s"
class ShoppingCarView(APIView):
#     """
#         购物车接口
#         1010 代表成功
#         1011 课程不存在
#         1012 价格策略不存在
#         1013 获取购物车失败
#         1014 删除的购物车数据不存在
#         """
#
    authentication_classes = [LoginAuth]  #认证
#     #展示购物车数据
    def get(self, request, *args, **kwargs):
        res = BaseResponse()

        try:
            # 1 获取用户id
            user_id = request.user.id
            # 2 从redis获取购物车所有数据
            shopping_car_key = SHOPPING_CAR_KEY % (user_id, "*")
            # 用redis中scan_iter方法过滤用户购物车的所有key
            all_names = REDIS_CONN.scan_iter(shopping_car_key)
            # print(all_names)
            #循环每个key 去 redis 中拿到这个key的value
            ret = []
            for name in all_names:
                print(name)
                course_info=REDIS_CONN.hgetall(name)#获取name为键的所有
                ret.append(course_info)
            # print(ret)
            res.data = ret
        except Exception as e:
            res.code = 1013
            res.error = "获取购物车失败"

        return Response(res.dict)





    # 给购物车增加商品
    # 传过来的数据 有 课程ID 以及价格策略ID
    def post(self, request, *args, **kwargs):
        res = BaseResponse()

        try:

            # 1 获取用户提交(前端传过来)的课程ID以及价格策略ID
            course_id = request.data.get("course_id", "")
            price_policy_id = request.data.get("price_policy_id", "")
            user_id = request.user.pk
            # 2 检查用户传过来的数据是否合法
            # 2.1  查看课程ID是否存在
            course_obj = Course.objects.filter(id=course_id).first()
            if not course_obj:
                res.code = 1011
                res.error = "课程对象不存在"
                return Response(res.dict)
            # 2.2  查看价格策略price_policy_id是否合法
            #  获取该课程的所有价格策略 判断price_policy_id是否在里面
            price_policy_queryset = course_obj.price_policy.all()
            price_policy_dict = {}
            for price_policy in price_policy_queryset:
                price_policy_dict[price_policy.pk] = {
                    "price": price_policy.price,
                    "valid_period": price_policy.valid_period,  #周期
                    "valid_period_text": price_policy.get_valid_period_display(),
                }
            if price_policy_id not in price_policy_dict:
                res.code = 1012
                res.error = "课程的价格策略不存在"
                return Response(res.dict)
            # 3构建数据结构 构建出购物车的key 用户数据合法 得到用户的购物车key
            shopping_car_key = SHOPPING_CAR_KEY % (user_id, course_id)
            # 4 构建购物车数据
            course_info = {
                "id": course_id,
                "title": course_obj.title,
                "img_src": str(course_obj.course_img),
                "default_policy": price_policy_id,
                "price_policy_dict": json.dumps(price_policy_dict,ensure_ascii=False)
            }
            # 5 写入redis hmset这个方法有值就更新  没值就新建 解决了用户重复点一个商品的问题
            REDIS_CONN.hmset(shopping_car_key, course_info)

            res.data = "加入购物车成功"
            res.data = course_info  # 把course_info放在了data里
        except Exception as e:
            print(e)
            res.code = 1010
            res.error = "加入购物车失败"

        print(res.dict)
        return Response(res.dict)


#
#
#     # 删除购物车数据
#     # 传过来的数据 {course_ids: [1,2]}
    def delete(self, request, *args, **kwargs):
        res = BaseResponse()
        # 1 验证数据合法性 课程ID是否在购物车里
        try:
            for course_id in request.data["course_ids"]:
                shopping_car_key = SHOPPING_CAR_KEY % (request.user.pk, course_id)
                if not REDIS_CONN.exists(shopping_car_key):
                    res.code = 1014
                    res.error = "课程不存在购物车"
                # 2 数据合法 删除redis购物车里的数据
                REDIS_CONN.delete(shopping_car_key)
        except Exception as e:
            res.code = 1015
            res.error = "删除购物车失败"
        return Response(res.dict)



    # 更新购物车里的课程的价格策略
    # 传过来的数据 有 course_id 以及 price_policy_id
    def patch(self, request, *args, **kwargs):
        res = BaseResponse()
        # 1 验证数据的合法性 course_id 以及 policy_id
        try:
            course_id = request.data["course_id"]
            policy_id = request.data["price_policy_id"]
            # 判断redis购物车里是否有course_id
            shopping_car_key = SHOPPING_CAR_KEY % (request.user.pk, course_id)
            if not REDIS_CONN.exists(shopping_car_key):
                res.code = 1014
                res.error = "课程不存在购物车"
            # 判断policy_id 是否合法 redis中取 验证
            price_policy_dict = json.loads(REDIS_CONN.hget(shopping_car_key, "price_policy_dict"))
            if str(policy_id) not in price_policy_dict:
                res.code = 1015
                res.error = "价格策略不合法"
            # 2 更改购物车里的数据
            REDIS_CONN.hset(shopping_car_key, "default_policy", policy_id)
        except Exception as e:
            print(e)
            res.code = 1016
            res.error = "更新购物车失败"
        return Response(res.dict)


#
#
#
#
#
View Code

3,在购物车接口中返回错误信息,状态码,实例化了BaseResponse(),在utils中写了response.py

class BaseResponse():

    def __init__(self):
        self.code=1000
        self.data = None
        self.msg = ''
    @property
    def dict(self):
        return self.__dict__

if __name__=="__main__":
    res = BaseResponse()
    res.code=1001
    print(res.dict)
View Code

4,购物车中自定义报错信息在utils里写了excepyions.py

class PricePolicyException(Exception):
    def __init__(self,msg):
        self.msg=msg
View Code

5,urls.py

"""LuffyBoy URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/1.11/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.conf.urls import url, include
    2. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url
from django.contrib import admin


from rest_framework.routers import DefaultRouter
from course.view.courseView import CourseView
from course.view.categoryView import CategoryView
from course.view.login import LoginView
from course.view.shopping_car import ShoppingCarView

router=DefaultRouter() #实例化
router.register("course",CourseView)#把路由注册进来course,CourseView对应的视图
router.register("category",CategoryView)


urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r"^login/",LoginView.as_view()),
    url(r'^shoppingcar/',ShoppingCarView.as_view()),

]
urlpatterns+=router.urls#把"course"添加到列表里



# http://127.0.0.1:8000/course/?format=json
View Code

================以上是购物车接口====== 

utils文件夹下

添加的认证类在utils文件中

auth.py:

from rest_framework.authentication import BaseAuthentication
from course.models import UserToken
from rest_framework.exceptions import AuthenticationFailed
from django.core.cache import cache
from django.utils.timezone import utc
import datetime


#第一版普通版本解决不了时效和缓存
# class LoginAuth(BaseAuthentication):
#     def authenticate(self, request):
#         print("request.META",request.META.get("HTTP_AUTHENTICATE"))
#         token=request.META.get("HTTP_AUTHENTICATE")
#         token = UserToken.objects.filter(token=token).first()
#
#         if token:
#             return token.user,token.token
#         else:
#             raise AuthenticationFailed("认证失败")


#第二版解决时效和缓存


class LoginAuth(BaseAuthentication):
    def authenticate(self,request):
        print("request.META",request.META.get("HTTP_AUTHENTICATE"))
        token=request.META.get("HTTP_AUTHENTICATE",'')#从响应头里获取

        # 缓存查询token是否存在(第一次进来的时候token不存在,走数据库)
        user=cache.get("token_"+token)  #价格字符串做标识
        if user:
            return user, "token_"+token
        try:
             # 数据库查询是否存在token
             token=UserToken.objects.get(token=token)
        except Exception as e:
            raise AuthenticationFailed("认证失败!")

        # token是否过期
        utcnow = datetime.datetime.utcnow().replace(tzinfo=utc)  #当前时间
        if utcnow - token.create_time > datetime.timedelta(days=14):  #当前时间-token创建时间> 数据库设定存活时间 14天
            raise AuthenticationFailed('认证信息过期')

        # 加入缓存
        cache_token="token_"+token.token   #"token_"做标识

        # 14+create-now > 7
        delta=utcnow-token.create_time#当前时间-创建时间
        delta_7=datetime.timedelta(days=7)
        cache.set(cache_token,token.user,min(delta_7,delta).total_seconds())#total_seconds()转化为秒

        # 返回元组
        return token.user,cache_token
View Code

middlewares.py解决跨域:

#解决跨域


from django.middleware.security import SecurityMiddleware
from django.utils.deprecation import MiddlewareMixin


class MyCors(MiddlewareMixin):
    def process_response(self, request, response):
        # 简单请求
        response["Access-Control-Allow-Origin"] = "*"
        # 复杂请求 会先发送预检请求 OPTIONS
        if request.method == "OPTIONS":
            response["Access-Control-Allow-Headers"] = "Content-Type"
            response["Access-Control-Allow-Methods"] = "POST, PUT, PATCH, DELETE"
        return response
View Code

serializer.py序列化

#序列化

from rest_framework import serializers
from course.models import Course

class CourseModelSerializer(serializers.ModelSerializer):#序列化器
    class Meta:
        model=Course
        fields="__all__"

    price = serializers.SerializerMethodField()  #价钱
    level = serializers.SerializerMethodField()  #等级
    rel_teachers = serializers.SerializerMethodField() #讲师
    rel_courses = serializers.SerializerMethodField() #推荐课程
    price_policys = serializers.SerializerMethodField() #价格策略



    def get_price(self,obj):     #价钱
        price_policy = obj.price_policy.all()
        if price_policy:
            return price_policy[0].price
        return ""

    def get_level(self,obj):  #等级
        return obj.get_level_display()  #choice类型

    def get_rel_teachers(self,obj): #讲师
        print(obj)
        # l=[]  #第一种方法
        # for teacher in obj.coursedetail.teachers.all():
        #     l.append()
        # return l
        #第二种方法简化列表生成式
        return [teacher.name for teacher in obj.coursedetail.teachers.all()]


    def get_rel_courses(self,obj):  #推荐课程
        return [(course.title,course.pk) for course in obj.coursedetail.recommend_courses.all()]

    def get_price_policys(self,obj):  #价格策略
        ret=[{"price":price_policy.price,"pk":price_policy.pk,"valid_period":price_policy.valid_period,"valid_period_text":price_policy.get_valid_period_display()} for price_policy in obj.price_policy.all()]

        return ret
View Code

view文件夹下

课程courseView.py

from rest_framework import serializers
from rest_framework.views import APIView
from rest_framework import generics
from rest_framework.viewsets import ModelViewSet
from rest_framework.response import Response
from course.models import Course
from course.utils.serializer import CourseModelSerializer
from course.utils.auth import LoginAuth


class CourseView(ModelViewSet):

    authentication_classes = [LoginAuth]   #认证

    queryset = Course.objects.all()
    serializer_class = CourseModelSerializer

    # def list(self, request, *args, **kwargs):
    #     queryset = self.filter_queryset(self.get_queryset())
    #     page = self.paginate_queryset(queryset)
    #
    #     response={"code":1000,"data":None,"err_msg":""}
    #
    #     if page is not None:
    #         serializer = self.get_serializer(page, many=True)
    #         response["data"]=serializer.data
    #         return self.get_paginated_response(response)
    #
    #     serializer = self.get_serializer(queryset, many=True)
    #     response["data"] = serializer.data
    #     return Response(response)
View Code

分类序列化categoryView.py

from rest_framework import serializers
from rest_framework.views import APIView
from rest_framework import generics
from rest_framework.viewsets import ModelViewSet
from rest_framework.response import Response
from course.models import Category

class CategoryModelSerializer(serializers.ModelSerializer):#序列化器
    class Meta:
        model=Category
        fields="__all__"



class CategoryView(ModelViewSet):  #序列化器
    queryset = Category.objects.all()
    serializer_class = CategoryModelSerializer
View Code

登录login.py

from django.shortcuts import HttpResponse
from rest_framework.views import APIView
from course.models import Account,UserToken
from rest_framework.response import Response

class LoginView(APIView):
    def get_radon_str(self,user):
        import hashlib,time
        ctime = str(time.time())
        md5 = hashlib.md5(bytes(user,encoding="utf-8"))  #MD5加密根据用户名加盐
        md5.update(bytes(ctime,encoding="utf-8"))   #根据时间加盐
        return md5.hexdigest()

    def post(self,request):

        #获取数据
        user= request.data.get("user")
        pwd = request.data.get("pwd")


        #创建响应体
        response = {"date":None,"code":1000}
        try:
            user = Account.objects.filter(username=user,password=pwd).first()
            if user:  #校验成功
                random_str = self.get_radon_str(user.username)
                #数据库更新
                UserToken.objects.update_or_create(user=user,defaults={"token": random_str}) #创建token
                #创建响应体
                response["data"] = {"name":user.username}
                response["token"] = random_str
            else:#检验失败
                #构建响应体
                response["code"] = 1001  #用户名或者密码错误
                response["err_msg"] = "用户名或者密码错误"
        except Exception as e:
            #构建响应体
            response["code"] = 2000 #用户名或者密码错误
            request["err_msg"] = str(e)
        return Response(response)
View Code

表结构models.py

from django.db import models

# Create your models here.

from django.db import models
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
from django.contrib.contenttypes.models import ContentType

# Create your models here.
__all__ = ["Category", "Course", "CourseDetail", "Teacher", "DegreeCourse", "CourseChapter",
           "CourseSection", "PricePolicy", "OftenAskedQuestion", "Comment", "Account", "CourseOutline"]


class Account(models.Model):
    """
    用户表
    """
    username = models.CharField(max_length=32, verbose_name="用户姓名")
    password = models.CharField(max_length=128,verbose_name="密码",null=True)
    type_choices = [(1,"普通用户"),(2,"VIP"),(3,"SVIP")]
    user_type = models.IntegerField(choices=type_choices,default=1)
    # head_img = models.CharField(max_length=256, default='/static/frontend/head_portrait/logo@2x.png',
    #                             verbose_name="个人头像")

    def __str__(self):
        return self.username

    class Meta:
        verbose_name = "11-用户表"
        db_table = verbose_name
        verbose_name_plural = verbose_name
class UserToken(models.Model):
    user = models.OneToOneField("Account")
    token = models.CharField(max_length=32)
    create_time = models.DateTimeField(auto_now_add=True)#auto_now_add自动添加当前时间


class Category(models.Model):
    """课程分类表"""
    title = models.CharField(max_length=32, unique=True, verbose_name="课程的分类")

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = "01-课程分类表"
        db_table = verbose_name
        verbose_name_plural = verbose_name

class Course(models.Model):
    """课程表"""
    title = models.CharField(max_length=128, unique=True, verbose_name="课程的名称")
    course_img = models.ImageField(upload_to="course/%Y-%m", verbose_name='课程的图片',null=True,blank=True)
    category = models.ForeignKey(to="Category", verbose_name="课程的分类")
    COURSE_TYPE_CHOICES = ((0, "付费"), (1, "vip专享"), (2, "学位课程"))
    course_type = models.SmallIntegerField(choices=COURSE_TYPE_CHOICES)
    degree_course = models.ForeignKey(to="DegreeCourse", blank=True, null=True, help_text="如果是学位课程,必须关联学位表")

    brief = models.CharField(verbose_name="课程简介", max_length=1024)
    level_choices = ((0, '初级'), (1, '中级'), (2, '高级'))
    level = models.SmallIntegerField(choices=level_choices, default=1)
    status_choices = ((0, '上线'), (1, '下线'), (2, '预上线'))
    status = models.SmallIntegerField(choices=status_choices, default=0)
    pub_date = models.DateField(verbose_name="发布日期", blank=True, null=True)
    order = models.IntegerField("课程顺序", help_text="从上一个课程数字往后排,尽量间隔几个数字")
    study_num = models.IntegerField(verbose_name="学习人数", help_text="只要有人买课程,订单表加入数据的同时给这个字段+1")

    # order_details = GenericRelation("OrderDetail", related_query_name="course")
    # coupon = GenericRelation("Coupon")
    # 只用于反向查询不生成字段
    price_policy = GenericRelation("PricePolicy")
    often_ask_questions = GenericRelation("OftenAskedQuestion")
    course_comments = GenericRelation("Comment")

    def save(self, *args, **kwargs):
        if self.course_type == 2:
            if not self.degree_course:
                raise ValueError("学位课必须关联学位课程表")
        super(Course, self).save(*args, **kwargs)

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = "02-课程表"
        db_table = verbose_name
        verbose_name_plural = verbose_name


class CourseDetail(models.Model):
    """课程详细表"""
    course = models.OneToOneField(to="Course",related_name='coursedetail')
    hours = models.IntegerField(verbose_name="课程时长", default=7)
    # course_slogan = models.CharField(max_length=125, blank=True, null=True, verbose_name="课程口号")
    video_brief_link = models.CharField(max_length=255, blank=True, null=True)
    summary = models.TextField(max_length=2048, verbose_name="课程概述")
    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 self.course.title

    class Meta:
        verbose_name = "03-课程详细表"
        db_table = verbose_name
        verbose_name_plural = verbose_name


class Teacher(models.Model):
    """讲师表"""
    name = models.CharField(max_length=32, verbose_name="讲师名字")
    brief = models.TextField(max_length=1024, verbose_name="讲师介绍")

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = "04-教师表"
        db_table = verbose_name
        verbose_name_plural = verbose_name


class DegreeCourse(models.Model):
    """
    字段大体跟课程表相同,哪些不同根据业务逻辑去区分
    """
    title = models.CharField(max_length=32, verbose_name="学位课程名字")

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = "05-学位课程表"
        db_table = verbose_name
        verbose_name_plural = verbose_name


class CourseChapter(models.Model):
    """课程章节表"""
    course = models.ForeignKey(to="Course", related_name="course_chapters")
    chapter = models.SmallIntegerField(default=1, verbose_name="第几章")
    title = models.CharField(max_length=32, verbose_name="课程章节名称")

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = "06-课程章节表"
        db_table = verbose_name
        verbose_name_plural = verbose_name
        unique_together = ("course", "chapter")


class CourseSection(models.Model):
    """课时表"""
    chapter = models.ForeignKey(to="CourseChapter", related_name="course_sections")
    title = models.CharField(max_length=32, verbose_name="课时")
    section_order = models.SmallIntegerField(verbose_name="课时排序", help_text="建议每个课时之间空1至2个值,以备后续插入课时")
    section_type_choices = ((0, '文档'), (1, '练习'), (2, '视频'))
    free_trail = models.BooleanField("是否可试看", default=False)
    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")

    def course_chapter(self):
        return self.chapter.chapter

    def course_name(self):
        return self.chapter.course.title

    def __str__(self):
        return "%s-%s" % (self.chapter, self.title)

    class Meta:
        verbose_name = "07-课程课时表"
        db_table = verbose_name
        verbose_name_plural = verbose_name
        unique_together = ('chapter', 'section_link')


class PricePolicy(models.Model):
    """价格策略表"""
    # conten_type  指定表id
    content_type = models.ForeignKey(ContentType)  # 关联course or degree_course
    # 关联的表里的对象id
    object_id = models.PositiveIntegerField()
    #  关联的表里的那个对象
    content_object = GenericForeignKey('content_type', 'object_id')

    valid_period_choices = ((1, '1天'), (3, '3天'),
                            (7, '1周'), (14, '2周'),
                            (30, '1个月'),
                            (60, '2个月'),
                            (90, '3个月'),
                            (120, '4个月'),
                            (180, '6个月'), (210, '12个月'),
                            (540, '18个月'), (720, '24个月'),
                            (722, '24个月'), (723, '24个月'),
                            )
    # 周期
    valid_period = models.SmallIntegerField(choices=valid_period_choices)
    # 价格
    price = models.FloatField()

    def __str__(self):
        return "%s(%s)%s" % (self.content_object, self.get_valid_period_display(), self.price)

    class Meta:
        verbose_name = "08-价格策略表"
        db_table = verbose_name
        verbose_name_plural = verbose_name
        unique_together = ("content_type", 'object_id', "valid_period")


class OftenAskedQuestion(models.Model):
    """常见问题"""
    content_type = models.ForeignKey(ContentType)  # 关联course or degree_course
    object_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:
        verbose_name = "09-常见问题表"
        db_table = verbose_name
        verbose_name_plural = verbose_name
        unique_together = ('content_type', 'object_id', 'question')


class Comment(models.Model):
    """通用的评论表"""
    content_type = models.ForeignKey(ContentType, blank=True, null=True)
    object_id = models.PositiveIntegerField(blank=True, null=True)
    content_object = GenericForeignKey('content_type', 'object_id')

    content = models.TextField(max_length=1024, verbose_name="评论内容")
    account = models.ForeignKey("Account", verbose_name="会员名")
    date = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.content

    class Meta:
        verbose_name = "10-评价表"
        db_table = verbose_name
        verbose_name_plural = verbose_name





class CourseOutline(models.Model):
    """课程大纲"""
    course_detail = models.ForeignKey(to="CourseDetail", related_name="course_outline")
    title = models.CharField(max_length=128)
    order = models.PositiveSmallIntegerField(default=1)
    # 前端显示顺序

    content = models.TextField("内容", max_length=2048)

    def __str__(self):
        return "%s" % self.title

    class Meta:
        verbose_name = "12-课程大纲表"
        db_table = verbose_name
        verbose_name_plural = verbose_name
        unique_together = ('course_detail', 'title')
View Code

 admin.py

from django.contrib import admin

# Register your models here.


from course import models

for field in models.__all__:
    admin.site.register(getattr(models,field))
View Code

 

posted on 2018-11-15 19:32  liangliang123456  阅读(380)  评论(0)    收藏  举报

导航