一.用户登录注册
1.1 登录
①.settings中设置引用静态资源
STATICFILES_DIRS = ( os.path.join(BASE_DIR,‘static‘), )
②.urls更新
path(‘login/‘,LoginView.as_view(),name = ‘login‘),
③.view.py中写登录的版块
from django.shortcuts import render from django.contrib.auth import authenticate,login from django.contrib.auth.backends import ModelBackend from .models import UserProfile from django.db.models import Q from django.views.generic.base import View from .forms import LoginForm #邮箱和用户名都可以登录 # 基础ModelBackend类,因为它有authenticate方法 class CustomBackend(ModelBackend): def authenticate(self, request, username=None, password=None, **kwargs): try: # 不希望用户存在两个,get只能有一个。两个是get失败的一种原因 Q为使用并集查询 user = UserProfile.objects.get(Q(username=username)|Q(email=username)) # django的后台中密码加密:所以不能password==password # UserProfile继承的AbstractUser中有def check_password(self, raw_password): if user.check_password(password): return user except Exception as e: return None class LoginView(View): def get(self,request): return render(request, ‘login.html‘) def post(self,request): # 实例化 login_form = LoginForm(request.POST) if login_form.is_valid(): # 获取用户提交的用户名和密码 user_name = request.POST.get(‘username‘, None) pass_word = request.POST.get(‘password‘, None) # 成功返回user对象,失败None user = authenticate(username=user_name, password=pass_word) # 如果不是null说明验证成功 if user is not None: # 登录 login(request, user) return render(request, ‘index.html‘) # 只有当用户名或密码不存在时,才返回错误信息到前端 else: return render(request, ‘login.html‘, {‘msg‘: ‘用户名或密码错误‘,‘login_form‘:login_form}) # form.is_valid()已经判断不合法了,所以这里不需要再返回错误信息到前端了 else: return render(request,‘login.html‘,{‘login_form‘:login_form})
④.新建form.py文件写入,并在settings添加
AUTHENTICATION_BACKENDS = ( ‘users.views.CustomBackend‘, )
from django import forms # 登录表单验证 class LoginForm(forms.Form): # 用户名密码不能为空 username = forms.CharField(required=True) password = forms.CharField(required=True,min_length=5)
1.2 注册
①.urls中更新注册需要的url
# 注册 path(‘register/‘, RegisterView.as_view(), name=‘register‘), # 验证码 path(‘captcha/‘,include(‘captcha.urls‘)), # 邮件激活url re_path(‘active/(?P<active_code>.*)/‘,ActiveUserView.as_view(),name=‘user_active‘),
②.settings下INSTALLED_APPS中添加验证码
‘captcha‘,
③.重新生成一下数据库
python manage.py makemigrations
python manage.py migrate
④.更新form.py文件
from django import forms from captcha.fields import CaptchaField class LoginForm(forms.Form): ‘‘‘登录验证表单‘‘‘ username = forms.CharField(required=True) password = forms.CharField(required=True,min_length=5) class RegisterForm(forms.Form): ‘‘‘注册验证表单‘‘‘ email = forms.EmailField(required=True) password = forms.CharField(required=True,min_length=5) # 验证码 captcha = CaptchaField(error_messages={‘invalid‘:‘验证码错误‘})
⑤.更新view.py
from django.shortcuts import render from django.contrib.auth import authenticate,login from django.contrib.auth.backends import ModelBackend from .models import UserProfile,EmailVerifyRecord from django.db.models import Q from django.views.generic.base import View from .forms import LoginForm,RegisterForm from django.contrib.auth.hashers import make_password from utils.email_send import send_register_eamil #邮箱和用户名都可以登录 # 基础ModelBackend类,因为它有authenticate方法 class CustomBackend(ModelBackend): def authenticate(self, request, username=None, password=None, **kwargs): try: # 不希望用户存在两个,get只能有一个。两个是get失败的一种原因 Q为使用并集查询 user = UserProfile.objects.get(Q(username=username)|Q(email=username)) # django的后台中密码加密:所以不能password==password # UserProfile继承的AbstractUser中有def check_password(self, raw_password): if user.check_password(password): return user except Exception as e: return None class LoginView(View): ‘‘‘用户登录‘‘‘ def get(self,request): return render(request, ‘login.html‘) def post(self,request): # 实例化 login_form = LoginForm(request.POST) if login_form.is_valid(): # 获取用户提交的用户名和密码 user_name = request.POST.get(‘username‘, None) pass_word = request.POST.get(‘password‘, None) # 成功返回user对象,失败None user = authenticate(username=user_name, password=pass_word) # 如果不是null说明验证成功 if user is not None: if user.is_active: # 只有注册激活才能登录 login(request, user) return render(request, ‘index.html‘) else: return render(request, ‘login.html‘, {‘msg‘: ‘用户名或密码错误‘, ‘login_form‘: login_form}) # 只有当用户名或密码不存在时,才返回错误信息到前端 else: return render(request, ‘login.html‘, {‘msg‘: ‘用户名或密码错误‘,‘login_form‘:login_form}) # form.is_valid()已经判断不合法了,所以这里不需要再返回错误信息到前端了 else: return render(request,‘login.html‘,{‘login_form‘:login_form}) # 激活用户的view class ActiveUserView(View): def get(self, request, active_code): # 查询邮箱验证记录是否存在 all_record = EmailVerifyRecord.objects.filter(code = active_code) if all_record: for record in all_record: # 获取到对应的邮箱 email = record.email # 查找到邮箱对应的user user = UserProfile.objects.get(email=email) user.is_active = True user.save() # 激活成功跳转到登录页面 return render(request, "login.html", ) # 自己瞎输的验证码 else: return render(request, "register.html", {"msg": "您的激活链接无效"}) class RegisterView(View): ‘‘‘用户注册‘‘‘ def get(self,request): register_form = RegisterForm() return render(request,‘register.html‘,{‘register_form‘:register_form}) def post(self,request): register_form = RegisterForm(request.POST) if register_form.is_valid(): user_name = request.POST.get(‘email‘, None) pass_word = request.POST.get(‘password‘, None) # 实例化一个user_profile对象 user_profile = UserProfile() user_profile.username = user_name user_profile.email = user_name user_profile.is_active = False # 对保存到数据库的密码加密 user_profile.password = make_password(pass_word) user_profile.save() send_register_eamil(user_name,‘register‘) return render(request,‘login.html‘) else: return render(request,‘register.html‘,{‘register_form‘:register_form})
⑥.settings中添加
EMAIL_HOST = "smtp.qq.com" # SMTP服务器主机 EMAIL_PORT = 25 # 端口 EMAIL_HOST_USER = "xxx" # 邮箱地址 EMAIL_HOST_PASSWORD = "xxx" # 授权码 EMAIL_USE_TLS= False EMAIL_FROM = "xxx" # 邮箱地址
⑦.apps下新建utils文件夹,并创建email_send.py文件
from random import Random from django.core.mail import send_mail from users.models import EmailVerifyRecord from RcOnline.settings import EMAIL_FROM # 生成随机字符串 def random_str(random_length=8): str = ‘‘ # 生成字符串的可选字符串 chars = ‘AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789‘ length = len(chars) - 1 random = Random() for i in range(random_length): str += chars[random.randint(0, length)] return str # 发送注册邮件 def send_register_eamil(email, send_type="register"): # 发送之前先保存到数据库,到时候查询链接是否存在 # 实例化一个EmailVerifyRecord对象 email_record = EmailVerifyRecord() # 生成随机的code放入链接 code = random_str(16) email_record.code = code email_record.email = email email_record.send_type = send_type email_record.save() # 定义邮件内容: email_title = "" email_body = "" if send_type == "register": email_title = "Rc注册激活链接" email_body = "请点击下面的链接激活你的账号: http://127.0.0.1:8000/active/{0}".format(code) # 使用Django内置函数完成邮件发送。四个参数:主题,邮件内容,发件人邮箱地址,收件人(是一个字符串列表) send_status = send_mail(email_title, email_body, EMAIL_FROM, [email]) # 如果发送成功 if send_status: pass
1.3 找回密码
①.更新urls.py # 找回,重置,修改密码的url
import xadmin from django.urls import path, include, re_path from django.views.generic import TemplateView from users import views from users.views import LoginView, RegisterView, ActiveUserView, ForgetPwdView, ResetView, ModifyPwdView urlpatterns = [ path(‘xadmin/‘, xadmin.site.urls), # 首页 path(‘‘, TemplateView.as_view(template_name=‘index.html‘),name=‘index‘), # 登录 path(‘login/‘,LoginView.as_view(),name = ‘login‘), # 注册 path(‘register/‘, RegisterView.as_view(), name=‘register‘), # 验证码 path(‘captcha/‘,include(‘captcha.urls‘)), # 邮件激活url re_path(‘active/(?P<active_code>.*)/‘,ActiveUserView.as_view(),name=‘user_active‘), # 找回密码 path(‘forget/‘,ForgetPwdView.as_view(),name=‘forget_pwd‘), # 重置密码 re_path(‘reset/(?P<active_code>.*)/‘, ResetView.as_view(), name=‘reset_pwd‘), # 修改密码url path(‘modify_pwd/‘, ModifyPwdView.as_view(), name=‘modify_pwd‘), ]
②.forms.py中增加找回,重置密码的表单
class ForgetPwdForm(forms.Form): ‘‘‘忘记密码‘‘‘ email = forms.EmailField(required=True) captcha = CaptchaField(error_messages={‘invalid‘: ‘验证码错误‘}) class ModifyPwdForm(forms.Form): ‘‘‘重置密码‘‘‘ password1 = forms.CharField(required=True, min_length=5) password2 = forms.CharField(required=True, min_length=5)
③.email_send.py里面新增找回并重置修改等一系列操作的url
from random import Random from django.core.mail import send_mail from users.models import EmailVerifyRecord from RcOnline.settings import EMAIL_FROM # 生成随机字符串 def random_str(random_length=8): str = ‘‘ # 生成字符串的可选字符串 chars = ‘AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789‘ length = len(chars) - 1 random = Random() for i in range(random_length): str += chars[random.randint(0, length)] return str # 发送注册邮件 def send_register_eamil(email, send_type="register"): # 发送之前先保存到数据库,到时候查询链接是否存在 # 实例化一个EmailVerifyRecord对象 email_record = EmailVerifyRecord() # 生成随机的code放入链接 code = random_str(16) email_record.code = code email_record.email = email email_record.send_type = send_type email_record.save() # 定义邮件内容: email_title = "" email_body = "" if send_type == "register": email_title = "Rc注册激活链接" email_body = "请点击下面的链接激活你的账号: http://127.0.0.1:8000/active/{0}".format(code) # 使用Django内置函数完成邮件发送。四个参数:主题,邮件内容,从哪里发,接受者list send_status = send_mail(email_title, email_body, EMAIL_FROM, [email]) # 如果发送成功 if send_status: pass if send_type == "forget": email_title = "Rc找回密码链接" email_body = "请点击下面的链接找回你的密码: http://127.0.0.1:8000/reset/{0}".format(code) # 使用Django内置函数完成邮件发送。四个参数:主题,邮件内容,从哪里发,接受者list send_status = send_mail(email_title, email_body, EMAIL_FROM, [email]) # 如果发送成功 if send_status: pass
④.view中写找回,重置,修改密码的逻辑
class ForgetPwdView(View): ‘‘‘找回密码‘‘‘ def get(self,request): forget_form = ForgetPwdForm() return render(request,‘forgetpwd.html‘,{‘forget_form‘:forget_form}) def post(self,request): forget_form = ForgetPwdForm(request.POST) if forget_form.is_valid(): email = request.POST.get(‘email‘,None) send_register_eamil(email,‘forget‘) return render(request, ‘send_success.html‘) else: return render(request,‘forgetpwd.html‘,{‘forget_form‘:forget_form}) class ResetView(View): def get(self, request, active_code): all_records = EmailVerifyRecord.objects.filter(code=active_code) if all_records: for record in all_records: email = record.email return render(request, "password_reset.html", {"email":email}) else: return render(request, "active_fail.html") return render(request, "login.html") class ModifyPwdView(View): def post(self, request): modify_form = ModifyPwdForm(request.POST) if modify_form.is_valid(): pwd1 = request.POST.get("password1", "") pwd2 = request.POST.get("password2", "") email = request.POST.get("email", "") if pwd1 != pwd2: return render(request, "password_reset.html", {"email":email, "msg":"密码不一致!"}) user = UserProfile.objects.get(email=email) user.password = make_password(pwd2) user.save() return render(request, "login.html") else: email = request.POST.get("email", "") return render(request, "password_reset.html", {"email":email, "modify_form":modify_form })
二.授课机构相关功能
2.1 机构
①.urls添加机构首页路由
# 机构首页路由 path("org/", include(‘organization.urls‘, namespace="org")), # 处理图片显示的url,使用Django自带serve,传入参数告诉它去哪个路径找,我们有配置好的路径MEDIAROOT re_path(r‘^media/(?P<path>.*)‘, serve, {"document_root": MEDIA_ROOT }),
②.view.py增加逻辑
class OrgView(View): ‘‘‘课程机构‘‘‘ def get(self, request): # 所有课程机构 all_orgs = CourseOrg.objects.all() # 所有城市 all_citys = CityDict.objects.all() # 城市筛选 city_id = request.GET.get(‘city‘,‘‘) if city_id: all_orgs = all_orgs.filter(city_id=int(city_id)) # 类别筛选 category = request.GET.get(‘ct‘,‘‘) if category: all_orgs = all_orgs.filter(category=category) # 热门课程机构排名 hot_orgs = all_orgs.order_by(‘-click_nums‘)[:3] # 学习人数和课程数筛选 sort = request.GET.get(‘sort‘, "") if sort: if sort == "students": all_orgs = all_orgs.order_by("-students") elif sort == "courses": all_orgs = all_orgs.order_by("-course_nums") # 有多少家机构 org_nums = all_orgs.count() # 对课程机构进行分页 # 尝试获取前台get请求传递过来的page参数 # 如果是不合法的配置参数默认返回第一页 try: page = request.GET.get(‘page‘, 1) except PageNotAnInteger: page = 1 # 这里指从allorg中取五个出来,每页显示5个 p = Paginator(all_orgs, 2, request=request) orgs = p.page(page) return render(request, "org-list.html", { "all_orgs": orgs, "all_citys": all_citys, "org_nums": org_nums, ‘city_id‘:city_id, "category": category, ‘hot_orgs‘:hot_orgs, ‘sort‘:sort, })
③.增加分页
INSTALLED_APPS = [ ‘django.contrib.admin‘, ‘django.contrib.auth‘, ‘django.contrib.contenttypes‘, ‘django.contrib.sessions‘, ‘django.contrib.messages‘, ‘django.contrib.staticfiles‘, ‘course‘, ‘operation‘, ‘organization‘, ‘users‘, ‘xadmin‘, ‘crispy_forms‘, ‘captcha‘, ‘pure_pagination‘, ]
④.models下CourseOrg更新
class CourseOrg(models.Model): ORG_CHOICES = ( ("pxjg", u"培训机构"), ("gx", u"高校"), ("gr", u"个人"), ) name = models.CharField(‘机构名称‘,max_length=50) desc = models.TextField(‘机构描述‘) category = models.CharField(max_length=20, choices=ORG_CHOICES, verbose_name=u"机构类别", default="pxjg") click_nums = models.IntegerField(‘点击数‘,default=0) fav_nums = models.IntegerField(‘收藏数‘,default=0) students = models.IntegerField("学习人数",default=0) course_nums = models.IntegerField("课程数",default=0) image = models.ImageField(‘logo‘,upload_to=‘org/%Y/%m‘,max_length=100) address = models.CharField(‘机构地址‘,max_length=150,) city = models.ForeignKey(CityDict,verbose_name=‘所在城市‘,on_delete=models.CASCADE) add_time = models.DateTimeField(default=datetime.now) class Meta: verbose_name = ‘课程机构‘ verbose_name_plural = verbose_name def __str__(self): return self.name
⑤.settings下TEMPLATES增加图片处理器
#添加图片处理器,为了在课程列表中前面加上MEDIA_URL ‘django.template.context_processors.media‘,
2.2 学习咨询
①.新建form.py文件
import re from django import forms from operation.models import UserAsk class UserAskForm(forms.ModelForm): class Meta: model = UserAsk fields = [‘name‘, ‘mobile‘, ‘course_name‘] def clean_mobile(self): """ 验证手机号码是否合法 """ mobile = self.cleaned_data[‘mobile‘] REGEX_MOBILE = "^1[358]\d{9}$|^147\d{8}$|176\d{8}$" p = re.compile(REGEX_MOBILE) if p.match(mobile): return mobile else: raise forms.ValidationError(u"手机号码非法", code="mobile_invalid")
②.更改之前org_list的路由
path("org/", include(‘organization.urls‘, namespace="org")),
并在organization下新建urls.py
from organization.views import OrgView, AddUserAskView, OrgHomeView, OrgCourseView, OrgDescView, OrgTeacherView, AddFavView from django.urls import path,re_path # 要写上app的名字 app_name = "organization" urlpatterns = [ path(‘list/‘,OrgView.as_view(),name=‘org_list‘), path(‘add_ask/‘, AddUserAskView.as_view(), name="add_ask"), # home页面的url re_path(‘home/(?P<org_id>\d+)/‘, OrgHomeView.as_view(), name="org_home"), # 机构课程url re_path(‘course/(?P<org_id>\d+)/‘, OrgCourseView.as_view(), name="org_course"), # 机构介绍 re_path(‘desc/(?P<org_id>\d+)/‘, OrgDescView.as_view(), name="org_desc"), # 机构讲师 re_path(‘teacher/(?P<org_id>\d+)/‘, OrgTeacherView.as_view(), name="org_teacher"), # 收藏 path(‘add_fav/‘, AddFavView.as_view(), name="add_fav"), ]
③.后台逻辑更新
from django.shortcuts import render from django.views.generic import View from .models import CourseOrg,CityDict from pure_pagination import Paginator, EmptyPage, PageNotAnInteger from django.http import HttpResponse from .forms import UserAskForm from operation.models import UserFavorite from django.contrib.auth import authenticate class OrgView(View): ‘‘‘课程机构‘‘‘ def get(self, request): # 所有课程机构 all_orgs = CourseOrg.objects.all() # 所有城市 all_citys = CityDict.objects.all() # 城市筛选 city_id = request.GET.get(‘city‘,‘‘) if city_id: all_orgs = all_orgs.filter(city_id=int(city_id)) # 类别筛选 category = request.GET.get(‘ct‘,‘‘) if category: all_orgs = all_orgs.filter(category=category) # 热门课程机构排名 hot_orgs = all_orgs.order_by(‘-click_nums‘)[:3] # 学习人数和课程数筛选 sort = request.GET.get(‘sort‘, "") if sort: if sort == "students": all_orgs = all_orgs.order_by("-students") elif sort == "courses": all_orgs = all_orgs.order_by("-course_nums") # 有多少家机构 org_nums = all_orgs.count() # 对课程机构进行分页 # 尝试获取前台get请求传递过来的page参数 # 如果是不合法的配置参数默认返回第一页 try: page = request.GET.get(‘page‘, 1) except PageNotAnInteger: page = 1 # 这里指从allorg中取五个出来,每页显示5个 p = Paginator(all_orgs, 2, request=request) orgs = p.page(page) return render(request, "org-list.html", { "all_orgs": orgs, "all_citys": all_citys, "org_nums": org_nums, ‘city_id‘:city_id, "category": category, ‘hot_orgs‘:hot_orgs, ‘sort‘:sort, }) class AddUserAskView(View): """ 用户添加咨询 """ def post(self, request): userask_form = UserAskForm(request.POST) if userask_form.is_valid(): user_ask = userask_form.save(commit=True) # 如果保存成功,返回json字符串,后面content type是告诉浏览器返回的数据类型 return HttpResponse(‘{"status":"success"}‘, content_type=‘application/json‘) else: # 如果保存失败,返回json字符串,并将form的报错信息通过msg传递到前端 return HttpResponse(‘{"status":"fail", "msg":"添加出错"}‘, content_type=‘application/json‘) class OrgHomeView(View): ‘‘‘机构首页‘‘‘ def get(self,request,org_id): current_page = ‘home‘ # 根据id找到课程机构 course_org = CourseOrg.objects.get(id=int(org_id)) # 判断收藏状态 has_fav = False if request.user.is_authenticated: if UserFavorite.objects.filter(user=request.user, fav_id=course_org.id, fav_type=2): has_fav = True # 反向查询到课程机构的所有课程和老师 all_courses = course_org.course_set.all()[:4] all_teacher = course_org.teacher_set.all()[:2] return render(request,‘org-detail-homepage.html‘,{ ‘course_org‘:course_org, ‘all_courses‘:all_courses, ‘all_teacher‘:all_teacher, ‘current_page‘:current_page, ‘has_fav‘:has_fav, }) class OrgCourseView(View): """ 机构课程列表页 """ def get(self, request, org_id): current_page = ‘course‘ # 根据id取到课程机构 course_org = CourseOrg.objects.get(id= int(org_id)) # 通过课程机构找到课程。内建的变量,找到指向这个字段的外键引用 all_courses = course_org.course_set.all() # 判断收藏状态 has_fav = False if request.user.is_authenticated: if UserFavorite.objects.filter(user=request.user, fav_id=course_org.id, fav_type=2): has_fav = True return render(request, ‘org-detail-course.html‘,{ ‘all_courses‘:all_courses, ‘course_org‘: course_org, ‘current_page‘:current_page, ‘has_fav‘: has_fav, }) class OrgDescView(View): ‘‘‘机构介绍页‘‘‘ def get(self, request, org_id): current_page = ‘desc‘ # 根据id取到课程机构 course_org = CourseOrg.objects.get(id= int(org_id)) # 判断收藏状态 has_fav = False if request.user.is_authenticated: if UserFavorite.objects.filter(user=request.user, fav_id=course_org.id, fav_type=2): has_fav = True return render(request, ‘org-detail-desc.html‘,{ ‘course_org‘: course_org, ‘current_page‘:current_page, ‘has_fav‘: has_fav, }) class OrgTeacherView(View): """ 机构教师页 """ def get(self, request, org_id): current_page = ‘teacher‘ course_org = CourseOrg.objects.get(id= int(org_id)) all_teacher = course_org.teacher_set.all() # 判断收藏状态 has_fav = False if request.user.is_authenticated: if UserFavorite.objects.filter(user=request.user, fav_id=course_org.id, fav_type=2): has_fav = True return render(request, ‘org-detail-teachers.html‘,{ ‘all_teacher‘:all_teacher, ‘course_org‘: course_org, ‘current_page‘:current_page, ‘has_fav‘: has_fav, }) class AddFavView(View): """ 用户收藏和取消收藏 """ def post(self, request): fav_id = request.POST.get(‘fav_id‘, 0) # 防止后边int(fav_id)时出错 fav_type = request.POST.get(‘fav_type‘, 0) # 防止int(fav_type)出错 if not request.user.is_authenticated: # 未登录时返回json提示未登录,跳转到登录页面是在ajax中做的 return HttpResponse(‘{"status":"fail", "msg":"用户未登录"}‘, content_type=‘application/json‘) exist_record = UserFavorite.objects.filter(user=request.user, fav_id=int(fav_id), fav_type=int(fav_type)) if exist_record: # 如果记录已经存在,表示用户取消收藏 exist_record.delete() return HttpResponse(‘{"status":"fail", "msg":"已取消收藏"}‘, content_type=‘application/json‘) else: user_fav = UserFavorite() if int(fav_id) > 0 and int(fav_type) > 0: user_fav.user = request.user user_fav.fav_id = int(fav_id) user_fav.fav_type = int(fav_type) user_fav.save() return HttpResponse(‘{"status":"success", "msg":"已收藏"}‘, content_type=‘application/json‘) else: return HttpResponse(‘{"status":"fail", "msg":"收藏出错"}‘, content_type=‘application/json‘)
④.更新course下的models
class Course(models.Model): DEGREE_CHOICES = ( ("cj", "初级"), ("zj", "中级"), ("gj", "高级") ) name = models.CharField("课程名",max_length=50) desc = models.CharField("课程描述",max_length=300) detail = models.TextField("课程详情") degree = models.CharField(‘难度‘,choices=DEGREE_CHOICES, max_length=2) learn_times = models.IntegerField("学习时长(分钟数)",default=0) students = models.IntegerField("学习人数",default=0) fav_nums = models.IntegerField("收藏人数",default=0) image = models.ImageField("封面图",upload_to="courses/%Y/%m",max_length=100) click_nums = models.IntegerField("点击数",default=0) add_time = models.DateTimeField("添加时间",default=datetime.now,) course_org = models.ForeignKey(CourseOrg, on_delete=models.CASCADE, verbose_name="所属机构", null=True, blank=True) class Meta: verbose_name = "课程" verbose_name_plural = verbose_name def __str__(self): return self.name
⑤.更新organization下models # Teacher新增头像
image = models.ImageField( default=‘‘, upload_to="teacher/%Y/%m", verbose_name="头像", max_length=100 )
三.课程相关操作
3.1 课程列表及详情
①.urls.py更新
# 课程url path("course/", include(‘course.urls‘, namespace="course")),
②.course下新建urls.py
from django.urls import path,re_path from .views import CourseListView, CourseDetailView # 要写上app的名字 app_name = "course" urlpatterns = [ path(‘list/‘,CourseListView.as_view(),name=‘course_list‘), # 课程详情 re_path(‘course/(?P<course_id>\d+)/‘, CourseDetailView.as_view(), name="course_detail"), ]
③.view.py增加后台逻辑
from django.shortcuts import render from django.views.generic import View from operation.models import UserFavorite from .models import Course from pure_pagination import Paginator, EmptyPage, PageNotAnInteger class CourseListView(View): def get(self, request): all_courses = Course.objects.all().order_by(‘-add_time‘) # 热门课程推荐 hot_courses = Course.objects.all().order_by(‘-click_nums‘)[:3] # 排序 sort = request.GET.get(‘sort‘, "") if sort: if sort == "students": all_courses = all_courses.order_by("-students") elif sort == "hot": all_courses = all_courses.order_by("-click_nums") # 分页 try: page = request.GET.get(‘page‘, 1) except PageNotAnInteger: page = 1 p = Paginator(all_courses,2 , request=request) courses = p.page(page) return render(request, "course-list.html", { "all_courses":courses, ‘sort‘: sort, ‘hot_courses‘:hot_courses, }) class CourseDetailView(View): ‘‘‘课程详情‘‘‘ def get(self, request, course_id): course = Course.objects.get(id=int(course_id)) # 课程的点击数加1 course.click_nums += 1 course.save() # 课程标签 # 通过当前标签,查找数据库中的课程 has_fav_course = False has_fav_org = False # 必须是用户已登录我们才需要判断。 if request.user.is_authenticated: if UserFavorite.objects.filter(user=request.user, fav_id=course.id, fav_type=1): has_fav_course = True if UserFavorite.objects.filter(user=request.user, fav_id=course.course_org.id, fav_type=2): has_fav_org = True tag = course.tag if tag: # 需要从1开始不然会推荐自己 relate_courses = Course.objects.filter(tag=tag)[:2] else: relate_courses = [] return render(request, "course-detail.html", { ‘course‘:course, ‘relate_courses‘:relate_courses, "has_fav_course": has_fav_course, "has_fav_org": has_fav_org, })
④.更新models
class Course(models.Model): DEGREE_CHOICES = ( ("cj", "初级"), ("zj", "中级"), ("gj", "高级") ) name = models.CharField("课程名",max_length=50) desc = models.CharField("课程描述",max_length=300) detail = models.TextField("课程详情") degree = models.CharField(‘难度‘,choices=DEGREE_CHOICES, max_length=2) learn_times = models.IntegerField("学习时长(分钟数)",default=0) students = models.IntegerField("学习人数",default=0) fav_nums = models.IntegerField("收藏人数",default=0) image = models.ImageField("封面图",upload_to="courses/%Y/%m",max_length=100) click_nums = models.IntegerField("点击数",default=0) tag = models.CharField(‘课程标签‘,default=‘‘,max_length=10) add_time = models.DateTimeField("添加时间",default=datetime.now,) course_org = models.ForeignKey(CourseOrg, on_delete=models.CASCADE, verbose_name="所属机构", null=True, blank=True) category = models.CharField("课程类别",max_length=20, default="") class Meta: verbose_name = "课程" verbose_name_plural = verbose_name def get_zj_nums(self): #获取课程的章节数 return self.lesson_set.all().count() def get_learn_users(self): #获取这门课程的学习用户 return self.usercourse_set.all()[:5] def __str__(self): return self.name
class CourseOrg(models.Model): ORG_CHOICES = ( ("pxjg", u"培训机构"), ("gx", u"高校"), ("gr", u"个人"), ) name = models.CharField(‘机构名称‘,max_length=50) desc = models.TextField(‘机构描述‘) category = models.CharField(max_length=20, choices=ORG_CHOICES, verbose_name=u"机构类别", default="pxjg") click_nums = models.IntegerField(‘点击数‘,default=0) fav_nums = models.IntegerField(‘收藏数‘,default=0) students = models.IntegerField("学习人数",default=0) course_nums = models.IntegerField("课程数",default=0) image = models.ImageField(‘logo‘,upload_to=‘org/%Y/%m‘,max_length=100) address = models.CharField(‘机构地址‘,max_length=150,) city = models.ForeignKey(CityDict,verbose_name=‘所在城市‘,on_delete=models.CASCADE) add_time = models.DateTimeField(default=datetime.now) class Meta: verbose_name = ‘课程机构‘ verbose_name_plural = verbose_name def get_teacher_nums(self): #获取机构的教师数 return self.teacher_set.all().count() def __str__(self): return self.name
原文:https://www.cnblogs.com/JangNara/p/12996322.html