django的一些用法的积累与总结

本文总结了使用Django搭建网站时的经验,包括发送邮件设置、用户密码保存、自定义表单验证、多参数URL写法和激活码生成。详细介绍了在Django中配置SMTP服务,确保密码安全,自定义表单验证规则,以及如何构建用户激活功能。
摘要由CSDN通过智能技术生成

前言

最近又要用到django去搭建网站,之前用的东西需要花一些时间去恢复记忆,同时还需要学习一些新的知识,进一步提升自己使用django的能力,因此写这篇博客持续更新使用过程中积累的一些技巧,知识和用法等。
目前我自己写了一个认证系统,包括登入登出,注册激活,密码找回等功能,放在了github仓库中,有使用django-registration-redux不适合的,或者需要个性化定制认证功能的,可以考虑使用和优化这个认证系统。以下的代码大部分来自于该项目。

发送邮件设置

要使用django发送邮件,事先需要做一些设置,这里我以腾讯企业邮箱为例。

  • 打开邮箱的smtp发送邮件服务,一般在设置中的客户端设置中
    在这里插入图片描述
  • 然后在yourapp/settings中设置如下内容
EMAIL_HOST = 'smtp.exmail.qq.com'
EMAIL_PORT = '465'
EMAIL_HOST_USER = 'xxx@xxx.com'
EMAIL_HOST_PASSWORD = 'xxxx'
DEFAULT_FROM_EMAIL = 'xxx@xxx.com'
EMAIL_USE_SSL = True
  • 之后使用django.core.mail中的send_mail发送邮件即可
from django.core.mail import send_mail
send_mail(subject,message,from_email,recipient_list)
#subject:发送主题
#message:发送内容
#from_email:对应settings中的DEFAULT_FROM_EMAIL
#recipient_list 发送人列表,例如[a@xx.com, b@xx.com]

保存用户密码

实际上,无论是django.forms.Form,还是django.forms.ModelForm,都仅仅是发挥表单提交和表单验证的功能,用户的密码在存到数据库的时候是不会加密的,因此,需要手动加密,一般的方法,这里引用django基础教程中的方法,先保存form模型到数据库,然后再根据用户名提取到user对象,之后再使用user.set_password()的方法给密码加密,例子如下:

if request.method == 'POST':
        form = Registration_Form(request.POST)
        if form.is_valid():
            userform = form.save(commit=False)
            userform.is_active = False #初始用户未激活
            userform.save()

            username = form.cleaned_data['username']
            email = form.cleaned_data['email']
            user = User.objects.get(username=username)
            user.set_password(user.password) #form保存时不会自动加密,因此这里需要手动加密
            user.userauth = UserAuth(user=user)
            user.save()
            user.userauth.send_activation_email(request,purpose='registration')
            return render(request,'user_auth/registration_complete.html',{'username':username,
            'email':email})
        else:
            print(form.errors)
            return render(request,'user_auth/registration.html',{'form':form})
            
    form = Registration_Form()
    return render(request,'user_auth/registration.html',{'form':form}) 

自定义form表单验证

要对表单的一些字段或者内容进行自定义验证的话,可以通过在form 类中添加clean()和clean_yourfield()方法来增加验证内容,如下的例子,自定义方法验证邮箱的唯一性和两次输入的密码是否相同的form类,需要注意的是django默认的User中邮箱是可以重复的,因此我们需要自己去检查邮箱的唯一性。另外,除去User模型中有的字段,我们可以额外添加一些字段或者重写其中的字段,而Meta类中的field是有顺序的,如果你在模板中使用for循环来遍历字段的话,它将决定最终字段的显示的顺序。

class Registration_Form(forms.ModelForm):

    username = forms.CharField(max_length=64,label='用户名',
        widget=forms.TextInput(attrs={'placeholder':'用户名'}),
        # error_messages={'required':'不能为空','max_length':'要求64个字符以内'}
        )
    confirm_password = forms.CharField(label='重新输入密码',max_length=64,widget=forms.PasswordInput(attrs={'class':'form-control',
    'placeholder':'重复输入密码',
    }))
    password = forms.CharField(label='登陆密码',max_length=64,widget=forms.PasswordInput(attrs={'class':'form-control',
    'placeholder':'登陆密码',
    }))
    email = forms.EmailField(label='用户邮箱',widget=forms.EmailInput(attrs={'placeholder':'用户邮箱'}))
    
    class Meta:
        model = User
        fields = ['username','password','confirm_password','email'] #添加confirm_password以调整顺序

    def clean(self):
        if self.cleaned_data['password'] != self.cleaned_data['confirm_password']:
            raise forms.ValidationError('两次密码输入不一致,请检查!',code='password error')
           
        return self.cleaned_data

    def clean_email(self): #函数名是严格限制的 clean+下划线+字段
        """
        用于验证邮箱的唯一性
        """
        if User.objects.filter(email__exact=self.cleaned_data['email']):
            raise forms.ValidationError('该Email已经注册过了,请检查!',code='invalid email')
        return self.cleaned_data['email']

可以看到,这里还使用了forms.ValidationError来自定义错误说明,它们最终将被添加到form.errors中。
这里特别说明的是在ModelForm中的字段,最终是先验证ModelForm中的字段,然后再验证自定义的字段,因此如果我这里想写一个clean_password(self)的方法来使用self.cleaned_data[‘confirm_password’]就会KeyError的的错误,因此最好的额办法是写一个clean_confirm_password(self)的方法中引用self.cleaned_data[‘password’],因为此时的password的key已经存在了!

模板中有多个参数的url写法

{% url 'user_auth:registration_resend_email' username email %}

这里的username和email都是即将传递给名为registration_resend_email的URL的参数,最终找到的URL如下:

'registration/resend_email/<username>/<email>/'

激活码的生成

通过查看django-registration-redux的源码,学习到了如何将用户激活的功能集成到User的关联模型中,我们只需要创建一个与User 有OneToOneField()的Userauth模型,然后在该模型下写认证功能,可以直接引用self.user和self.save()以及self.yourfield来构建激活码的生成及验证,以下是代码:

from datetime import datetime,timedelta
import hashlib
import string
import os

from django.db import models
from django.contrib.auth.models import User
from django.core.mail import send_mail
from django.utils.crypto import get_random_string
from django.conf import settings 

class UserAuth(models.Model):
    
    user = models.OneToOneField(User,on_delete=models.CASCADE)

    activation_time = models.DateTimeField(default=datetime.now())

    activation_key = models.CharField(max_length=64,blank=True)

    activation_valid = models.BooleanField(default=False)

    def __str__(self):
        return self.user

    def generate_activation_key(self,save=True):
        """
        生成64位随机激活码
        """
        random_string = get_random_string(length=32,allowed_chars=string.printable)
        self.activation_key = hashlib.sha256(random_string.encode('utf-8')).hexdigest()

        if save:
            self.save()

        return self.activation_key

    def send_activation_email(self,request,purpose='reset_password'):
        """
        用于给用户发送注册确认邮件或者密码重置激活邮件
        purpose = [ reset_password,registration ]
        这里特别需要注意的是activation_url的构建
        purpose的设置是以urls.py中设置的路径关联的
        因为在urls.py中设置了激活URL为:
        resent_password/activation/(P<activation_key>[\w-]+)
        registration/activation/(P<activation_key>[\w-]+)
        因此,这里我拼了一个这样的激活路径,如果后续修改了url,那么
        这里的activation_url也必须要修改以适应新的激活URL
        """
        activation_key = self.generate_activation_key(save=True)
        activation_url = 'http://' + "/".join([request.META['HTTP_HOST'],
                'accounts',purpose,'activation',activation_key])
        if purpose == 'registration':
            subject = getattr(settings,'REGISTRATION_SUBJECT')
            message = getattr(settings,'REGISTRATION_MESSAGE')
        elif purpose == 'reset_password':
            subject = getattr(settings,'RESET_PASSWORD_SUBJECT')
            message = getattr(settings,'RESET_PASSWORD_MESSAGE')
        if subject and message:
            message = message.format(
                username=self.user.username,
                activation_url=activation_url,
                sender=getattr(settings,'EMAIL_HOST_USER'),
                time=datetime.now())

        from_email = getattr(settings,'DEFAULT_FROM_EMAIL')
        recipient_list = [ self.user.email ]
        send_mail(subject,message,from_email,recipient_list)
        #保存发送激活码时间
        self.activation_time = datetime.now()
        self.activation_valid = True
        self.save()
        return True
    
    def confirm_activation_key(self):
        """
        确认激活码是否有效且验证时间未过期
        这里特别需要说明的是activation_valid值
        它主要是用来保证用户激活及密码重置以后
        原来的激活或者密码重置界面将无法使用
        默认情况下是false
        """
        expired_days = getattr(settings,'EXPIRED_DAYS') or 1
        is_not_expired = self.activation_time + timedelta(expired_days) > datetime.now()
        is_valid = self.activation_valid
        return is_valid and is_not_expired
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值