# 一 、xadmin安装,注意xadmin不支持python3 #1、pip install xadmin #2、在setting中将xadmin、与其依赖crispy_forms的注册到app中(这里要注意,下载xadmin时候会默认将crispy-forms一起下载,但是在注册app时候,要用下划线,而不是分隔符) INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'xadmin', 'crispy_forms', ] #3、修改django项目中urls.py中 from django.conf.urls import url,include import xadmin from users.views import ActiveUserView urlpatterns = [ url(r'^admin/', xadmin.site.urls,name='admin'), url(r'^captcha/', include('captcha.urls'),name ='captcha' ), url(r'^active/(?P<active_code>.*)/$', ActiveUserView.as_view(),), # (?P)固定写法,P代表Parameter,active_code:参数字段,".*",代表后面所有字符都赋值给active_code ] #4、直接访问后台127.0.0.1/admin 就可以了 #5、使用xadmin替换pip安装的xadmin,去github上下载最新的xadmin,然后解压出来,拷贝里面的xadmin文件夹到项目下 #6、在项目/下创建一个文件夹extra_apps专门用来存放以后项目用到的第三方包,将xadmin拖放进去 #7、mark一下extra_apps,让pycharm把此目录当成搜索目录,在setings.py中添加sys.path.insert(1,os.path.join(BASE_DIR,'extra_apps')),告诉python把此目录当成搜索目录 #8、pip uninstall xadmin 卸载之前通过pip安装的xadmin,直接访问127.0.0.1/admin ,此时运行的就是github上下载下来的源码的xadmin #二、项目中使用xadmin #1、在app下新建adminx.py #2、注册自己的model类到xadmin import xadmin from .models import EmailVerifyRecord class EmailVerifyRecordAdmin(object): #定义admin list_display = ['code', 'email', 'send_type', 'send_time'] # 后台显示哪些列 search_fields = ['code', 'email', 'send_type'] # 搜索,搜索中不能添加时间比较麻烦,放在过滤里面 list_filter = ['code', 'email', 'send_type', 'send_time'] # 过滤 xadmin.site.register(EmailVerifyRecord,EmailVerifyRecordAdmin) #将EmailVerifyRecord的model注册到EmailVerifyRecordAdmin, #这时候重启服务,访问后台就会出现此模块 #3、注册主题,随意找一个adminx写入 from xadmin import views class BaseSetting(object): enable_themes = True #主题 use_bootswatch = True xadmin.site.register(views.BaseAdminView,BaseSetting) #4、修改左上角系统标题、与下方footer名称,菜单折叠,随意找一个adminx写入 from xadmin import views class GlobalSetting(object): site_title = '在线学习管理系统' #左上角系统标题 site_footer = '在线学习网站' #下方footer名称 menu_style = 'accordion' #菜单折叠 xadmin.site.register(views.CommAdminView,GlobalSetting) #5、修改菜单名字为中文,拿user模块来举例 #5.1 在user模块下的apps.py中,UsersConfig中添加属性: verbose_name = u'用户操作' #5.2 然后,在user模块下的__init__.py中写入 default_app_config = 'users.apps.UsersConfig' #6、xadmin常用操作 class BannerAdmin(object): ... model_icon = 'fa fa-group' #具体去百度找 font awesome,只需要替换group ordering = ['-click_num'] # 显示排序 readonly_fields = ['click_num', 'fav_nums'] # 后台不可编辑 exclude = ['add_time'] # 详情不显示add_time 此字段与readonly_fields互斥 relfield_style = 'fk-ajax' # 下拉筛选改为搜索 #保证项目使用最新版本的font awesome解压找到font、css,找到项目下\xadmin\static\xadmin\vendor\font-awesome,替换css与css就是最新版本的 #7、一般外键关联数据在xadmin只能通过在列表选择对应外键数据跳转再去编辑,但是想在详情编辑中,可以直接编辑(只能一层嵌套): class LessonInline(object): model = Lesson extra = 0 class CourseAdmin(object): list_display = ['name','desc','detail','degree','learn_times','students','fav_nums','image','click_num','add_time'] search_fields = ['name','desc','detail','degree','learn_times','students','fav_nums','image','click_num'] list_filter = ['name','desc','detail','degree','learn_times','students','fav_nums','image','click_num','add_time'] model_icon = 'fa fa-book' #图标 ordering = ['-click_num'] #显示排序 readonly_fields = ['click_num','fav_nums']#后台不可编辑 exclude= ['add_time'] #详情不显示add_time 此字段与readonly_fields互斥 relfield_style='fk-ajax' #下拉筛选改为搜索 inlines = [LessonInline] #8、一张表在后台注册成两个管理器,以课程为例,课程一张表,后台分为轮播课程、非轮播课程 #models代码如下: class Course(models.Model): name = models.CharField(verbose_name=u'课程名',max_length=50) is_banner = models.BooleanField(verbose_name=u'是否轮播',default=False) #是否为轮播课程 add_time = models.DateTimeField(verbose_name=u'添加时间',default=datetime.now) class Meta: verbose_name = u'课程' verbose_name_plural = verbose_name def __unicode__(self): return self.name class BannerCourse(Course): '''banner课程''' class Meta: verbose_name = u'轮播课程' verbose_name_plural = verbose_name proxy = True #不会生成表 #adminx代码如下: class CourseAdmin(object): list_display = ['name','is_banner','add_time'] search_fields = ['name','is_banner'] list_filter = ['name','is_banner', 'add_time'] def queryset(self): qs = super(CourseAdmin, self).queryset() qs = qs.filter(is_banner=False) return qs class BannerCourseAdmin(object): list_display = ['name', 'is_banner', 'add_time'] search_fields = ['name', 'is_banner'] list_filter = ['name', 'is_banner', 'add_time'] def queryset(self): qs = super(BannerCourseAdmin, self).queryset() qs = qs.filter(is_banner=True) return qs xadmin.site.register(BannerCourse, BannerCourseAdmin) xadmin.site.register(Course, CourseAdmin) #9、将model中的方法获取的值,在后台列表字段显示 #model中代码如下: class Course(models.Model): name = models.CharField(verbose_name=u'课程名',max_length=50) class Meta: verbose_name = u'课程' verbose_name_plural = verbose_name def get_zj_nums(self): '''获取该课程章节''' return self.lesson_set.all().count() get_zj_nums.short_description = u'章节数' #指定后台显示列表字段名 def __unicode__(self): return self.name #admix中代码如下: class CourseAdmin(object): list_display = ['name','get_zj_nums'] search_fields = ['name'] list_filter = ['name'] #10 在model中定义方法,返回html,在后台以html代码形式显示: #model中代码: class Course(models.Model): name = models.CharField(verbose_name=u'课程名',max_length=50) class Meta: verbose_name = u'课程' verbose_name_plural = verbose_name def go_to(self): from django.utils.safestring import mark_safe return '<a href="http://www.baidu.com">百度</a>' #如果不使用mark_safe,在后台显示的就是一段文本了 go_to.short_description = u'跳转' # 指定后台显示列表字段名 def __unicode__(self): return self.name # admix中代码如下: class CourseAdmin(object): list_display = ['name', 'go_to'] search_fields = ['name'] list_filter = ['name'] #11、xadmin插件开发,集成百度uditor编辑器, #11.1 github上搜素django ueditor,找到zhangfisher/DjangoUeditor,下载并解压, #11.2 切换命令行到解压后的目录执行python setup.py install(如果是虚拟环境开发,进入虚拟环境在进入对应目录) #11.3 将 DjangoUeditor 放入到settings.py中的INSTALLED_APPS #11.4 配置urls.py如下: urlpatterns = [ ... url(r'^ueditor/', include('DjangoUeditor.urls')), ] #11.5 比如给课程加富文本编辑器,去Course的model中引入代码: from DjangoUeditor.models import UEditorField detail = UEditorField(u'课程详情', width=600, height=300, imagePath="course/ueditor/", filePath="course/ueditor/", upload_settings={"imageMaxSize": 1204000},default='') #imagePath:图片上传路径,跟平时写的model中的路径是一样的 #filePath:富文本中文件的路径,跟平时写的model中的路径是一样的 #11.6 给xadmin写插件集成ueditor,在xadmin/plugin下新建ueditor.py(名字随意.py),代码如下: import xadmin from xadmin.views import BaseAdminPlugin,CreateAdminView,UpdateAdminView from DjangoUeditor.models import UEditorField from DjangoUeditor.widgets import UEditorWidget from django.conf import settings class XadminUEditorWidget(UEditorWidget): def __init__(self,**kwargs): self.ueditor_options = kwargs self.Media.js = None super(XadminUEditorWidget,self).__init__(kwargs) class UeditorPlugin(BaseAdminPlugin): def get_field_style(self,attrs,db_field,style,**kwargs): if style == 'ueditor': #这个字段与adminx中的style_fields = {'detail':'ueditor'} 字段对应 if isinstance(db_field,UEditorField): widget = db_field.formfield().widget param = {} param.update(widget.ueditor_settings) param.update(widget.attrs) return {'widget':XadminUEditorWidget(**param)} return attrs def block_extrahead(self,context,nodes): js = '<script type="text/javascript" src="%s"></script>' % (settings.STATIC_URL + "ueditor/ueditor.config.js") js += '<script type="text/javascript" src="%s"></script>' % (settings.STATIC_URL + "ueditor/ueditor.all.min.js") nodes.append(js) xadmin.site.register_plugin(UeditorPlugin,UpdateAdminView) xadmin.site.register_plugin(UeditorPlugin,CreateAdminView) #11.7 在课程的adminx中CourseAdmin加入代码如下: class CourseAdmin(object): .... style_fields = {'detail':'ueditor'} #11.8 如果上传图片csrf_token出错,那就把github上下载下来的源码解压出的文件夹DjangoUeditor复制,替换掉开发环境下的site-packages/DjangoUeditor #因为通过python setup.py install安装的有问题,我下载的是这样,还有一个是他的路由用的是旧版的,如果是新版的django,url改了不再是(),而是[], #这样就需要修改DjangoUeditor/urls.py: #源码: # urlpatterns = patterns('', # url(r'^controller/$',get_ueditor_controller) # ) #修改后: urlpatterns = [ url(r'^controller/$', get_ueditor_controller) ] #11.9 前端展示,全是转义后的html,关闭django模板转义: {% autoescape off%} {{ course.detail }} {% endautoescape %} #12 excel的插件使用:待研究 #三、使用static文件夹,放入css、js、图片等静态资源 #1、在根目录创建static文件夹 #2、在static下创建css、js、img、images等 #3、在settings中添加静态资源文件夹路径支持,内容如下: STATIC_URL = '/static/' STATICFILES_DIRS=( os.path.join(BASE_DIR,'static'),#【注】:这里一定注意,后面那个"," ,元组只有一项必须要加 ) #四、处理直接访问静态html文件 #1、在urls中引入 from django.views.generic import TemplateView #2、在urlpatterns中添加路由支持 url('^$', TemplateView.as_view(template_name='index.html'),name='index') #template_name只需要写名字就可以了 url('^login/$', TemplateView.as_view(template_name='login.html'),name='login') #template_name只需要写名字就可以了 #这样django会直接访问静态页面,不走views中django代码 #五、用户登陆 #1 、指定字段登陆 from django.shortcuts import render from django.contrib.auth import authenticate,login #自定义包 def user_login(request): if request.method == 'POST': user_name = request.POST.get('username') pass_word = request.POST.get('password') user = authenticate(username = user_name,password = pass_word) if user is not None: login(request,user) return render(request,'index.html') else: return render(request) return render(request,'login.html',{}) #2、username、或者email等任何一个字段作为账号登陆 #首先在user_login所在的views.py中定义class from django.contrib.auth.backends import ModelBackend from .models import UserProfile #自定义登陆验证 class CustomBackend(ModelBackend): def authenticate(self, username=None, password=None, **kwargs): try: user = UserProfile.objects.get(username = username) if user.check_password(password): #将外界传进来的password加密后验证 return user else: return None except Exception as e: return None #然后要在settings.py中添加 AUTHENTICATION_BACKENDS = ('users.views.CustomBackend',) #默认验证authenticate使用的是ModelBackend,这样通过重写后,就执行我们自己方法了,","不要忘记 #django查询数据库过滤时候使用“或” user = UserProfile.objects.get(Q(username=account) | Q(mobile=account)) #查询username或者mobile为username的用户 #页面上判断登陆成功: request.user.is_authenticated #六、基于类完成views的书写 #1、修改views.py from django.shortcuts import render from django.contrib.auth import authenticate,login from django.contrib.auth.backends import ModelBackend from django.db.models import Q from django.views.generic.base import View #自定义包 from .models import UserProfile class LoginView(View): def get(self,request):#对应get方法,如果想接受PUT、HEADER、DELETE等可以查看View中声明的 return render(request,'login.html',{}) def post(self,request):#对应post方法,如果想接受PUT、HEADER、DELETE等可以查看View中声明的 user_name = request.POST.get('username') pass_word = request.POST.get('password') user = authenticate(username=user_name, password=pass_word) if user is not None: login(request, user) return render(request, 'index.html') else: return render(request, 'login.html', {'err_msg': '用户名或密码错误'}) #2、修改urls.py中的urlpatterns url(r'^login/$',LoginView.as_view(),name='login'), #七、使用form #1、在app下创建forms.py,写入下面内容创建form from django import forms class LoginForm(forms.Form): username = forms.CharField(required=True,min_length=5,max_length=20) password = forms.CharField(required=True,min_length=5,max_length=20) #2、views中 #django内部包 from django.shortcuts import render from django.contrib.auth import authenticate,login from django.contrib.auth.backends import ModelBackend from django.db.models import Q from django.views.generic.base import View #自定义包 from .models import UserProfile from .forms import LoginForm #自定义登陆验证 class CustomBackend(ModelBackend): def authenticate(self, username=None, password=None, **kwargs): try: user = UserProfile.objects.get(Q(username = username) | Q(mobile=username)) if user.check_password(password): #将外界传进来的password加密后验证 return user else: return None except Exception as e: return None class LoginView(View): def get(self,request):#对应get方法 return render(request,'login.html',{}) def post(self,request):#对应post方法 login_form = LoginForm(request.POST) if login_form.is_valid(): user_name = request.POST.get('username') pass_word = request.POST.get('password') user = authenticate(username=user_name, password=pass_word) if user is not None: login(request, user) return render(request, 'index.html') else: return render(request, 'login.html', {'err_msg': '用户名或密码错误'}) else: print(login_form.errors) return render(request,'login.html',{'login_form':login_form}) #template中 #在class中添加出错样式 {% if login_form.errors.username %}errorput{% endif %} #显示错误信息 { % for key, error in login_form.errors.items %} {{error}} { % endfor %} {{err_msg}} #八、url路径使用与静态文件static使用 #1、url <a style="color:white" class="fr registerbtn" href="{% url 'register' 11 22 %}">注册</a> #11 22为参数 #2、静态资源路径:使用这种方式静态资源不在依赖settings.py中STATIC_URL = '/static/',而是依赖STATICFILES_DIRS #,在根目录创建static,settings.py中添加 STATICFILES_DIRS = ( os.path.join(BASE_DIR, 'static'), ) #在templates中的html中写入: {% load staticfiles %} <link rel="stylesheet" type="text/css" href="{% static 'css/reset.css' %}"> <script src="{% static 'js/jquery.min.js'%}" type="text/javascript"></script> #3、模板继承 #父级模板 base.html {% block title %}我是父模板title{% endblock %} #子模板 {% extends 'base.html' %} {% block title %}我是子模板title{% endblock %} #4、引入子模版 {% include 'page.html' %} #5、模板规则 {{ request.user.mobile|default_if_none:'' }} #如果字段为none让其显示字符串 <li class="{% if forloop.counter|divisibleby:5 %}five{% endif %}"></li> #forloop.counter能被5整除,第5个 <div class="module1_{{ forloop.counter|add:2 }} box"></div> #forloop.counter + 2 #九、django验证码,github搜素 "django captcha",找到“mbi/django-simple-captcha”,点进去查看说明 #1、pip install django-simple-captcha==0.4.6 ,这里我用的0.4.6 #2、将captcha 加入settings.py下的install_app中 #3、 在urls.py中加入,url(r'^captcha/', include('captcha.urls')), #4、运行makemigrations、migrate,创建验证码需要的表 #5、在forms.py中对应的业务的form类中添加注册码,比如注册需要使用验证码,那我就在注册的form中填写内容如下: from django import forms from captcha.fields import CaptchaField class RegisterForm(forms.Form): email = forms.CharField(required=True,min_length=6,max_length=20) password = forms.CharField(required=True, min_length=6, max_length=20) captcha = CaptchaField() #6、在views中实例化RegisterForm传入模板html中 from .forms import RegisterForm class RegisterView(View): def get(self,request): register_form = RegisterForm() return render(request,'register.html',{'register_form':register_form}) #7、在模板html中只需要引用就可以了 {{ register_form.captcha }} #8、后台验证 register_form = RegisterForm() register_form.is_validate() #9、如果验证码不正确,在form.errors中会返回,但是是英文的,自定义验证码错误信息为中文 #在form中将captcha改为如下: captcha = CaptchaField(error_messages={'invalid':u'验证码错误'}) #十、django中给密码加密 from django.contrib.auth.hashers import make_password make_password(password) #十一、django发送邮件 from django.core.mail import send_mail #在settings.py添加发送者邮箱相关信息如下: EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' #email后端 EMAIL_USE_TLS = False #是否使用TLS安全传输协议 EMAIL_USE_SSL = True #是否使用SSL加密,qq企业邮箱要求使用 EMAIL_HOST = 'smtp.exmail.qq.com' #发送邮件的邮箱 的 SMTP服务器,这里用了qq企业邮箱 EMAIL_PORT = 465 #发件箱的SMTP服务器端口 EMAIL_HOST_USER = 'service@eagldasdade.com' #发送邮件的邮箱地址 EMAIL_HOST_PASSWORD = 'asdasdadasd' #发送邮件的邮箱密码 EMAIL_FROM = 'service@eagldasdade.com' #要与EMAIL_HOST_USER保持一致 #在view中 from jiudaoyou.settings import EMAIL_FROM def send_register_email(email): email_title = '注册激活链接' email_body = '请点击下面的链接激活您的账号:http://127.0.0.1:8000/active/{0}'.format('1234') send_arr = [email] #必须是个list,可以发送多个 send_status = send_mail(email_title,email_body,EMAIL_FROM,send_arr) if send_status: pass #十二、扩展django系统自带的user表 #1、在model中创建UserProfile,集成AbstractUser from django.db import models from django.contrib.auth.models import AbstractUser class UserProfile(AbstractUser): #扩充系统的表user,继承了AbstractUser,会把之前系统的user表中字段都继承下来并将新添加字段添加进去 ,去setting中设置AUTH_USER_MODEL = "users.UserProfile" nick_name = models.CharField(verbose_name=u"昵称",max_length=50,default="") birday = models.DateField(verbose_name=u"生日",null=True,blank=True) gender = models.CharField(verbose_name=u"性别",max_length=10,choices=(('male',u'男'),('female',u'女')),default='male') address = models.CharField(verbose_name=u"昵称",max_length=100,default=u'') mobile = models.CharField(verbose_name=u"手机",max_length=11,null=True,blank=True) image = models.ImageField(verbose_name=u"头像",upload_to='media/images/photo/%Y/%m',default='media/images/photo/default.png',max_length=256) class Meta: verbose_name = u'用户' verbose_name_plural = verbose_name def __unicode__(self): return self.username #之前表有username, #2、在settings.py中设置代码如下 AUTH_USER_MODEL = "users.UserProfile" #注意这里没有model,app.类名,这样也默认将user注册在后台admin,不需要单独写注册 #十三、在页面上显示数据库的相对路径图片 #1、配置settings.py代码如下: MEDIA_URL = '/media/'#页面访问路径,在页面显示时候,拼在图片字段前面的路径 MEDIA_ROOT = os.path.join(BASE_DIR,'media') #上传文件的路径,页面显示用不到,这里提一下,上传时候拼在model字段图片前面的路径 #2、在settings.py的 TEMPLATES下的OPTIONS中添加media上下文: 'django.core.context_processors.media', #3、页面上 <img src = "{ MEDIA_URL }}{{ course_org.image }}"/> #MEDIA_URL是配置,如果不配置第2步,MEDIA_URL是取不到值得 #4、配置显示路由,在urls.py的urlpatterns中: from django.views.static import serve from jiudaoyou.settings import MEDIA_ROOT urlpatterns=[ url(r'^media/(?P<path>.*)$',serve,{'document_root':MEDIA_ROOT}) ] #十四、django分页库,github搜索pure pagination,找到“jamespacileo/django-pure-pagination” #1、pip install django-pure-pagination #2、将pure_pagination注册到settings.py的INSTALLED_APPS 中: INSTALLED_APPS = ( ... 'pure_pagination', ) #3、views.py中 all_orgs = CourseOrg.objects.all() page = request.GET.get('page', 1) p = Paginator(all_orgs, 5, request=request) orgs = p.page(page) return render(request,'org-list.html',{ ... 'all_orgs':orgs, }) #4、template的html上 {% for course_org in all_orgs.object_list %} #内容 { % endfor %} {{ all_orgs.render }} #默认页码 #自定义页码 {% load i18n %} <ul class ="pagelist" > # 有上一页显示上一页 {% if all_orgs.has_previous %} <li class ="long" > < a href="?{{ all_orgs.previous_page_number.querystring }}" > 上一页 </a> </li> {% endif %} {% for page in all_orgs.pages %} {% if page %} {% ifequal page all_orgs.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_orgs.has_next %} # 有下一页显示下一页 <li class ="long" > <a href="?{{ all_orgs.next_page_number.querystring }}" > 下一页 </a> </li> {% endif %} </ul> #十五、ModelForm :将model字段映射到form中,不需要在写一次model中的字段,save之后直接保存到数据库 #1、form中 from django import forms from operation.models import UserAsk class UserAskForm(forms.ModelForm): #这里也可以像forms.Form中一样新增字段 class Meta: model = UserAsk # 使用哪个model中的字段 fields = ['name', 'mobile', 'course_name'] # 使用model下某些字段验证 #对每一个字段进行重写验证,必须以clean开头,如下: def clean_mobile(self): mobile = self.cleaned_data['mobile'] #获取用户post后,传进入form的mobile if len(mobile) == 11: return mobile else: raise forms.ValidationError(u'手机号不合法',code='mobile_invalid') #必须抛出这个异常,才能捕获 def clean_name(self): name = self.cleaned_data['name'] #获取用户post后,传进入form的name print(name) print(len(name)) if len(name) > 2: return name else: raise forms.ValidationError(u'姓名非法',code='name_invalid') #必须抛出这个异常,才能捕获 def clean_course_name(self): course_name = self.cleaned_data['course_name'] #获取用户post后,传进入form的course_name print(course_name) if len(course_name) >2: return course_name else: raise forms.ValidationError(u'课程名不合法',code='course_name_invalid') #必须抛出这个异常,才能捕获 #2、views中 from django.views.generic import View from django.shortcuts import render from django.http import JsonResponse #自定义内部包 from .forms import UserAskForm class AddUserAskView(View): def post(self,request): userask_form = UserAskForm(request.POST)#如果不指定instance会新增,指定instance会修改:userask_form.save(commit=True,instance=request.user) if userask_form.is_valid(): userask_form.save(commit=True) #异步ajax返回json return JsonResponse({'status':'success'}) else: # 异步ajax返回json return JsonResponse({'status':'fail','msg':userask_form.errors}) #十六、url命名空间 #1、全局urls.py中 urlpatterns = [ .... url(r'^org/', include('organization.urls',namespace='org')), ] #2、每个应用下的urls.py中 urlpatterns = [ #list url(r'list/$',OrgView.as_view(),name='org_list'), ] #3、模板页面上 <a href="{% url 'org:org_list' %}"></a> #十七、模板页面获取当前课程(course)的章节数量(lesson),由于lesson是存在course这个外键的,所以,在course中可以利用ar的set方向查,Course的model中定义如下: class Course(models.Model): course_org = models.ForeignKey(CourseOrg,verbose_name=u'课程机构',null=True,blank=True) name = models.CharField(verbose_name=u'课程名',max_length=50) desc = models.CharField(verbose_name=u'课程描述', max_length=300) detail = models.TextField(verbose_name=u'课程详情') degree = models.CharField(verbose_name=u'课程等级', choices=(('cj','初级'),('zj','中级'),('cg','高级')),max_length=2) learn_times = models.IntegerField(verbose_name=u'学习时长(分钟数)',default=0) students = models.IntegerField(verbose_name=u'学习人数', default=0) fav_nums = models.IntegerField(verbose_name=u'收藏人数', default=0) image = models.ImageField(verbose_name=u'封面图片', upload_to='course/%Y/%m', default='course/default.png',max_length=256) click_num = models.IntegerField(verbose_name=u'点击数', default=0) add_time = models.DateTimeField(verbose_name=u'添加时间',default=datetime.now) class Meta: verbose_name = u'课程' 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()[:8] #课程与用户是多对多 def __unicode__(self): return self.name #模板html上代码如下: 章节数:{{ course.get_zj_nums }} 用户:{% for user_course in course.get_learn_users%} 用户姓名:{{user_course.user.name}} {% endfor %} #choice 如果是选择类型,类似性别字段为sex,不能直接在模板上{{user.sex}},要写法如下: {{user.get_sex_display}} #此时会显示男、女 #十八、view验证登陆,未登录不让进 #1、创建一个文件mixin_utils.py,内容如下: #python内部包 #django内部包 from django.contrib.auth.decorators import login_required from django.utils.decorators import method_decorator #自定义内部包 class LoginRequiredMixIn(object): @method_decorator(login_required(login_url='/login/')) def dispatch(self, request, *args, **kwargs): return super(LoginRequiredMixIn, self).dispatch(request, *args, **kwargs) #2、在view.py中继承即可: from django.views.generic.base import View from .models import Course,CourseResource from operation.models import UserFavorite,CourseComments,UserCourse class CourseCommentView(LoginRequiredMixIn,View): #这里顺序不能错 '''课程评论信息''' def get(self, request, course_id): vw = 'comments' course = Course.objects.get(id=int(course_id)) all_course_resource = CourseResource.objects.filter(course=course) all_comments = CourseComments.objects.filter(course_id=int(course_id)) return render(request, 'course-comment.html', { 'course': course, 'all_comments': all_comments, 'all_course_resource': all_course_resource, 'vw': vw }) #如果不登录访问CourseCommentView,那就会跳转到login #十九、上传图片 #1、方法一: # form from django import forms from .models import UserProfile class UploadImageForm(forms.ModelForm): '''上传头像form''' class Meta: model = UserProfile # 使用哪个model中的字段 fields = ['image'] # 使用model下某些字段验证 #views class UploadImageView(LoginRequiredMixIn,View): '''用户上传头像''' def post(self,request): image_form = UploadImageForm(request.POST,request.FILES) if image_form.is_valid(): request.user.image = image_form.cleaned_data['image'] request.user.save() return render(request, 'usercenter-info.html', { }) return render(request,'usercenter-info.html',{ }) #2、方法二,利用ModelForm直接报错# : # form from django import forms from .models import UserProfile class UploadImageForm(forms.ModelForm): '''上传头像form''' class Meta: model = UserProfile # 使用哪个model中的字段 fields = ['image'] # 使用model下某些字段验证 #views中 class UploadImageView(LoginRequiredMixIn,View): '''用户上传头像''' def post(self,request): image_form = UploadImageForm(request.POST,request.FILES,instance=request.user) #如果不指定,instance会新增,指定instance会修改 if image_form.is_valid(): image_form.save(commit=True) return render(request, 'usercenter-info.html', { }) return render(request,'usercenter-info.html',{ }) #二十、获取新插入数据的id d = Data() d.save() #id :d.id #二十一、后台重定向 from django.core.urlresolvers import reverse from django.http import HttpResponseRedirect return HttpResponseRedirect(reverse('users:user_index')) #reverse中的写法跟前台模板url后写法相同 {% url 'users:user_index' %} #二十二、配置404、500页面 #404配置 #1、全局url配置参数,handler404,代码如下: urlpatterns = [ ...... ] #全家404页面配置 handler404 = 'users.views.page_not_found' #变量名必须是这个 handler500 = 'users.views.page_error' #变量名必须是这个 #2、在users下的views.py中添加方法如下: #全局404错误页 def page_not_found(request): from django.shortcuts import render_to_response response = render_to_response('404.html',{}) #当然404页面要存在 response.status_code = 404 return response #全局500错误页 def page_error(request): from django.shortcuts import render_to_response response = render_to_response('500.html',{}) response.status_code = 500 return response #3、开启settings.py中的DEFUG为False、配置ALLOWED_HOSTS: DEBUG = False ALLOWED_HOSTS = ['*'] #*代表所有 #4、此时图片、css等是找不到的,因为DEBUG为False的时候,settings.py中的STATIC_URL、STATICFILES_DIRS不在生效,线上都是通过服务器(apache、nginx等)代理的, #当DEBUG为False时候,django认为是生产环境,就自动使者两个变量失效,这时候自己配置就好了: #settings.py中添加代码如下: STATIC_ROOT = os.path.join(BASE_DIR,'static') #配置生产环境下静态资源路径 #urls.py中的urlpatterns中添加代码如下: urlpatterns = [ ... url(r'^static/(?P<path>.*)$',serve,{'document_root':STATIC_ROOT}) ]
django学习2
最新推荐文章于 2024-07-17 11:47:37 发布