django学习2

# 一 、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})
]




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值