<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های Reza Heydari</title>
        <link>https://virgool.io/feed/@reza.heydari</link>
        <description></description>
        <language>fa</language>
        <pubDate>2026-06-07 15:49:35</pubDate>
        <image>
            <url>https://static.virgool.io/images/default-avatar.jpg</url>
            <title>Reza Heydari</title>
            <link>https://virgool.io/@reza.heydari</link>
        </image>

                    <item>
                <title>جنگو - Test Runner</title>
                <link>https://virgool.io/@reza.heydari/%D8%AC%D9%86%DA%AF%D9%88-test-runner-lewh3tf97w8o</link>
                <description>توی این مطلب میخواییم یه نگاهی کوتاه به Test Runner در جنگو بندازیم.تست رانر ( Test Runner ) یه قسمت از تست فریمورک هست که تستایی که نوشتین پیدا میکنه و اجراشون میکنه. شما می تونین قسمتای مختلف این تست رانر رو شخصی سازی کنید. تستا تو جنگو از یه کلاس Test Runner یه اسم ‍‍DiscoverRunner استفاده میکنه. این کلاس میاد تستای شمارو پیدا میکنه دیتابیس تستون رو میسازه. در کل میاد تستارو پیدا میکنه تنطیمات انجام میده بعدم اجراشون میکنه. برای اینکه بتونین این کلاس رو توسعه بدین یا شخصی سازی کنین باید یه کلاس که از این کلاس ارث میبره رو بنویسین و توی فایل settings.py پروژتون بیایین متغیر TEST_RUNNER رو برابر این کلاستون قرار بدین. برای مثال برای اینکه اطمینان پیدا کنیم که همه هشدار هامون رو نمایش بدیم بدون اینکه نیاز داشته باشه -W رو بزارین هر دفعه که تستاتون رو اجرا میکنین. میتونین از کد زیر استفاده کنیم. # example/tests/runner.py
import warnings
from django.test.runner import DiscoverRunner

class ExampleTestRunner(DiscoverRunner):
    def run_tests(self, *args, **kwargs):
        # Show all warnings once, especially to show DeprecationWarning
        # messages which Python ignores by default
        warnings.simplefilter(&amp;quotdefault&amp;quot)
        return super().run_tests(*args, **kwargs)توی این کد ما اومدیم متد run_tests رو بازنویسی کردیم. بعدش میاییم توی فایل settings متغیر TEST_RUNNER مینویسیم به این شکل: TEST_RUNNER = &amp;quotexample.tests.runner.ExampleTestRunner&amp;quotشما میتونین با این روش پروسه تست هاتون توی جنگو رو توسعه بدین ...برای اطلاعات بیشتر میتونین این لینک در مورد تست رانر توی داکیومنت خود جنگو بخونین.. امیدوارم مفید بوده باشه. منابعSpeed Up Your Django Tests - Adam Johnson Advanced testing topics </description>
                <category>Reza Heydari</category>
                <author>Reza Heydari</author>
                <pubDate>Thu, 09 Jul 2020 01:38:32 +0430</pubDate>
            </item>
                    <item>
                <title>ارسال لینک بازیابی رمز عبور با پیامک در جنگو</title>
                <link>https://virgool.io/cheyab-blog/%D8%A7%D8%B1%D8%B3%D8%A7%D9%84-%D9%84%DB%8C%D9%86%DA%A9-%D8%A8%D8%A7%D8%B2%DB%8C%D8%A7%D8%A8%DB%8C-%D8%B1%D9%85%D8%B2-%D8%B9%D8%A8%D9%88%D8%B1-%D8%A8%D8%A7-%D9%BE%DB%8C%D8%A7%D9%85%DA%A9-%D8%AF%D8%B1-%D8%AC%D9%86%DA%AF%D9%88-adp6ovcsapnu</link>
                <description>سلام این اولین مطلبی هست که توی ویرگول منتشر میکنم . ممنون میشم برای بهتر شدن مطالب بعدی نظراتتو بگین ! اولین کاری که باید بعد اینکه یه پروژه جنگو ساختین اینه که یه اپ با دستور زیر بسازی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):
        &amp;quot&amp;quot&amp;quot
        Create and save a user with the given phone number and password.
        &amp;quot&amp;quot&amp;quot
        if not phone_number:
            raise ValueError(&#039;The given phone number must be set&#039;)
        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(&#039;is_staff&#039;, False)
        extra_fields.setdefault(&#039;is_superuser&#039;, False)
        return self._create_user(phone_number, password, **extra_fields)

    def create_superuser(self, phone_number, password=None, **extra_fields):
        extra_fields.setdefault(&#039;is_staff&#039;, True)
        extra_fields.setdefault(&#039;is_superuser&#039;, True)

        if extra_fields.get(&#039;is_staff&#039;) is not True:
            raise ValueError(&#039;Superuser must have is_staff=True.&#039;)
        if extra_fields.get(&#039;is_superuser&#039;) is not True:
            raise ValueError(&#039;Superuser must have is_superuser=True.&#039;)

        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(
        _(&#039;شماره موبایل&#039;),
        max_length=11,
        unique=True,
        validators=[RegexValidator(regex=r&#039;09(\d{9})$&#039;)])
    phone_number_verified = models.BooleanField(default=False)
    is_staff = models.BooleanField(
        _(&#039;staff status&#039;),
        default=False,
    )
    is_active = models.BooleanField(
        _(&#039;active&#039;),
        default=True,
    )
    date_joined = models.DateTimeField(_(&#039;date joined&#039;), default=timezone.now)

    objects = CustomUserManager()
    USERNAME_FIELD = &#039;phone_number&#039;

    class Meta:
        verbose_name = _(&#039;user&#039;)
        verbose_name_plural = _(&#039;users&#039;)جنگو برای بازیابی رمز عبور راهکاری اندیشیده که با ایمیل کار میکنه شما ایمیل رو وارد میکنین لینک به ایمیل شما فرستاده میشه و روی لینک که کلیک کنید میتونین رمز جدید رو بزارین ما میخواییم این کار رو با شماره موبایل انجام بدیم پس فقط لازمه قسمت اول رو بازنویسی کنیم  اولین کاری که انجام میدیم اینه  که فرم خودمون روی توی فایل 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=&#039;شماره موبایل&#039;, max_length=11,
                                   validators=[RegexValidator(regex=r&#039;09(\d{9})$&#039;)])

    def send_sms(self, phone_number, reset_link):
        try:
            api = kavenegar.KavenegarAPI(settings.KAVENEGAR_APIKEY)
            message = f&#039;برای بازیابی رمز عبور روی لینک زیر کلیک کنید \n {reset_link}&#039;
            params = {
                &#039;sender&#039;: &#039;1000596446&#039;,
                &#039;receptor&#039;: phone_number,
                &#039;message&#039;: 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):
        &amp;quot&amp;quot&amp;quot
        Generate a one-use only link for resetting password and send it to the
        user.
        &amp;quot&amp;quot&amp;quot
        phone_number = self.cleaned_data[&amp;quotphone_number&amp;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 = &#039;https&#039; if use_https else &#039;http&#039;
        uid = urlsafe_base64_encode(force_bytes(user.pk))
        token = token_generator.make_token(user)
        reset_link = protocol + &#039;://&#039; + domain + reverse(&#039;password_reset_confirm&#039;,
                                                         args=[uid, token])
        print(reset_link)
        self.send_sms(user_phone_number, reset_link)توی این مثال ما اومدیم برای ارسال پیامک از سرویس کاوه نگار استفاده کردیم در ضمن برای استفاده از کد باید APIKEY که از کاوه نگار میگیرین رو به صورت یه متغییر توی فایل settings.py اضافه کنین به این شکل KAVENEGAR_APIKEY = &#039;YOUR_APIKEY&#039; الان وقتشه بریم سراغ نوشتن 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(&#039;password_reset_done&#039;)
    template_name = &#039;registration/password_reset_form.html&#039;
    token_generator = default_token_generator
    title = _(&#039;Password reset&#039;)

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

    def form_valid(self, form):
        phone_number = form.cleaned_data[&#039;phone_number&#039;]
        try:
            user = UserModel.objects.get(phone_number=phone_number)
            opts = {
                &#039;use_https&#039;: self.request.is_secure(),
                &#039;token_generator&#039;: self.token_generator,
                &#039;request&#039;: self.request,
            }
            form.save(**opts)
        except UserModel.DoesNotExist:
            form.add_error(None, &#039;این شماره موبایل پیدا نشد!&#039;)
            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(&#039;password_reset/&#039;, PasswordResetView.as_view(), name=&#039;password_reset&#039;),
    path(&#039;password_reset/done/&#039;, views.PasswordResetDoneView.as_view(), name=&#039;password_reset_done&#039;),
    path(&#039;reset/&lt;uidb64&gt;/&lt;token&gt;/&#039;, views.PasswordResetConfirmView.as_view(), name=&#039;password_reset_confirm&#039;),
    path(&#039;reset/done/&#039;, views.PasswordResetCompleteView.as_view(), name=&#039;password_reset_complete&#039;),
]ما توی این آموزش اومدیم فقط یه ویوو رو تغییر دادیم برای بقیه از همون مدل پیش فرض جنگو استفاده کردیم.و در آخر اینکه فراموش نکنین این فایل urls رو توی urls اصلی پروژتون اضافه کنید.ممنون از توجهتون.</description>
                <category>Reza Heydari</category>
                <author>Reza Heydari</author>
                <pubDate>Thu, 18 Jun 2020 14:55:31 +0430</pubDate>
            </item>
            </channel>
</rss>