ارسال لینک بازیابی رمز عبور با پیامک در جنگو

سلام این اولین مطلبی هست که توی ویرگول منتشر میکنم . ممنون میشم برای بهتر شدن مطالب بعدی نظراتتو بگین !

اولین کاری که باید بعد اینکه یه پروژه جنگو ساختین اینه که یه اپ با دستور زیر بسازی

python manage.py startapp users

و اون رو توی فایل setting.py اضافه میکنیم

در مرحله بعد باید فیلد شماره تلفن رو به مدل من توی این مثال از کلاس AbstractBaseUser استفاده کردم. در مرحله اول میاییم یه فایل manager.py رو توی اپ users میسازیم. و این کد رو بهش اضافه میکنیم.

from django.contrib.auth.base_user import BaseUserManager

class CustomUserManager(BaseUserManager):
    use_in_migrations = True

    def _create_user(self, phone_number, password, **extra_fields):
        &quot&quot&quot
        Create and save a user with the given phone number and password.
        &quot&quot&quot
        if not phone_number:
            raise ValueError('The given phone number must be set')
        user = self.model(phone_number=phone_number, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_user(self, phone_number, password=None, **extra_fields):
        extra_fields.setdefault('is_staff', False)
        extra_fields.setdefault('is_superuser', False)
        return self._create_user(phone_number, password, **extra_fields)

    def create_superuser(self, phone_number, password=None, **extra_fields):
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)

        if extra_fields.get('is_staff') is not True:
            raise ValueError('Superuser must have is_staff=True.')
        if extra_fields.get('is_superuser') is not True:
            raise ValueError('Superuser must have is_superuser=True.')

        return self._create_user(phone_number, password, **extra_fields)

حالا میاییم توی فایل models.py مدل User خودمون رو تعریف می کنیم. برای اینکار فایل مورد نظر رو به این شکل تغییر میدیم.

from django.db import models
from django.contrib.auth.models import PermissionsMixin
from django.contrib.auth.base_user import AbstractBaseUser
from django.utils.translation import gettext_lazy as _
from django.core.validators import RegexValidator
from django.utils import timezone

from .manager import CustomUserManager


class CustomUser(AbstractBaseUser, PermissionsMixin):
    phone_number = models.CharField(
        _('شماره موبایل'),
        max_length=11,
        unique=True,
        validators=[RegexValidator(regex=r'09(\d{9})$')])
    phone_number_verified = models.BooleanField(default=False)
    is_staff = models.BooleanField(
        _('staff status'),
        default=False,
    )
    is_active = models.BooleanField(
        _('active'),
        default=True,
    )
    date_joined = models.DateTimeField(_('date joined'), default=timezone.now)

    objects = CustomUserManager()
    USERNAME_FIELD = 'phone_number'

    class Meta:
        verbose_name = _('user')
        verbose_name_plural = _('users')

جنگو برای بازیابی رمز عبور راهکاری اندیشیده که با ایمیل کار میکنه شما ایمیل رو وارد میکنین لینک به ایمیل شما فرستاده میشه و روی لینک که کلیک کنید میتونین رمز جدید رو بزارین ما میخواییم این کار رو با شماره موبایل انجام بدیم پس فقط لازمه قسمت اول رو بازنویسی کنیم اولین کاری که انجام میدیم اینه که فرم خودمون روی توی فایل forms.py اضافه کنیم. این کد رو به این فایل اضافه میکنیم.

from django import forms
from django.contrib.auth import get_user_model
from django.core.validators import RegexValidator
from django.contrib.auth.tokens import default_token_generator
from django.utils.encoding import force_bytes
from django.utils.http import urlsafe_base64_encode
from django.contrib.sites.shortcuts import get_current_site
from django.urls import reverse
from django.conf import settings

import kavenegar

UserModel = get_user_model()

class PasswordResetForm(forms.Form):
    phone_number = forms.CharField(label='شماره موبایل', max_length=11,
                                   validators=[RegexValidator(regex=r'09(\d{9})$')])

    def send_sms(self, phone_number, reset_link):
        try:
            api = kavenegar.KavenegarAPI(settings.KAVENEGAR_APIKEY)
            message = f'برای بازیابی رمز عبور روی لینک زیر کلیک کنید \n {reset_link}'
            params = {
                'sender': '1000596446',
                'receptor': phone_number,
                'message': message,
            }
            response = api.sms_send(params)
            print(response)
        except kavenegar.APIException as e:
            print(e)
        except kavenegar.HTTPException as e:
            print(e)

    def get_users(self, phone_number):
        return UserModel.objects.get(phone_number=phone_number)

    def save(self, domain_override=None,
             use_https=False, token_generator=default_token_generator,
             request=None):
        &quot&quot&quot
        Generate a one-use only link for resetting password and send it to the
        user.
        &quot&quot&quot
        phone_number = self.cleaned_data[&quotphone_number&quot]
        if not domain_override:
            current_site = get_current_site(request)
            site_name = current_site.name
            domain = current_site.domain
        else:
            site_name = domain = domain_override
        user = self.get_users(phone_number)
        user_phone_number = user.phone_number
        protocol = 'https' if use_https else 'http'
        uid = urlsafe_base64_encode(force_bytes(user.pk))
        token = token_generator.make_token(user)
        reset_link = protocol + '://' + domain + reverse('password_reset_confirm',
                                                         args=[uid, token])
        print(reset_link)
        self.send_sms(user_phone_number, reset_link)

توی این مثال ما اومدیم برای ارسال پیامک از سرویس کاوه نگار استفاده کردیم در ضمن برای استفاده از کد باید APIKEY که از کاوه نگار میگیرین رو به صورت یه متغییر توی فایل settings.py اضافه کنین به این شکل

KAVENEGAR_APIKEY = 'YOUR_APIKEY' 

الان وقتشه بریم سراغ نوشتن view برای این کار توی فایل view.py این کد رو اضافه میکنیم

from django.contrib.auth.tokens import default_token_generator
from django.contrib.auth import get_user_model
from django.contrib.auth.views import PasswordContextMixin

from django.views.generic import FormView
from django.views.decorators.csrf import csrf_protect

from django.utils.decorators import method_decorator
from django.utils.translation import gettext_lazy as _

from django.urls import reverse_lazy

from .forms import PasswordResetForm

UserModel = get_user_model()

class PasswordResetView(PasswordContextMixin, FormView):
    form_class = PasswordResetForm
    success_url = reverse_lazy('password_reset_done')
    template_name = 'registration/password_reset_form.html'
    token_generator = default_token_generator
    title = _('Password reset')

    @method_decorator(csrf_protect)
    def dispatch(self, *args, **kwargs):
        return super().dispatch(*args, **kwargs)

    def form_valid(self, form):
        phone_number = form.cleaned_data['phone_number']
        try:
            user = UserModel.objects.get(phone_number=phone_number)
            opts = {
                'use_https': self.request.is_secure(),
                'token_generator': self.token_generator,
                'request': self.request,
            }
            form.save(**opts)
        except UserModel.DoesNotExist:
            form.add_error(None, 'این شماره موبایل پیدا نشد!')
            return self.form_invalid(form)
        return super().form_valid(form) 

و در آخر میاییم فایل توی اپ یوزرمون فایل urls.py رو میسازیم و url هایی که نیاز داریم رو توش تعریف می کنیم!

from django.urls import path
from django.contrib.auth import views
from .views import PasswordResetView

urlpatterns = [
    path('password_reset/', PasswordResetView.as_view(), name='password_reset'),
    path('password_reset/done/', views.PasswordResetDoneView.as_view(), name='password_reset_done'),
    path('reset/<uidb64>/<token>/', views.PasswordResetConfirmView.as_view(), name='password_reset_confirm'),
    path('reset/done/', views.PasswordResetCompleteView.as_view(), name='password_reset_complete'),
]

ما توی این آموزش اومدیم فقط یه ویوو رو تغییر دادیم برای بقیه از همون مدل پیش فرض جنگو استفاده کردیم.

و در آخر اینکه فراموش نکنین این فایل urls رو توی urls اصلی پروژتون اضافه کنید.

ممنون از توجهتون.