Django实现教育平台全程记录-----环境配置,用户注册,原页面登录/登出,找回密码,404页面配置

windows虚拟环境安装及配置

pip install virtualenv
virtualenv testvir # 默认在C:\Users\Administrator\testvir\
cd testdir/Scripts

activate.bat  # 进入testdir虚拟环境
deactivate.bat  # 退出环境
##  虚拟环境需要知道当前安装的虚拟环境的目录,这样较麻烦,所以用另一款开发库
pip install virtualenvwrapper-win    
mkvirtualenv testvir2 # 默认安装在 C:\Users\Administrator\Envs\testvir2
deactivate.bat  # 退出当前环境
workon # 查看所有虚拟环境

workon testvir2 # 这样就进入了虚拟环境,就可以在虚拟环境下进行匹配安装了

# pycharm 创建项目导入虚拟环境的python.exe,查看setting中的interpreter下安装了哪些包

配置host 0.0.0.0 ,那么你本机的ip4地址也能访问了。
 

django配置

1. 创建log,static,media[存放用户上传的文件],apps目录,将所有的app(message)放入apps,并在setting中注册app
2. pycharm设置apps目录为mark Directory as sources root,pycharm可以直接from message import views(不用from apps.message import views)
3. cmd的命令行不能from message import views,需要settings中设置,把apps添加进去  import sys  sys.path.insert(0,os.path.join(BASE_DIR,'apps'))
4. 配置mysql数据库
5. python manage.py makemigrations(变更表的比较) // python manage.py migrate (将变更迁徙到数据库)
6. 配置template路径  'DIRS': [os.path.join(BASE_DIR, 'templates')]   
配置static路径:  STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static')

]

django的admin后台管理

1. 创建超级用户:python manage.py createsuperuser
2. settings中该admin后台管理为中文:LANGUAGE_CODE = 'zh-hans'  ,更改时区:TIME_ZONE = 'Asia/Shanghai'  USE_TZ = False
3. 将写好的UserProfile类添加到admin中,urlProfile参考  点击打开链接
 class UserProfileAdmin(admin.ModelAdmin):
    pass
admin.site.register(UserProfile,UserProfileAdmin)
这样就可以管理了

 

使用django的xadmin

1.  windows:https://github.com/sshwsfc/xadmin.git  然后 pip install   xadmin-master.zip (多试几次) ;或者在django的根目录(templates同级目录下)下创建extra_app,解压  xadmin-master.zip将里面的admin文件夹复制到extra_app,再将extra_app 修改权限mark Directory as sources root,这样就能直接用admin了,但是xadmin的依赖包crispy_forms(pip install x-admin 附带下载的)是没有的(也可以直接pip install django-crispy-forms)。linux可以直接pip
2. 注册app : 'xadmin' ,'crispy_forms'  
3. 替换url:  import xadmin   url(r'^xadmin/', xadmin.site.urls),
4. 迁徙xadmin的表 : python manage.py migrate  ,会生成4张xadmin的表,里面的表会自动关联到上面创建的UserProfile表(比如:xadmin_usersettings)
5. 注册app到xadmin后台管理系统:
新建对应的app下新建adminx.py文件,添加model类(继承的AbstractUser用以扩展的User的Model无需注册,会自己注册)
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']  # 添加过滤功能

xadmin.site.register(EmailVerifyRecord,EmailVerifyRecordAdmin)

1.用户登录

1. 用post提交form的用户名和密码,后台进行验证

from django.shortcuts import render,redirect
from django.contrib.auth import authenticate,login
class LoginView(View):
    def get(self,request):
		# 记住来源的url,如果没有则设置为首页('/')
        request.session['login_from'] = request.META.get('HTTP_REFERER', '/')
        return render(request,'login.html')
	def post(self,request):
		form = LoginForm(request.POST)
		if form.is_valid():    # form字段的数据格式是否符合form表单要求
			username = request.POST.get('username')
			password = request.POST.get('password')
			user = authenticate(username=username,password=password)             # 拿用户名和密码去数据中对比是否存在  A 
			if user is not None:
				login(request,user)                
				if user.is_active:
					login(request,user)     # 登录账户,这样xadmin也就登录了
					# 重定向到来源的url
					return redirect(request.session['login_from'])
				else:
					return render(request, 'login.html', {'msg': '用户未激活'})
			else:
				return render(request,'login.html',{'msg':'用户名/密码错误'})    
			else:
				return render(request,'login.html',{'form':form})   # form传到前端,用以显示错误  <div class="error btns login-form-tips" id="jsLoginTips">{% for k,v in form.errors.items %}{{ v }}{% endfor %}{{ msg }}</div>
		# 记住来源的url,如果没有则设置为首页('/')
        request.session['login_from'] = request.META.get('HTTP_REFERER', '/')
        return render(request,'login.html')
	def post(self,request):
		form = LoginForm(request.POST)
		if form.is_valid():    # form字段的数据格式是否符合form表单要求
			username = request.POST.get('username')
			password = request.POST.get('password')
			user = authenticate(username=username,password=password)             # 拿用户名和密码去数据中对比是否存在  A 
			if user is not None:
				login(request,user)                
				if user.is_active:
					login(request,user)     # 登录账户,这样xadmin也就登录了
					# 重定向到来源的url
					return redirect(request.session['login_from'])
				else:
					return render(request, 'login.html', {'msg': '用户未激活'})
			else:
				return render(request,'login.html',{'msg':'用户名/密码错误'})    
			else:
				return render(request,'login.html',{'form':form})   # form传到前端,用以显示错误  <div class="error btns login-form-tips" id="jsLoginTips">{% for k,v in form.errors.items %}{{ v }}{% endfor %}{{ msg }}</div>

在前端想要添加错误信息,那么可以这样写,如果有错就会有提示。为了更有好提示,可以添加样式

{% for k,v in form.errors.items %}{{ v }}{% endfor %}{{ msg }}

2 . 上面的方式只能邮箱,密码登录。通过重写authenticate方法,达到邮箱也可以登录

× 在settings中注册
# Application definition
AUTHENTICATION_BACKENDS = (
    'users.views.CustomBackend',
)

× 然后重写authenticate,这样登录的时候就可以用邮箱登录了。执行顺序 A --> B,最后返回B中的user

from django.db.models import Q
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(Q(username=username)|Q(email=username))  # 获取到username的记录  B
            if user.check_password(password):    # django不支持form表单的明文密码反解,所以只能先将form里的明文passowrd转换成密文,然后和数据库的比对
                return user
        except Exception as e:
            return None

用户登出

from django.contrib.auth import logout
class LogoutView(View):
    def get(self,request):   # 
        logout(request)
        return redirect(request.META.get('HTTP_REFERER', '/'))

2.用户注册

第六章1 100min

第一步:添加验证码登录

× pip install django-simple-captcha==0.4.6   #  https://github.com/mbi/django-simple-captcha
× 配置url  url(r'^captcha/', include('captcha.urls')), ----> 注册app  'captcha',   -----> migrations , migrate
× form表单:

class RegisterForm(forms.Form):
    email = forms.EmailField(required=True,max_length=20)
    password = forms.CharField(required=True,min_length=5)
    captcha = CaptchaField(error_messages={"invalid":u"验证码错误"})
× 视图函数:
class RegisterView(View):
    def get(self,request):
        register_form = RegisterForm()
        return render(request,'register.html',{'register_form':register_form})
    def post(self,request):
        pass

× 前端页面添加: {{ register_form.captcha }}    # 错误则红框标红显示  <div class="form-group marb8 {% if register_form.password.errors %}errorput{% endif %} ">
此时,页面显示验证码。对应的数据库表中生成相应的验证码的值和hash值。同时,前端页面有个hidden的text框,值为该验证码的hash值。
系统会将用户填写的验证码和hidden框中的hash值跟数据库中的值进行联合匹配是否一致。
 

第二步:点击注册并登录按钮,发送邮件至邮箱进行验证

× 完善上面的post方法,点击注册,先在userprofile中保存字段

def post(self,request):  
    register_form = RegisterForm(request.POST)  
    if register_form.is_valid():  
        username = register_form.cleaned_data['email']  
        password = register_form.cleaned_data['password']  
        if UserProfile.objects.get(email=username):
            return render(request,'register.html',{'msg':"用户已存在"})
        user_profile = UserProfile()  
        user_profile.username = username  
        user_profile.emial = username  
        user_profile.password = make_password(password)  
        user_profile.is_active = 0  
        user_profile.save()  
  
        send_register_email(username,"register")    # 调用定义的邮件方法  
        return render(request,"login.html",{'register_form':register_form})  
    else:  
        return render(request,'register.html',{'register_form':register_form})  

× 添加Model EmailVerifyRecord

注:为什么设计的该表需要code和email字段?比如用户需要密码找回,服务器如何才能安全把修改密码的html返回给用户,只能通过发送邮箱等方式让用户点击邮箱中的链接,进入到修改密码的界面(总不能直接给页面让你修改密码)。邮件格式肯定是 localhost/resetpwd/active_code带上激活码这种格式(总不能localhost/resetpwd/email 带上邮箱的名字,这样别人也能修改密码了)。所以就需要一个保存激活码和邮箱关系的表

from utils.email_send import send_register_email
class EmailVerifyRecord(models.Model):
    code = models.CharField(verbose_name=u"验证码",max_length=100)
    email = models.EmailField(verbose_name=u"邮箱")
    send_type = models.CharField(max_length=100,verbose_name=u"验证码类型",choices=(("register","注册"),("forget","找回密码"),('update','修改邮箱')))
    send_time = models.DateTimeField(default=datetime.now,verbose_name=u'发送时间')
    class Meta:
        verbose_name = u"邮箱验证"
        verbose_name_plural = verbose_name
    def __str__(self):
        return "{0},{1}".format(self.email,self.send_time)  # 这会在xadmin后台管理中成功添加数据后返回的导航提示

× settings配置qq邮箱为发送邮箱,
EMAIL_HOST = 'smtp.qq.com'
EMAIL_HOST_USER = '[email protected]'
EMAIL_HOST_PASSWORD = 'spgqttasdasxzrlqnbegh'          # 需要打开qq邮箱的POP3/SMTP服务,发送短信获取该值
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_FROM = '[email protected]'

× 创建utils的python目录并创建email.send.py

import random
from django.core.mail import send_mail
from users.models import EmailVerifyRecord
from DjangoDdu.settings import EMAIL_FROM

def random_str(randomLength=8):
    """生成随机字符串"""
    chars = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789"
    str = ""
    for i in range(randomLength):
            j = random.randint(0,len(chars)-1)
            str += chars[j]
    return str

def send_register_email(email,send_type="register"):
    email_record = EmailVerifyRecord()
    code = random_str(16)
    email_record.code = code
    email_record.email = email
    email_record.send_type = send_type
    email_record.save()

    if send_type == "register":
        email_title = "用户注册链接"
        email_body = "点击下面链接激活账号:http://127.0.0.1:8000/active/{0}".format(code)
        send_status = send_mail(email_title,email_body,EMAIL_FROM,[email])     #发送邮件到注册框填写的邮箱
        if send_status:
            pass

第三步 邮箱激活账户    (把User表中的is_active设置为1)

× url配置      url(r'^active/(?P<active_code>.*)/$',ActiveUserView.as_view(),name='active')

× 视图函数    

class ActiveUserView(View):
    def get(self,request,active_code):
        register_user = EmailVerifyRecord.objects.get(code=active_code)
        if register_user:
            email = register_user.email         # Email 表中的email
            user = UserProfile.objects.get(email=email)  # 根据email查找出User表中的对象
            user.is_active = 1
            user.save()
            return render(request,'login.html')
        else:
            return HttpResponse('激活链接不对')

3.找回密码

找回密码的步骤跟用户注册差不多,不详细写。

× 点击提交,逻辑:将认证邮箱保存在

class ForgetPwdView(View):
    def get(self,request):
        forget_form = ForgetForm()
        return render(request,'forgetpwd.html',{'forget_form':forget_form})
    def post(self,request):
        forget_form = ForgetForm(request.POST)
        if forget_form.is_valid():
            email = forget_form.cleaned_data['email']
            user = UserProfile.objects.filter(email=email)
            if user:  
                send_register_email(email,'forget')   # 将active_code和邮箱 保在EmailVersityRecord表中,作为后续修改密码时候获取相关用户使用
                return HttpResponse('验证码已发送,请注意查收')
            else:
                return render(request, 'forgetpwd.html', {'forget_form': forget_form,'msg':"邮箱不存在"})
        else:
            return render(request,'forgetpwd.html',{'forget_form':forget_form})

× 获取邮箱链接进行密码重置

class ResetView(View):
    def get(self,request,active_code):
        """通过激活码获取对应的邮箱"""
        record_email_query = EmailVerifyRecord.objects.filter(code=active_code)
        if record_email_query:
            email = record_email_query.first().email
            return render(request,'password_reset.html',{'email':email})
        else:
            return render(request,'email_link_fail.html')

× 提交form表单,进行逻辑认证

class ModifyPwdForm(forms.Form):
    password = forms.CharField(required=True,min_length=5)
    password2 = forms.CharField(required=True,min_length=5)
class ModifyPwdView(View):
    def post(self, request):
        modify_pwd_form = ModifyPwdForm(request.POST)
        email = request.POST.get('email')
        if modify_pwd_form.is_valid():
            password = request.POST.get('password')
            password2 = request.POST.get('password2')
            if password != password2:
                return render(request,'password_reset.html',{'msg':'两次密码不一致,请重新输入','email':email})
            email = request.POST.get("email")
            user = UserProfile.objects.get(email=email)
            user.password = make_password(password)
            user.save()
            return redirect('/login/')
        else:
            return render(request,'password_reset.html',{'modify_pwd_form':modify_pwd_form,'email':email})

4.404或500等页面显示

如果想让django显示自定义的http错误提示,那么需要让django进入生产环境,在settings中设置

DEBUG = False

ALLOWED_HOSTS = ["*"]   # × 代表允许所有ip访问

在主程序的url中添加 (users是创建的一个app)

# 全局404页面处理
handler_404 = 'users.views.page_not_found'

在users的app的views中添加,这样就配置完成了。

def page_not_found(request):
    response = render_to_response('404.html',{})     # 好像404.html只能放在templates目录的第一层下,不能新建一个目录
    response.status_code = 404   # 该状态码会影响浏览器的显示
    return response

但是由于设置了debug=false,会认为你是生产环境,staticfiles_dirs就会失效,django就找不到你配置的{% ‘static ’css/com.css ‘ %}的样式文件。需要在settings中设置

STATIC_ROOT = os.path.join(BASE_DIR,'static')

然后在主url文件中添加

from DjangoDdu.settings import MEDIA_ROOT,STATIC_ROOT

urlpatterns = [
    # http错误页面
    url(r'^static/(?P<path>.*)$',serve,{'document_root':STATIC_ROOT}),
]

http错误显示

400错误

遇到访问地址不存在就会找到404.html并显示(比如访问了 http://127.0.0.1:8000/asdasd  这样随意的一个url)。

500错误

1 如果访问了 http://127.0.0.1:8000/course/detail/2000/ 这样的url会找到500.html返回(因为你的网站中只设定了20门课,只能访问到http://127.0.0.1:8000/course/detail/20/ )

2 或者你在一个视图函数中写了 print(1/0)  也会显示500错误

猜你喜欢

转载自blog.csdn.net/qq_34964399/article/details/80369321
今日推荐