<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"><channel><title>نوشته های Reza Heydari</title><link>https://virgool.ir/feed/@reza.heydari</link><description></description><language>fa</language><pubDate>2026-11-12 10:50:16</pubDate><image><url>https://virgool.ir/images/default-avatar.jpg</url><title>Reza Heydari</title><link>https://virgool.ir/@reza.heydari</link></image><item><title>جنگو - Test Runner</title><link>https://virgool.ir/@reza.heydari/جنگو-test-runner-lewh3tf97w8o</link><description>توی این مطلب میخواییم یه نگاهی کوتاه به Test Runner در جنگو بندازیم.تست رانر ( Test Runner ) یه قسمت از تست فریمورک هست که تستایی که نوشتین پیدا میکنه و اجراشون میکنه. شما می تونین قسمتای مختلف این تست رانر رو شخصی سازی کنید. تستا تو جنگو از یه کلاس Test Runner یه اسم ‍‍DiscoverRunner استفاده میکنه. این کلاس میاد تستای شمارو پیدا میکنه دیتابیس تستون رو میسازه. در کل میاد تستارو پیدا میکنه تنطیمات انجام میده بعدم اجراشون میکنه. برای اینکه بتونین این کلاس رو توسعه بدین یا شخصی سازی کنین باید یه کلاس که از این کلاس ارث میبره رو بنویسین و توی فایل settings.py پروژتون بیایین متغیر TEST_RUNNER رو برابر این کلاستون قرار بدین. برای مثال برای اینکه اطمینان پیدا کنیم که همه هشدار هامون رو نمایش بدیم بدون اینکه نیاز داشته باشه -W رو بزارین هر دفعه که تستاتون رو اجرا میکنین. میتونین از کد زیر استفاده کنیم. # example/tests/runner.py&#xA;import warnings&#xA;from django.test.runner import DiscoverRunner&#xA;&#xA;class ExampleTestRunner(DiscoverRunner):&#xA;    def run_tests(self, *args, **kwargs):&#xA;        # Show all warnings once, especially to show DeprecationWarning&#xA;        # messages which Python ignores by default&#xA;        warnings.simplefilter(&#34;default&#34;)&#xA;        return super().run_tests(*args, **kwargs)توی این کد ما اومدیم متد run_tests رو بازنویسی کردیم. بعدش میاییم توی فایل settings متغیر TEST_RUNNER مینویسیم به این شکل: TEST_RUNNER = &#34;example.tests.runner.ExampleTestRunner&#34;شما میتونین با این روش پروسه تست هاتون توی جنگو رو توسعه بدین ...برای اطلاعات بیشتر میتونین این لینک در مورد تست رانر توی داکیومنت خود جنگو بخونین.. امیدوارم مفید بوده باشه. منابعSpeed Up Your Django Tests - Adam Johnson Advanced testing topics </description><category>Reza Heydari</category><author>Reza Heydari</author><pubDate>Thu, 09 Jul 2020 02:38:32 +0430</pubDate></item><item><title>ارسال لینک بازیابی رمز عبور با پیامک در جنگو</title><link>https://virgool.ir/cheyab-blog/ارسال-لینک-بازیابی-رمز-عبور-با-پیامک-در-جنگو-adp6ovcsapnu</link><description>سلام این اولین مطلبی هست که توی ویرگول منتشر میکنم . ممنون میشم برای بهتر شدن مطالب بعدی نظراتتو بگین ! اولین کاری که باید بعد اینکه یه پروژه جنگو ساختین اینه که یه اپ با دستور زیر بسازیpython manage.py startapp usersو اون رو توی فایل setting.py اضافه میکنیم در مرحله بعد باید فیلد شماره تلفن رو به مدل من توی این مثال از کلاس AbstractBaseUser استفاده کردم. در مرحله اول میاییم یه فایل manager.py رو توی اپ users میسازیم. و این کد رو بهش اضافه میکنیم. from django.contrib.auth.base_user import BaseUserManager&#xA;&#xA;class CustomUserManager(BaseUserManager):&#xA;    use_in_migrations = True&#xA;&#xA;    def _create_user(self, phone_number, password, **extra_fields):&#xA;        &#34;&#34;&#34;&#xA;        Create and save a user with the given phone number and password.&#xA;        &#34;&#34;&#34;&#xA;        if not phone_number:&#xA;            raise ValueError(&#39;The given phone number must be set&#39;)&#xA;        user = self.model(phone_number=phone_number, **extra_fields)&#xA;        user.set_password(password)&#xA;        user.save(using=self._db)&#xA;        return user&#xA;&#xA;    def create_user(self, phone_number, password=None, **extra_fields):&#xA;        extra_fields.setdefault(&#39;is_staff&#39;, False)&#xA;        extra_fields.setdefault(&#39;is_superuser&#39;, False)&#xA;        return self._create_user(phone_number, password, **extra_fields)&#xA;&#xA;    def create_superuser(self, phone_number, password=None, **extra_fields):&#xA;        extra_fields.setdefault(&#39;is_staff&#39;, True)&#xA;        extra_fields.setdefault(&#39;is_superuser&#39;, True)&#xA;&#xA;        if extra_fields.get(&#39;is_staff&#39;) is not True:&#xA;            raise ValueError(&#39;Superuser must have is_staff=True.&#39;)&#xA;        if extra_fields.get(&#39;is_superuser&#39;) is not True:&#xA;            raise ValueError(&#39;Superuser must have is_superuser=True.&#39;)&#xA;&#xA;        return self._create_user(phone_number, password, **extra_fields)حالا میاییم توی فایل models.py مدل User خودمون رو تعریف می کنیم. برای اینکار فایل مورد نظر رو به این شکل تغییر میدیم.from django.db import models&#xA;from django.contrib.auth.models import PermissionsMixin&#xA;from django.contrib.auth.base_user import AbstractBaseUser&#xA;from django.utils.translation import gettext_lazy as _&#xA;from django.core.validators import RegexValidator&#xA;from django.utils import timezone&#xA;&#xA;from .manager import CustomUserManager&#xA;&#xA;&#xA;class CustomUser(AbstractBaseUser, PermissionsMixin):&#xA;    phone_number = models.CharField(&#xA;        _(&#39;شماره موبایل&#39;),&#xA;        max_length=11,&#xA;        unique=True,&#xA;        validators=[RegexValidator(regex=r&#39;09(\d{9})$&#39;)])&#xA;    phone_number_verified = models.BooleanField(default=False)&#xA;    is_staff = models.BooleanField(&#xA;        _(&#39;staff status&#39;),&#xA;        default=False,&#xA;    )&#xA;    is_active = models.BooleanField(&#xA;        _(&#39;active&#39;),&#xA;        default=True,&#xA;    )&#xA;    date_joined = models.DateTimeField(_(&#39;date joined&#39;), default=timezone.now)&#xA;&#xA;    objects = CustomUserManager()&#xA;    USERNAME_FIELD = &#39;phone_number&#39;&#xA;&#xA;    class Meta:&#xA;        verbose_name = _(&#39;user&#39;)&#xA;        verbose_name_plural = _(&#39;users&#39;)جنگو برای بازیابی رمز عبور راهکاری اندیشیده که با ایمیل کار میکنه شما ایمیل رو وارد میکنین لینک به ایمیل شما فرستاده میشه و روی لینک که کلیک کنید میتونین رمز جدید رو بزارین ما میخواییم این کار رو با شماره موبایل انجام بدیم پس فقط لازمه قسمت اول رو بازنویسی کنیم  اولین کاری که انجام میدیم اینه  که فرم خودمون روی توی فایل forms.py اضافه کنیم. این کد رو به این فایل اضافه میکنیم. from django import forms&#xA;from django.contrib.auth import get_user_model&#xA;from django.core.validators import RegexValidator&#xA;from django.contrib.auth.tokens import default_token_generator&#xA;from django.utils.encoding import force_bytes&#xA;from django.utils.http import urlsafe_base64_encode&#xA;from django.contrib.sites.shortcuts import get_current_site&#xA;from django.urls import reverse&#xA;from django.conf import settings&#xA;&#xA;import kavenegar&#xA;&#xA;UserModel = get_user_model()&#xA;&#xA;class PasswordResetForm(forms.Form):&#xA;    phone_number = forms.CharField(label=&#39;شماره موبایل&#39;, max_length=11,&#xA;                                   validators=[RegexValidator(regex=r&#39;09(\d{9})$&#39;)])&#xA;&#xA;    def send_sms(self, phone_number, reset_link):&#xA;        try:&#xA;            api = kavenegar.KavenegarAPI(settings.KAVENEGAR_APIKEY)&#xA;            message = f&#39;برای بازیابی رمز عبور روی لینک زیر کلیک کنید \n {reset_link}&#39;&#xA;            params = {&#xA;                &#39;sender&#39;: &#39;1000596446&#39;,&#xA;                &#39;receptor&#39;: phone_number,&#xA;                &#39;message&#39;: message,&#xA;            }&#xA;            response = api.sms_send(params)&#xA;            print(response)&#xA;        except kavenegar.APIException as e:&#xA;            print(e)&#xA;        except kavenegar.HTTPException as e:&#xA;            print(e)&#xA;&#xA;    def get_users(self, phone_number):&#xA;        return UserModel.objects.get(phone_number=phone_number)&#xA;&#xA;    def save(self, domain_override=None,&#xA;             use_https=False, token_generator=default_token_generator,&#xA;             request=None):&#xA;        &#34;&#34;&#34;&#xA;        Generate a one-use only link for resetting password and send it to the&#xA;        user.&#xA;        &#34;&#34;&#34;&#xA;        phone_number = self.cleaned_data[&#34;phone_number&#34;]&#xA;        if not domain_override:&#xA;            current_site = get_current_site(request)&#xA;            site_name = current_site.name&#xA;            domain = current_site.domain&#xA;        else:&#xA;            site_name = domain = domain_override&#xA;        user = self.get_users(phone_number)&#xA;        user_phone_number = user.phone_number&#xA;        protocol = &#39;https&#39; if use_https else &#39;http&#39;&#xA;        uid = urlsafe_base64_encode(force_bytes(user.pk))&#xA;        token = token_generator.make_token(user)&#xA;        reset_link = protocol + &#39;://&#39; + domain + reverse(&#39;password_reset_confirm&#39;,&#xA;                                                         args=[uid, token])&#xA;        print(reset_link)&#xA;        self.send_sms(user_phone_number, reset_link)توی این مثال ما اومدیم برای ارسال پیامک از سرویس کاوه نگار استفاده کردیم در ضمن برای استفاده از کد باید APIKEY که از کاوه نگار میگیرین رو به صورت یه متغییر توی فایل settings.py اضافه کنین به این شکل KAVENEGAR_APIKEY = &#39;YOUR_APIKEY&#39; الان وقتشه بریم سراغ نوشتن view برای این کار توی فایل view.py این کد رو اضافه میکنیم from django.contrib.auth.tokens import default_token_generator&#xA;from django.contrib.auth import get_user_model&#xA;from django.contrib.auth.views import PasswordContextMixin&#xA;&#xA;from django.views.generic import FormView&#xA;from django.views.decorators.csrf import csrf_protect&#xA;&#xA;from django.utils.decorators import method_decorator&#xA;from django.utils.translation import gettext_lazy as _&#xA;&#xA;from django.urls import reverse_lazy&#xA;&#xA;from .forms import PasswordResetForm&#xA;&#xA;UserModel = get_user_model()&#xA;&#xA;class PasswordResetView(PasswordContextMixin, FormView):&#xA;    form_class = PasswordResetForm&#xA;    success_url = reverse_lazy(&#39;password_reset_done&#39;)&#xA;    template_name = &#39;registration/password_reset_form.html&#39;&#xA;    token_generator = default_token_generator&#xA;    title = _(&#39;Password reset&#39;)&#xA;&#xA;    @method_decorator(csrf_protect)&#xA;    def dispatch(self, *args, **kwargs):&#xA;        return super().dispatch(*args, **kwargs)&#xA;&#xA;    def form_valid(self, form):&#xA;        phone_number = form.cleaned_data[&#39;phone_number&#39;]&#xA;        try:&#xA;            user = UserModel.objects.get(phone_number=phone_number)&#xA;            opts = {&#xA;                &#39;use_https&#39;: self.request.is_secure(),&#xA;                &#39;token_generator&#39;: self.token_generator,&#xA;                &#39;request&#39;: self.request,&#xA;            }&#xA;            form.save(**opts)&#xA;        except UserModel.DoesNotExist:&#xA;            form.add_error(None, &#39;این شماره موبایل پیدا نشد!&#39;)&#xA;            return self.form_invalid(form)&#xA;        return super().form_valid(form) و در آخر میاییم فایل توی اپ یوزرمون فایل urls.py رو میسازیم و url هایی که نیاز داریم رو توش تعریف می کنیم! from django.urls import path&#xA;from django.contrib.auth import views&#xA;from .views import PasswordResetView&#xA;&#xA;urlpatterns = [&#xA;    path(&#39;password_reset/&#39;, PasswordResetView.as_view(), name=&#39;password_reset&#39;),&#xA;    path(&#39;password_reset/done/&#39;, views.PasswordResetDoneView.as_view(), name=&#39;password_reset_done&#39;),&#xA;    path(&#39;reset/&lt;uidb64&gt;/&lt;token&gt;/&#39;, views.PasswordResetConfirmView.as_view(), name=&#39;password_reset_confirm&#39;),&#xA;    path(&#39;reset/done/&#39;, views.PasswordResetCompleteView.as_view(), name=&#39;password_reset_complete&#39;),&#xA;]ما توی این آموزش اومدیم فقط یه ویوو رو تغییر دادیم برای بقیه از همون مدل پیش فرض جنگو استفاده کردیم.و در آخر اینکه فراموش نکنین این فایل urls رو توی urls اصلی پروژتون اضافه کنید.ممنون از توجهتون.</description><category>Reza Heydari</category><author>Reza Heydari</author><pubDate>Thu, 18 Jun 2020 15:55:31 +0430</pubDate></item></channel></rss>