# course/adminx.py
import xadmin
from .models import Course, Lesson, Video, CourseResource,BannerCourse
from organization.models import CourseOrg
class LessonInline(object):
model = Lesson
extra = 0
class CourseResourceInline(object):
model = CourseResource
extra = 0
# Course的admin管理器
class CourseAdmin(object):
'''课程'''
list_display = [ 'name','desc','detail','degree','learn_times','students','get_zj_nums','go_to'] #显示的字段
search_fields = ['name', 'desc', 'detail', 'degree', 'students'] #搜索
list_filter = [ 'name','desc','detail','degree','learn_times','students'] #过滤
model_icon = 'fa fa-book' #图标
ordering = ['-click_nums'] #排序
readonly_fields = ['click_nums'] #只读字段
exclude = ['fav_nums'] #不显示的字段
# list_editable = ['degree','desc']
# refresh_times = [3,5] #自动刷新(里面是秒数范围)
inlines = [LessonInline,CourseResourceInline] #增加章节和课程资源
style_fields = {"detail": "ueditor"}
def queryset(self):
# 重载queryset方法,来过滤出我们想要的数据的
qs = super(CourseAdmin, self).queryset()
# 只显示is_banner=True的课程
qs = qs.filter(is_banner=False)
return qs
def save_models(self):
# 在保存课程的时候统计课程机构的课程数
# obj实际是一个course对象
obj = self.new_obj
# 如果这里不保存,新增课程,统计的课程数会少一个
obj.save()
# 确定课程的课程机构存在。
if obj.course_org is not None:
#找到添加的课程的课程机构
course_org = obj.course_org
#课程机构的课程数量等于添加课程后的数量
course_org.course_nums = Course.objects.filter(course_org=course_org).count()
course_org.save()
class BannerCourseAdmin(object):
'''轮播课程'''
list_display = [ 'name','desc','detail','degree','learn_times','students']
search_fields = ['name', 'desc', 'detail', 'degree', 'students']
list_filter = [ 'name','desc','detail','degree','learn_times','students']
model_icon = 'fa fa-book'
ordering = ['-click_nums']
readonly_fields = ['click_nums']
exclude = ['fav_nums']
inlines = [LessonInline,CourseResourceInline]
def queryset(self):
#重载queryset方法,来过滤出我们想要的数据的
qs = super(BannerCourseAdmin, self).queryset()
#只显示is_banner=True的课程
qs = qs.filter(is_banner=True)
return qs
class LessonAdmin(object):
'''章节'''
list_display = ['course', 'name', 'add_time']
search_fields = ['course', 'name']
#这里course__name是根据课程名称过滤
list_filter = ['course__name', 'name', 'add_time']
class VideoAdmin(object):
'''视频'''
list_display = ['lesson', 'name', 'add_time']
search_fields = ['lesson', 'name']
list_filter = ['lesson', 'name', 'add_time']
class CourseResourceAdmin(object):
'''课程资源'''
list_display = ['course', 'name', 'download', 'add_time']
search_fields = ['course', 'name', 'download']
list_filter = ['course__name', 'name', 'download', 'add_time']
# 将管理器与model进行注册关联
xadmin.site.register(Course, CourseAdmin)
xadmin.site.register(BannerCourse, BannerCourseAdmin)
xadmin.site.register(Lesson, LessonAdmin)
xadmin.site.register(Video, VideoAdmin)
xadmin.site.register(CourseResource, CourseResourceAdmin)
显示字段 list_display = (‘action_time’, ‘user’, ‘ip_addr’, ‘str’, ‘link’)
筛选 list_filter = [‘user’, ‘action_time’]
搜索 search_fields = [‘ip_addr’, ‘message’]
图标 model_icon = ‘fa fa-cog’
# users/adminx.py
import xadmin
from .models import EmailVerifyRecord,Banner
from xadmin import views
# 创建xadmin的最基本管理器配置,并与view绑定
class BaseSetting(object):
# 开启主题功能
enable_themes = True
use_bootswatch = True
# 全局修改,固定写法
class GlobalSettings(object):
# 修改title
site_title = 'imooc后台管理界面'
# 修改footer
site_footer = '科比的公司'
# 收起菜单 将每个数据库的表收起
menu_style = 'accordion'
#xadmin中这里是继承object,不再是继承admin
class EmailVerifyRecordAdmin(object):
# 显示的列
list_display = ['code', 'email', 'send_type', 'send_time']
# 搜索的字段
search_fields = ['code', 'email', 'send_type']
# 过滤
list_filter = ['code', 'email', 'send_type', 'send_time']
class BannerAdmin(object):
list_display = ['title', 'image', 'url','index', 'add_time']
search_fields = ['title', 'image', 'url','index']
list_filter = ['title', 'image', 'url','index', 'add_time']
xadmin.site.register(EmailVerifyRecord,EmailVerifyRecordAdmin)
xadmin.site.register(Banner,BannerAdmin)
# 将基本配置管理与view绑定
xadmin.site.register(views.BaseAdminView,BaseSetting)
# 将title和footer信息进行注册
xadmin.site.register(views.CommAdminView,GlobalSettings)
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 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 HttpResponseRedirect(reverse('index'))
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})
设置redis Djangosession
这里采用默认的mysql保存
from django.contrib.auth.hashers import make_password
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)
# 如果用户已存在,则提示错误信息
if UserProfile.objects.filter(email = user_name):
return render(request, 'register.html', {'register_form':register_form,'msg': '用户已存在'})
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})
# 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放入链接
if send_type == 'update_email':
code = random_str(4)
else:
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 = "NBA注册激活链接"
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
elif send_type == "forget":
email_title = "NBA找回密码链接"
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
elif send_type == "update_email":
email_title = "NBA邮箱修改验证码"
email_body = "你的邮箱验证码为{0}".format(code)
# 使用Django内置函数完成邮件发送。四个参数:主题,邮件内容,从哪里发,接受者list
send_status = send_mail(email_title, email_body, EMAIL_FROM, [email])
# 如果发送成功
if send_status:
pass
settings
EMAIL_HOST = "smtp.qq.com" # SMTP服务器主机
EMAIL_PORT = 25 # 端口
EMAIL_HOST_USER = "" # 邮箱地址
EMAIL_HOST_PASSWORD = "" # 授权码
EMAIL_USE_TLS = False
EMAIL_FROM = "" # 邮箱地址
# 激活用户
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()
# 验证码不对的时候跳转到激活失败页面
else:
return render(request,'active_fail.html')
# 激活成功跳转到登录页面
return render(request, "login.html", )
在settings.py定义
# 上传图片
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR,'media')
在root目录下设置media文件夹
在models.py中定义文件路径
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)
tag = models.CharField('机构标签',max_length=10,default='全国知名')
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)
1.settings.py
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')]
,
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
#添加图片处理器,为了在课程列表中前面加上MEDIA_URL
'django.template.context_processors.media',
],
},
},
]
2.设置图片路径,使用{{ MEDIA_URL }}{{ course_org.image }}
{% for course_org in all_orgs.object_list %}
<dl class="des difdes">
<dt>
<a href="{% url 'org:org_home' course_org.id %}">
<img width="200" height="120" class="scrollLoading"
data-url="{{ MEDIA_URL }}{{ course_org.image }}"/>
a>
dt>
<dd>
<div class="clearfix">
<a href="org-detail-homepage.html">
<h1>{{ course_org.name }}h1>
<div class="pic fl">
<img src="{% static 'images/authentication.png' %}"/>
<img src="{% static 'images/gold.png' %}"/>
div>
a>
div>
<ul class="cont">
<li class="first"><p class="pic9">课程数:<span>1span>p>
<p class="c7">学习人数:<span>1000span>p>li>
<li class="c8" style="padding-left:18px;">北京市海淀区中关村北大街li>
<li class="pic10" style="padding-left:18px;">经典课程:
<a href="/diary/19/">c语言基础入门a>
<a href="/diary/16/">数据库基础a>
li>
ul>
dd>
<div class="buy start_groupbuy jsShowPerfect2" data-id="22"><br/>联系<br/>服务div>
dl>
{% endfor %}
pure_pagination 对Django的分页paginate进行封装, 在settings.py的INSTALLED_APPS设置pure_pagination
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',
'DjangoUeditor',
]
from pure_pagination import Paginator, EmptyPage, PageNotAnInteger
class OrgView(View):
'''课程机构'''
def get(self, request):
# 所有课程机构
all_orgs = CourseOrg.objects.all()
# 所有城市
all_citys = CityDict.objects.all()
# 机构搜索功能
search_keywords = request.GET.get('keywords', '')
if search_keywords:
# 在name字段进行操作,做like语句的操作。i代表不区分大小写
# or操作使用Q
all_orgs = all_orgs.filter(Q(name__icontains=search_keywords) | Q(desc__icontains=search_keywords))
# 城市筛选
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)
# 对课程机构进行分页
# 尝试获取前台get请求传递过来的page参数
# 如果是不合法的配置参数默认返回第一页
try:
page = request.GET.get('page', 1)
except PageNotAnInteger:
page = 1
# 这里指从allorg中取五个出来,每页显示2个,可以在settings中设置分页显示数量
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,
})
<div class="pageturn">
<ul class="pagelist">
{% if all_courses.has_previous %}
<li class="long"><a href="?{{ all_courses.previous_page_number.querystring }}">上一页a>li>
{% endif %}
{% for page in all_courses.pages %}
{% if page %}
{% ifequal page all_courses.number %}
<li class="active"><a href="?{{ page.querystring }}">{{ page }}a>li>
{% else %}
<li><a href="?{{ page.querystring }}" class="page">{{ page }}a>li>
{% endifequal %}
{% else %}
<li class="none"><a href="">...a>li>
{% endif %}
{% endfor %}
{% if all_courses.has_next %}
<li class="long"><a href="?{{ all_courses.next_page_number.querystring }}">下一页a>li>
{% endif %}
ul>
div>
集成DjangoUeditor时,出现错误,错误提示为:
from widgets import UEditorWidget,AdminUEditorWidget
ImportError: No module named ‘widgets’
经查发现,DjangoUeditor是基于Python 2.7的,对Python3的支持有问题。导致widgets.py文件出错,不能import。解决方法为修改widgets.py或者采用网上修改好的版本
参考
https://blog.csdn.net/zhch1979/article/details/104684122/
https://blog.csdn.net/weixin_43063753/article/details/87466738