چرا جنگو رو یاد گرفتی؟
Final Results
11%
باهاش کارمند بشم
19%
پروژه های فریلنسری باهاش انجام بدم
28%
هم فریلنسری هم کارمندی
15%
از سر بیکاری
28%
یه اشتباهی بود کردیم دیگه
19%
موارد دیگه
😁19👎1
امنیت پایدارتر با یک چرخش ساده! 😎
✅ اگه با JWT کار کرده باشی، میدونی که ما یک access token و یک refresh token داریم
✅ اکسس توکن ما که خب عمرش کوتاهه مثلا بعد 10 دقیقه باطل میشه و از طریق رفرش توکن که عمرش بلندتره(مثلا 7 روز) باید یک اکسس توکن و رفرش توکن جدید از سرور درخواست کنیم
🤨 حالا یک مسعله ای هست این وسط ؟!
رفرش توکن شما نباید اینطوری باشه که توی اون 7 روز هربار که ازش استفاده کردی فرت و فرت بهت اکسس توکن بده.
😈 اینطوری اگه هکر عزیز بنا به هر علتی به اون رفرش توکن دسترسی پیدا کنه توی اون 7 روز هزاربار میتونه token بگیره و عشق و حال کنه
☝🏻اینجا دوتا مفهوم داریم به اسم rotate refresh token
و revoke refresh token که خیلی شبیه هم هستن(با فرق کوچولو)
✅ Rotate Token
یعنی هر بار که کاربر از Refresh Token استفاده کرد، یه Access Token جدید و یه Refresh Token جدید صادر میکنیم.
توی این حالت، Refresh Token قبلی دیگه نباید قابل استفاده باشه
اینجوریه که میگه: تو بیا رفرش توکن رو توی یک جایی مثلا ردیس یا هرچی، ذخیره کن و وقتی کاربر از اون رفرش توکن استفاده کرد قبلی رو حذف کن و جدیده رو بزار جاش تا یکبار بیشتر نتونه استفاده کنه
✅ Revoke Token
یعنی بیاعتبار کردن یک توکن قبل از اینکه تاریخ انقضاش برسه(با expire طبیعی توکن اشتباه نگیری). مثلا وقتی کاربر logout میکنه یا Refresh Token جدید گرفته، Refresh Token قبلی رو revoke میکنیم.
✅ در واقع میشه یه جورایی گفت :
اRotate یعنی "توکن جدید بده و قبلی رو کنار بذار"
اRevoke یعنی "توکن فعلی رو از کار بنداز"
این لینک زیر هم خیلی مفصل تر توضیح داده
https://auth0.com/docs/secure/tokens/refresh-tokens/refresh-token-rotation
از تلگرام @LearnByLearn
✅ اگه با JWT کار کرده باشی، میدونی که ما یک access token و یک refresh token داریم
✅ اکسس توکن ما که خب عمرش کوتاهه مثلا بعد 10 دقیقه باطل میشه و از طریق رفرش توکن که عمرش بلندتره(مثلا 7 روز) باید یک اکسس توکن و رفرش توکن جدید از سرور درخواست کنیم
🤨 حالا یک مسعله ای هست این وسط ؟!
رفرش توکن شما نباید اینطوری باشه که توی اون 7 روز هربار که ازش استفاده کردی فرت و فرت بهت اکسس توکن بده.
😈 اینطوری اگه هکر عزیز بنا به هر علتی به اون رفرش توکن دسترسی پیدا کنه توی اون 7 روز هزاربار میتونه token بگیره و عشق و حال کنه
☝🏻اینجا دوتا مفهوم داریم به اسم rotate refresh token
و revoke refresh token که خیلی شبیه هم هستن(با فرق کوچولو)
✅ Rotate Token
یعنی هر بار که کاربر از Refresh Token استفاده کرد، یه Access Token جدید و یه Refresh Token جدید صادر میکنیم.
توی این حالت، Refresh Token قبلی دیگه نباید قابل استفاده باشه
اینجوریه که میگه: تو بیا رفرش توکن رو توی یک جایی مثلا ردیس یا هرچی، ذخیره کن و وقتی کاربر از اون رفرش توکن استفاده کرد قبلی رو حذف کن و جدیده رو بزار جاش تا یکبار بیشتر نتونه استفاده کنه
✅ Revoke Token
یعنی بیاعتبار کردن یک توکن قبل از اینکه تاریخ انقضاش برسه(با expire طبیعی توکن اشتباه نگیری). مثلا وقتی کاربر logout میکنه یا Refresh Token جدید گرفته، Refresh Token قبلی رو revoke میکنیم.
✅ در واقع میشه یه جورایی گفت :
اRotate یعنی "توکن جدید بده و قبلی رو کنار بذار"
اRevoke یعنی "توکن فعلی رو از کار بنداز"
این لینک زیر هم خیلی مفصل تر توضیح داده
https://auth0.com/docs/secure/tokens/refresh-tokens/refresh-token-rotation
از تلگرام @LearnByLearn
✍18❤7👍6👏2🔥1
This media is not supported in your browser
VIEW IN TELEGRAM
وقتی یه نفر میگه: تو که کارت راحته، فقط نشستی پشت میز پای لپتاپ 😁😅
👍10😁4👎1
✅ هندل کردن Open Redirect Attack توی جنگو با RedirectURLMixin
این Open Redirect Attack چیه؟ کلمه این رو گذاشتم اولش راست چین بشه 😁
وقتی شما کاربر رو به URL بیرونی ریدایرکت میکنید بدون بررسی، یه attacker میتونه ازش سوء استفاده کنه:
https://yoursite.com/login/?next=http://hack.com
کاربر فکر میکنه داره به سایت شما میره، ولی بعد از login به سایت مهاجم هدایت میشه. این میتونه phishing یا سرقت اطلاعات session کاربر رو ممکن کنه. (من بلد نیستم چطوری میتونه، خودتون سرچ کنید)
میکسین ع RedirectURLMixin توی جنگو (django.contrib.auth.views) جلوی این حرکت رو می گیره. (یکی از کارهاش اینه)
چی کار میکنه؟
با میکسین ع RedirectURLMixin می تونیم بررسی کنیم که این URL جزو hostهای مجاز هست.
یه مثال ساده براش:
اون get_redirect_url یکی از متدهای این میکسین ع
حالا من اگه آدرس رو اینجوری بدم:
http://127.0.0.1:8000/profiles/aaa/?next=https://djangolearn.ir/
ریدارکت میشه به صفحه اصلی سایت خودتون نه سایت جنگولرن 😁
راستی از نسخه 4.1 به بعد این میکسین جایگزین SuccessURLAllowedHostsMixin شده:
The undocumented django.contrib.auth.views.SuccessURLAllowedHostsMixin mixin is replaced by RedirectURLMixin.
لایک نداشت این پست؟
این Open Redirect Attack چیه؟ کلمه این رو گذاشتم اولش راست چین بشه 😁
وقتی شما کاربر رو به URL بیرونی ریدایرکت میکنید بدون بررسی، یه attacker میتونه ازش سوء استفاده کنه:
https://yoursite.com/login/?next=http://hack.com
کاربر فکر میکنه داره به سایت شما میره، ولی بعد از login به سایت مهاجم هدایت میشه. این میتونه phishing یا سرقت اطلاعات session کاربر رو ممکن کنه. (من بلد نیستم چطوری میتونه، خودتون سرچ کنید)
میکسین ع RedirectURLMixin توی جنگو (django.contrib.auth.views) جلوی این حرکت رو می گیره. (یکی از کارهاش اینه)
چی کار میکنه؟
با میکسین ع RedirectURLMixin می تونیم بررسی کنیم که این URL جزو hostهای مجاز هست.
یه مثال ساده براش:
class AAA(RedirectURLMixin, View):
redirect_field_name = "next"
def get(self, request, *args, **kwargs):
url = self.get_redirect_url()
if url:
return redirect(url)
return redirect("/")
اون get_redirect_url یکی از متدهای این میکسین ع
حالا من اگه آدرس رو اینجوری بدم:
http://127.0.0.1:8000/profiles/aaa/?next=https://djangolearn.ir/
ریدارکت میشه به صفحه اصلی سایت خودتون نه سایت جنگولرن 😁
راستی از نسخه 4.1 به بعد این میکسین جایگزین SuccessURLAllowedHostsMixin شده:
The undocumented django.contrib.auth.views.SuccessURLAllowedHostsMixin mixin is replaced by RedirectURLMixin.
لایک نداشت این پست؟
❤32👍11😁1
سوال:
شما اسلایدر برای سایت تون چطوری می سازید؟
این پیشنهاد chatgpt بود:
اگه میخوای اسلایدرت خیلی انعطافپذیر باشه، میتونی از GenericForeignKey استفاده کنی که به هر مدل وصل بشه (محصول، مقاله، دستهبندی و …).
مزایا:
نهایت انعطافپذیری: میتونی هر چیزی رو توی اسلایدر بذاری.
آیندهنگر و تمیز.
معایب:
کار باهاش پیچیدهتره.
برای خیلی از پروژههای معمولی زیادی Over-Engineering محسوب میشه.
شما اسلایدر برای سایت تون چطوری می سازید؟
این پیشنهاد chatgpt بود:
اگه میخوای اسلایدرت خیلی انعطافپذیر باشه، میتونی از GenericForeignKey استفاده کنی که به هر مدل وصل بشه (محصول، مقاله، دستهبندی و …).
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
class Slider(models.Model):
title = models.CharField(max_length=255, blank=True)
image = models.ImageField(upload_to="sliders/")
url = models.URLField(blank=True, null=True)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE, null=True, blank=True)
object_id = models.PositiveIntegerField(null=True, blank=True)
content_object = GenericForeignKey('content_type', 'object_id')
order = models.PositiveIntegerField(default=0)
is_active = models.BooleanField(default=True)
مزایا:
نهایت انعطافپذیری: میتونی هر چیزی رو توی اسلایدر بذاری.
آیندهنگر و تمیز.
معایب:
کار باهاش پیچیدهتره.
برای خیلی از پروژههای معمولی زیادی Over-Engineering محسوب میشه.
❤10👍1🤔1
جنگولرن
سوال: شما اسلایدر برای سایت تون چطوری می سازید؟ این پیشنهاد chatgpt بود: اگه میخوای اسلایدرت خیلی انعطافپذیر باشه، میتونی از GenericForeignKey استفاده کنی که به هر مدل وصل بشه (محصول، مقاله، دستهبندی و …). from django.contrib.contenttypes.fields import…
پیرو پست قبلی، یکی پرسید اون ContentType چیه و کارش چیه؟
اگه دقت کرده باشید توی INSTALLED_APPS یه اپ هست به اسم django.contrib.contenttypes و به واسطه این وقتی migrate می کنید، یه جدول به اسم django_content_type ساخته میشه. که همه مدل های پروژه رو توش نگهداری می کنه.
حالا اگه این لینک رو ببینید:
https://docs.djangoproject.com/en/5.2/ref/contrib/contenttypes/#generic-relations
درباره جنریک ریلیشن توضیح داده یا GenericForeignKey که اشاره میکنه به content_type
مزیت ش چیه این جنریک ریلیشن؟
یک مثال از chatgpt برای comment :
فرض کن میخوای یه سیستم کامنت داشته باشی.
کاربر میتونه روی محصول کامنت بذاره.
یا روی پست بلاگ.
یا روی سفارش.
راه سنتی (بدون Generic):
یا باید برای هر مدل یه فیلد ForeignKey بسازی:
👉 مشکل: کلی فیلد خالی داری و هر بار باید کد اضافه بزنی.
یا باید برای هر مدل یه مدل کامنت جدا بسازی (CommentForProduct, CommentForBlog, ...).
👉 مشکل: کلی جدول و کد تکراری.
📌 راه حل با Generic Relation
به جای این همه دردسر، با GenericForeignKey یه بار تعریف میکنی:
حالا content_object میتونه هر چیزی باشه (Product، Blog، Order و ...).
✅ مزیتهای Generic Relation
سادگی و انعطافپذیری: فقط یه جدول داری که میتونه به همهچی وصل بشه.
کاهش کد تکراری: به جای نوشتن چند مدل/فیلد مختلف، یه بار تعریف میکنی و برای همه استفاده میشه.
افزودن مدلهای جدید بدون تغییر دیتابیس: مثلاً اگه فردا خواستی روی Category هم کامنت بذاری، لازم نیست مدل Comment رو تغییر بدی؛ همون GenericForeignKey جواب میده.
یکپارچگی دادهها:همه کامنتها/لایکها/اکتیویتیها توی یه جدول جمع میشه → مدیریت و جستجو راحتتر.
⚠️ معایبش
کمی پیچیدگی بیشتر در Queryها (چون باید از ContentType کمک بگیری).
enforce کردن روابط در سطح دیتابیس سختتره (چون DB نمیدونه object_id دقیقاً به کدوم جدول اشاره میکنه).
اگه دقت کرده باشید توی INSTALLED_APPS یه اپ هست به اسم django.contrib.contenttypes و به واسطه این وقتی migrate می کنید، یه جدول به اسم django_content_type ساخته میشه. که همه مدل های پروژه رو توش نگهداری می کنه.
حالا اگه این لینک رو ببینید:
https://docs.djangoproject.com/en/5.2/ref/contrib/contenttypes/#generic-relations
درباره جنریک ریلیشن توضیح داده یا GenericForeignKey که اشاره میکنه به content_type
مزیت ش چیه این جنریک ریلیشن؟
یک مثال از chatgpt برای comment :
فرض کن میخوای یه سیستم کامنت داشته باشی.
کاربر میتونه روی محصول کامنت بذاره.
یا روی پست بلاگ.
یا روی سفارش.
راه سنتی (بدون Generic):
یا باید برای هر مدل یه فیلد ForeignKey بسازی:
class Comment(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
product = models.ForeignKey(Product, null=True, blank=True, on_delete=models.CASCADE)
blog = models.ForeignKey(Blog, null=True, blank=True, on_delete=models.CASCADE)
order = models.ForeignKey(Order, null=True, blank=True, on_delete=models.CASCADE)
👉 مشکل: کلی فیلد خالی داری و هر بار باید کد اضافه بزنی.
یا باید برای هر مدل یه مدل کامنت جدا بسازی (CommentForProduct, CommentForBlog, ...).
👉 مشکل: کلی جدول و کد تکراری.
📌 راه حل با Generic Relation
به جای این همه دردسر، با GenericForeignKey یه بار تعریف میکنی:
class Comment(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
text = models.TextField()
حالا content_object میتونه هر چیزی باشه (Product، Blog، Order و ...).
✅ مزیتهای Generic Relation
سادگی و انعطافپذیری: فقط یه جدول داری که میتونه به همهچی وصل بشه.
کاهش کد تکراری: به جای نوشتن چند مدل/فیلد مختلف، یه بار تعریف میکنی و برای همه استفاده میشه.
افزودن مدلهای جدید بدون تغییر دیتابیس: مثلاً اگه فردا خواستی روی Category هم کامنت بذاری، لازم نیست مدل Comment رو تغییر بدی؛ همون GenericForeignKey جواب میده.
یکپارچگی دادهها:همه کامنتها/لایکها/اکتیویتیها توی یه جدول جمع میشه → مدیریت و جستجو راحتتر.
⚠️ معایبش
کمی پیچیدگی بیشتر در Queryها (چون باید از ContentType کمک بگیری).
enforce کردن روابط در سطح دیتابیس سختتره (چون DB نمیدونه object_id دقیقاً به کدوم جدول اشاره میکنه).
❤8👍6
می دونستید ممکنه unique_together در آینده توی جنگو منسوخ بشه؟
البته از جنگو 2.2 به بعد داره میگه در آینده ممکنه منسوخ بشه 😁
لینک:
https://docs.djangoproject.com/en/5.2/ref/models/options/#django.db.models.Options.unique_together
خود داکیومنت جنگو گفته بهتره از UniqueConstraint استفاده کنید:
لینک:
https://docs.djangoproject.com/en/5.2/ref/models/constraints/#django.db.models.UniqueConstraint
یه مثال:
فرض کن میخواهیم ترکیب محصول و رنگ فقط یکی باشه، قبلا اینجوری می نوشتیم:
توی UniqueConstraint اینجوریه:
تازه میتونیم بگیم در شرایطی خاص این حالت فعال باشه.
خودتون زحمت بکشید condition رو توی لینکی که دادم سرچ کنید.
قابلیت های دیگه ای هم داره، که بازم خودتون...
و من الله التوفیق
البته از جنگو 2.2 به بعد داره میگه در آینده ممکنه منسوخ بشه 😁
لینک:
https://docs.djangoproject.com/en/5.2/ref/models/options/#django.db.models.Options.unique_together
خود داکیومنت جنگو گفته بهتره از UniqueConstraint استفاده کنید:
لینک:
https://docs.djangoproject.com/en/5.2/ref/models/constraints/#django.db.models.UniqueConstraint
یه مثال:
فرض کن میخواهیم ترکیب محصول و رنگ فقط یکی باشه، قبلا اینجوری می نوشتیم:
class Meta:
unique_together = ('product', 'color')
توی UniqueConstraint اینجوریه:
class Meta:
constraints = [
models.UniqueConstraint(fields=['product', 'color'], name='unique_product_option')
]
تازه میتونیم بگیم در شرایطی خاص این حالت فعال باشه.
خودتون زحمت بکشید condition رو توی لینکی که دادم سرچ کنید.
قابلیت های دیگه ای هم داره، که بازم خودتون...
و من الله التوفیق
Django Project
Model Meta options | Django documentation
The web framework for perfectionists with deadlines.
❤11✍5👍3
اصل انیشتین: چرا حفظ کردن، مهارت نیست؟
روایت معروفی وجود دارد که از آلبرت انیشتین سرعت نور را پرسیدند و او در پاسخ گفت: «نمیدانم. چرا باید چیزی را حفظ کنم که میتوانم در عرض چند ثانیه در کتاب پیدا کنم؟»
این جمله، امروز بیش از هر زمان دیگری مصداق دارد. در دنیایی که پاسخ هر سوال فنی، از سینتکس یک تابع گمنام در جاوااسکریپت گرفته تا پیچیدهترین مفاهیم معماری نرمافزار، با یک جستجوی ساده در گوگل یا LLMها در دسترس است، چرا باید از یک برنامهنویس انتظار داشته باشیم که همهچیز را از حفظ باشد؟
یک توسعهدهنده خوب کسی نیست که تعریف دقیق حرف D در اصول SOLID (Dependency Inversion Principle) را طوطیوار تکرار کند. بلکه کسی است که میداند چنین اصولی وجود دارد، فلسفه پشت آن را درک کرده و مهمتر از همه، میداند در چه شرایطی و چگونه از آن برای حل یک مشکل واقعی در پروژه استفاده کند. او اگر جزئیات را فراموش کرده باشد، میداند کجا به دنبال آن بگردد. این همان مهارت واقعی است.
این رویکرد اغلب به دلایل زیر در مصاحبهها باب شده است:
سنجش آسان: پرسیدن سوالات تعریفی، راهی ساده برای «نمره دادن» و فیلتر کردن سریع کاندیداهاست. پاسخ یا درست است یا غلط و نیازی به تحلیل عمیق ندارد.
عدم آموزش مصاحبهکنندگان: بسیاری از مصاحبهکنندگان فنی، خودشان توسعهدهندگان ارشدی هستند که برای مصاحبه کردن آموزش ندیدهاند. آنها بهطور طبیعی سوالاتی را میپرسند که خودشان پاسخ قطعیاش را میدانند؛ یعنی تعاریف و الگوریتمهای مشخص.
رویکردی بهتر: چگونه استعداد واقعی را کشف کنیم؟
پیشنهاد میشود به جای آزمون حافظه، روی سنجش مهارتهای کلیدی و شبیهسازی محیط کار واقعی تمرکز کنیم:
۱. سوالات مبتنی بر «تجربه» بپرسید، نه «تعریف»
به جای اینکه بپرسید: «حرف D در SOLID چیست؟»
بپرسید: «میتوانی پروژهای را مثال بزنی که در آن از اصل Dependency Inversion استفاده کردی؟ چه مشکلی را برایت حل کرد و اگر استفاده نمیکردی چه اتفاقی میافتاد؟»
این سوال، درک عمیق و تجربه عملی فرد را نشان میدهد، نه توانایی حفظ کردن او را.
۲. مسائل واقعی و مشترک طراحی کنید
به جای دادن یک مسئله الگوریتمی پیچیده و درخواست حل آن روی وایتبورد بدون اینترنت، یک چالش کوچک و واقعی از پروژه فعلی شرکت را مطرح کنید.
بگویید: «بیا با هم این مشکل را حل کنیم. فرض کن این تسک به تو داده شده. میتوانی از اینترنت هم استفاده کنی و بلند بلند فکر کن تا من با روند تحلیلت آشنا شوم.»
این روش، توانایی جستجو، یادگیری، و مهمتر از همه، رویکرد او به حل مسئله را آشکار میکند که در کار روزمره هزاران بار ارزشمندتر از حفظ بودن یک الگوریتم است.
سخن پایانی: مغز را استخدام کنید، نه هارد دیسک را
هدف ما از استخدام، پیدا کردن یک مغز متفکر و حلکننده مسئله است، نه یک دایرةالمعارف متحرک.
✍🏻 sina khaghani
روایت معروفی وجود دارد که از آلبرت انیشتین سرعت نور را پرسیدند و او در پاسخ گفت: «نمیدانم. چرا باید چیزی را حفظ کنم که میتوانم در عرض چند ثانیه در کتاب پیدا کنم؟»
این جمله، امروز بیش از هر زمان دیگری مصداق دارد. در دنیایی که پاسخ هر سوال فنی، از سینتکس یک تابع گمنام در جاوااسکریپت گرفته تا پیچیدهترین مفاهیم معماری نرمافزار، با یک جستجوی ساده در گوگل یا LLMها در دسترس است، چرا باید از یک برنامهنویس انتظار داشته باشیم که همهچیز را از حفظ باشد؟
یک توسعهدهنده خوب کسی نیست که تعریف دقیق حرف D در اصول SOLID (Dependency Inversion Principle) را طوطیوار تکرار کند. بلکه کسی است که میداند چنین اصولی وجود دارد، فلسفه پشت آن را درک کرده و مهمتر از همه، میداند در چه شرایطی و چگونه از آن برای حل یک مشکل واقعی در پروژه استفاده کند. او اگر جزئیات را فراموش کرده باشد، میداند کجا به دنبال آن بگردد. این همان مهارت واقعی است.
این رویکرد اغلب به دلایل زیر در مصاحبهها باب شده است:
سنجش آسان: پرسیدن سوالات تعریفی، راهی ساده برای «نمره دادن» و فیلتر کردن سریع کاندیداهاست. پاسخ یا درست است یا غلط و نیازی به تحلیل عمیق ندارد.
عدم آموزش مصاحبهکنندگان: بسیاری از مصاحبهکنندگان فنی، خودشان توسعهدهندگان ارشدی هستند که برای مصاحبه کردن آموزش ندیدهاند. آنها بهطور طبیعی سوالاتی را میپرسند که خودشان پاسخ قطعیاش را میدانند؛ یعنی تعاریف و الگوریتمهای مشخص.
رویکردی بهتر: چگونه استعداد واقعی را کشف کنیم؟
پیشنهاد میشود به جای آزمون حافظه، روی سنجش مهارتهای کلیدی و شبیهسازی محیط کار واقعی تمرکز کنیم:
۱. سوالات مبتنی بر «تجربه» بپرسید، نه «تعریف»
به جای اینکه بپرسید: «حرف D در SOLID چیست؟»
بپرسید: «میتوانی پروژهای را مثال بزنی که در آن از اصل Dependency Inversion استفاده کردی؟ چه مشکلی را برایت حل کرد و اگر استفاده نمیکردی چه اتفاقی میافتاد؟»
این سوال، درک عمیق و تجربه عملی فرد را نشان میدهد، نه توانایی حفظ کردن او را.
۲. مسائل واقعی و مشترک طراحی کنید
به جای دادن یک مسئله الگوریتمی پیچیده و درخواست حل آن روی وایتبورد بدون اینترنت، یک چالش کوچک و واقعی از پروژه فعلی شرکت را مطرح کنید.
بگویید: «بیا با هم این مشکل را حل کنیم. فرض کن این تسک به تو داده شده. میتوانی از اینترنت هم استفاده کنی و بلند بلند فکر کن تا من با روند تحلیلت آشنا شوم.»
این روش، توانایی جستجو، یادگیری، و مهمتر از همه، رویکرد او به حل مسئله را آشکار میکند که در کار روزمره هزاران بار ارزشمندتر از حفظ بودن یک الگوریتم است.
سخن پایانی: مغز را استخدام کنید، نه هارد دیسک را
هدف ما از استخدام، پیدا کردن یک مغز متفکر و حلکننده مسئله است، نه یک دایرةالمعارف متحرک.
✍🏻 sina khaghani
👍34👏9❤4👎1
وات ایز F() expressions در جنگو 😁
جنگو در مورد تابع F توی داکیومنت میگه:
An F() object represents the value of a model field, transformed value of a model field, or annotated column. It makes it possible to refer to model field values and perform database operations using them without actually having to pull them out of the database into Python memory.
Django uses the F() object to generate an SQL expression that describes the required operation at the database level.
آخرش چی گفته؟ database level
این تابع برای مواقعی به درد میخوره که ممکنه همزمانی یا Concurrency پیش بیاد.
مثلا یه جایی میخواییم از انبار یه محصول کم کنیم، همزمان یه ریکوئست دیگه میاد که اونم میخواد کم کنه.
حالت عادی و بدون استفاده از F ، چون آبجکت توی مموری اومده و مثلا مقدار انبار 10 هست، هر دو از آبجکت توی مموری کم میکنن،
لذا انبار 9 میشه 😳
ولی با F مستقیم آپدیت روی رکورد زده میشه.
پیچوندمش؟ 😅 یه مثال:
فرض کن یه مدل داریم:
حالا بخوایم یه محصول رو یه دونه کم کنیم:
مشکل:
اگر دو درخواست همزمان این کار رو بکنن، ممکنه هر دو یک مقدار قدیمی بخونن (مثلاً stock=10) و بعد از save، نتیجه بشه stock=9، در حالی که باید 8 میشد!
این همون مشکل همزمانی (Concurrency ) هست.
با F اینجوری میشه:
اینجا F('stock') به دیتابیس میگه:
«به جای اینکه مقدار stock رو بیارم تو پایتون و دوباره بنویسم، مستقیماً در سطح دیتابیس مقدار فیلد رو یکی کم کن.»
این کار باعث میشه اتمیک (atomic) باشه و نیازی به lock دستی یا نگرانی از race condition نباشه.
راستی این lock باعث Deadlock نمیشه.
چون Deadlock وقتی پیش میاد که دو یا چند تراکنش همزمان قفل منابع مختلف رو بگیرن و هرکدوم منتظر آزاد شدن قفل اونوری بمونن.
جنگو در مورد تابع F توی داکیومنت میگه:
An F() object represents the value of a model field, transformed value of a model field, or annotated column. It makes it possible to refer to model field values and perform database operations using them without actually having to pull them out of the database into Python memory.
Django uses the F() object to generate an SQL expression that describes the required operation at the database level.
آخرش چی گفته؟ database level
این تابع برای مواقعی به درد میخوره که ممکنه همزمانی یا Concurrency پیش بیاد.
مثلا یه جایی میخواییم از انبار یه محصول کم کنیم، همزمان یه ریکوئست دیگه میاد که اونم میخواد کم کنه.
حالت عادی و بدون استفاده از F ، چون آبجکت توی مموری اومده و مثلا مقدار انبار 10 هست، هر دو از آبجکت توی مموری کم میکنن،
لذا انبار 9 میشه 😳
ولی با F مستقیم آپدیت روی رکورد زده میشه.
پیچوندمش؟ 😅 یه مثال:
فرض کن یه مدل داریم:
class Product(models.Model):
name = models.CharField(max_length=100)
stock = models.IntegerField(default=0)
حالا بخوایم یه محصول رو یه دونه کم کنیم:
product = Product.objects.get(id=1)
product.stock = product.stock - 1
product.save()
مشکل:
اگر دو درخواست همزمان این کار رو بکنن، ممکنه هر دو یک مقدار قدیمی بخونن (مثلاً stock=10) و بعد از save، نتیجه بشه stock=9، در حالی که باید 8 میشد!
این همون مشکل همزمانی (Concurrency ) هست.
با F اینجوری میشه:
from django.db.models import F
Product.objects.filter(id=1).update(stock=F('stock') - 1)
اینجا F('stock') به دیتابیس میگه:
«به جای اینکه مقدار stock رو بیارم تو پایتون و دوباره بنویسم، مستقیماً در سطح دیتابیس مقدار فیلد رو یکی کم کن.»
این کار باعث میشه اتمیک (atomic) باشه و نیازی به lock دستی یا نگرانی از race condition نباشه.
راستی این lock باعث Deadlock نمیشه.
چون Deadlock وقتی پیش میاد که دو یا چند تراکنش همزمان قفل منابع مختلف رو بگیرن و هرکدوم منتظر آزاد شدن قفل اونوری بمونن.
👍15❤8🆒4✍1
Forwarded from نمای پشت صحنه
توی سیستم های توزیع شده همونطور که میدونید ما یه چیزی داریم به اسم load balancer که میاد جلوی سرورا قرار میگیره و request هایی که میان رو بین سرورا پخش میکنه. حالا چجوری و با چه منطقی پخش میکنه؟
اینا مرسوم ترین روش ها هستن حالا بسته به وضعیت میشه هر کدوم یا ترکیبی ازشون رو انتخاب کرد:
1️⃣ Round Robin
درخواستها یکی یکی و به ترتیب بین سرورها تقسیم میشن. ساده و رایج هست، ولی توان سرورها رو در نظر نمیگیره.
2️⃣ Weighted Round Robin
همون Round Robin ولی سرورهای قویتر درخواست های بیشتری میگیرن. اینطوری فشار متعادل تر پخش میشه.
3️⃣ Least Connections
هر درخواست جدید به سروری میره که کمترین Connection فعال رو داره. برای کارهایی که زمان پردازش متغیر دارن خیلی خوبه.
4️⃣ IP Hash
این روش میاد IP کاربر رو هش میکنه و توی رنج تعداد سرور ها میزاره مثلا۱۰ تا سرور داریم میشه ۱ تا ۱۰ و request های یک IP همیشه به یه سرور میرن . این روش برای Session ها یا وب اپلیکیشن هایی که state دارن مفیده.
5️⃣ Least Response Time
درخواستها به سمتی میرن که هم تعداد Connection کمتر باشه و هم response time سریع تر. مناسب برای سرویسهای حساس به Performance.
اینا مرسوم ترین روش ها هستن حالا بسته به وضعیت میشه هر کدوم یا ترکیبی ازشون رو انتخاب کرد:
1️⃣ Round Robin
درخواستها یکی یکی و به ترتیب بین سرورها تقسیم میشن. ساده و رایج هست، ولی توان سرورها رو در نظر نمیگیره.
2️⃣ Weighted Round Robin
همون Round Robin ولی سرورهای قویتر درخواست های بیشتری میگیرن. اینطوری فشار متعادل تر پخش میشه.
3️⃣ Least Connections
هر درخواست جدید به سروری میره که کمترین Connection فعال رو داره. برای کارهایی که زمان پردازش متغیر دارن خیلی خوبه.
4️⃣ IP Hash
این روش میاد IP کاربر رو هش میکنه و توی رنج تعداد سرور ها میزاره مثلا۱۰ تا سرور داریم میشه ۱ تا ۱۰ و request های یک IP همیشه به یه سرور میرن . این روش برای Session ها یا وب اپلیکیشن هایی که state دارن مفیده.
5️⃣ Least Response Time
درخواستها به سمتی میرن که هم تعداد Connection کمتر باشه و هم response time سریع تر. مناسب برای سرویسهای حساس به Performance.
👍13❤7
درمورد Descriptor چی می دونیم؟
چطوری میتوان رفتارهای ویژگیهای مرتبط به یک کلاس را مدیریت کرد؟ چطوری میتوانیم کاری کنیم که ویژگیهای متفاوت کلاسهای مختلف به شکلی یکسان مدیریت شوند؟
ما در حالت ساده هیچ کنترلی روی ویژگی (Attribute) هایی که یک کلاس دارد نداریم.
وقتی شما کلاسی دارید که یک ویژگی به نام x دارد، هنگام کار با نمونههای ساختهشده از این کلاس میتوان هر مقداری را به این ویژگی نسبت داد.
مثلاً فرضکنید که ما یک کلاس به نام Person داریم که مقدار سن شخص در آن نگهداری میشود:
حالا ما موقع ساخت یک نمونه از این کلاس میتوانیم «هرچیزی» را به آن نسبت بدهیم:
در حالت ساده ما هیچ کنترلی روی ویژگیها نداریم. پس تمام نمونههای بالا از نظر زبان پایتون درست هستند. امّا این مقادیر منطق برنامهی ما را خراب میکنند.
شما میتوانید برای اعتبارسنجی (Validation) مقادیر کدهای اضافیای را درون init قرار بدهید. امّا آن کدها دیگر تغییرات مقادیر را پس از ساخت شئ کنترل نمیکنند.
حتّی میتوانید متدهایی برای اعتبارسنجی درون کلاستان بگذارید. امّا این کار تنها استفاده از کدتان را برای دیگران سختتر میکند و همواره این احتمال وجود دارد که برنامهنویس فراموش کند که پس از هرتغییری در هر جای کد، آن متدها را فراخوانی کند.
از این مورد بگذریم.
فرضکنید که شما میخواهید یک ویژگی درون کلاس A همیشه عدد مثبت باشد. حالا در جای دیگر برنامه نیازدارید که چند ویژگی کلاس B هم درست همین خاصیّت را داشته باشند.
کلاسهای A و B هم هیچ ربط منطقیای ندارند و نمیتوان به مواردی مثل ارثبری حتّی فکر کرد.
عالی نبود اگر میشد کاری کرد که ویژگیهای کلاس های مختلف، بدون اینکه به هم ربطی پیدا کنند، به یک شکل مدیریت شوند؟
خب Descriptor پروتکلی است که همهی این کارها را برای ما میکند.
پروتکل Descriptor خیلی ساده است. هر کلاسی که حداقل یکی از متدهای: set، get یا delete را پیادهسازی کند یک Descriptor حساب میشود.
کاربردها و مثال های Descriptor رو خودتون بخونید.
از سایت علی حسینی کپی کردم. این لینک
میخوام یه قابلیت ساده که توی جنگو هست رو توضیح بدم.
اما قبلش اگه بدونیم Descriptor چیه، یادگرفتنش باحال تر میشه.
پس اگه عمری بود، بقیه در پست های بعدی...
اسپانسر این قسمت 👈 لینک
چطوری میتوان رفتارهای ویژگیهای مرتبط به یک کلاس را مدیریت کرد؟ چطوری میتوانیم کاری کنیم که ویژگیهای متفاوت کلاسهای مختلف به شکلی یکسان مدیریت شوند؟
ما در حالت ساده هیچ کنترلی روی ویژگی (Attribute) هایی که یک کلاس دارد نداریم.
وقتی شما کلاسی دارید که یک ویژگی به نام x دارد، هنگام کار با نمونههای ساختهشده از این کلاس میتوان هر مقداری را به این ویژگی نسبت داد.
مثلاً فرضکنید که ما یک کلاس به نام Person داریم که مقدار سن شخص در آن نگهداری میشود:
class Person:
def __init__(self, age):
self.age = age
حالا ما موقع ساخت یک نمونه از این کلاس میتوانیم «هرچیزی» را به آن نسبت بدهیم:
person1 = Person(10000)
person2 = Person(-10)
person3 = Person("I am not even an integer!")
در حالت ساده ما هیچ کنترلی روی ویژگیها نداریم. پس تمام نمونههای بالا از نظر زبان پایتون درست هستند. امّا این مقادیر منطق برنامهی ما را خراب میکنند.
شما میتوانید برای اعتبارسنجی (Validation) مقادیر کدهای اضافیای را درون init قرار بدهید. امّا آن کدها دیگر تغییرات مقادیر را پس از ساخت شئ کنترل نمیکنند.
حتّی میتوانید متدهایی برای اعتبارسنجی درون کلاستان بگذارید. امّا این کار تنها استفاده از کدتان را برای دیگران سختتر میکند و همواره این احتمال وجود دارد که برنامهنویس فراموش کند که پس از هرتغییری در هر جای کد، آن متدها را فراخوانی کند.
از این مورد بگذریم.
فرضکنید که شما میخواهید یک ویژگی درون کلاس A همیشه عدد مثبت باشد. حالا در جای دیگر برنامه نیازدارید که چند ویژگی کلاس B هم درست همین خاصیّت را داشته باشند.
کلاسهای A و B هم هیچ ربط منطقیای ندارند و نمیتوان به مواردی مثل ارثبری حتّی فکر کرد.
عالی نبود اگر میشد کاری کرد که ویژگیهای کلاس های مختلف، بدون اینکه به هم ربطی پیدا کنند، به یک شکل مدیریت شوند؟
خب Descriptor پروتکلی است که همهی این کارها را برای ما میکند.
پروتکل Descriptor خیلی ساده است. هر کلاسی که حداقل یکی از متدهای: set، get یا delete را پیادهسازی کند یک Descriptor حساب میشود.
کاربردها و مثال های Descriptor رو خودتون بخونید.
از سایت علی حسینی کپی کردم. این لینک
میخوام یه قابلیت ساده که توی جنگو هست رو توضیح بدم.
اما قبلش اگه بدونیم Descriptor چیه، یادگرفتنش باحال تر میشه.
پس اگه عمری بود، بقیه در پست های بعدی...
اسپانسر این قسمت 👈 لینک
👏6❤2👍2
جنگولرن
وات ایز F() expressions در جنگو 😁 جنگو در مورد تابع F توی داکیومنت میگه: An F() object represents the value of a model field, transformed value of a model field, or annotated column. It makes it possible to refer to model field values and perform database…
نکته ای از عثمان در مورد پست F
ی مورد دیگه که خود جنگو داره از F object استفاده میکنه زمانیه که شما سعی میکنی ی رکورد جدید توی تیبل ایجاد کنی که اگه همون موقع بدون کال کردن refresh_from_db بیای یکی از فیلدهای رکورد جدید رو تو ی کوئری یا ایجاد رکورد تو ی جدول دیگه استفاده کنی توی کوئری یا ترنزکشنت ORM میاد دقیقا به اسم همون فیلد ترجمه میکنه، مثال:
شما فکر کنید ی تیبل به اسم Stock دارید و ی تیبل دیگه به اسم StockLog
فیلدهای استاک:
quantity
quantity_allocated
فیلدهای استاک لاگ:
initial_quantity
final_quantity
حالا شما ی رکورد جدید تو تیبل استاک می سازید:
stock = Stock.objects.create(quantity=10, quantity_allocated=0)
و میای بعدش میگی:
StockLog.objects.create(initial_quantity=0, final_quantity=stock.quantity)
Orm -> insert into stocklog(initial_quantity, quantity) values(0, 10)
اینجا حتما باید حواست به رفرش قبل اساین باشه
ی مورد دیگه که خود جنگو داره از F object استفاده میکنه زمانیه که شما سعی میکنی ی رکورد جدید توی تیبل ایجاد کنی که اگه همون موقع بدون کال کردن refresh_from_db بیای یکی از فیلدهای رکورد جدید رو تو ی کوئری یا ایجاد رکورد تو ی جدول دیگه استفاده کنی توی کوئری یا ترنزکشنت ORM میاد دقیقا به اسم همون فیلد ترجمه میکنه، مثال:
شما فکر کنید ی تیبل به اسم Stock دارید و ی تیبل دیگه به اسم StockLog
فیلدهای استاک:
quantity
quantity_allocated
فیلدهای استاک لاگ:
initial_quantity
final_quantity
حالا شما ی رکورد جدید تو تیبل استاک می سازید:
stock = Stock.objects.create(quantity=10, quantity_allocated=0)
و میای بعدش میگی:
StockLog.objects.create(initial_quantity=0, final_quantity=stock.quantity)
Orm -> insert into stocklog(initial_quantity, quantity) values(0, 10)
اینجا حتما باید حواست به رفرش قبل اساین باشه
✍5🤔4❤1
چرا ذهن ما عاشق Abstraction زودهنگام است؟
خیلی وقتها در تیمهای نرمافزاری میبینیم که مهندسان خیلی زود به سراغ abstraction و generalization میروند. یعنی قبل از اینکه حتی نیاز واقعی شکل بگیرد، یک لایه انتزاعی طراحی میکنند تا برای آینده آماده باشند.
این رفتار بیدلیل نیست. ذهن ما از نظر تکاملی عادت دارد الگوها را سریع تشخیص دهد و تعمیم دهد. همین باعث شده است که حتی وقتی دو سناریوی مشابه میبینیم، ناخودآگاه به فکر ساختن یک راهحل عمومی میافتیم. در زندگی روزمره این توانایی به بقای ما کمک کرده، اما در دنیای نرمافزار همیشه مفید نیست.
مشکل اصلی اینجاست که وقتی زود abstraction بسازیم، سطح اشتباه را انتخاب میکنیم. نه آنقدر بالا که به درد بخورد، نه آنقدر دقیق که واقعاً نیاز را برطرف کند. نتیجه این میشود که کدی مینویسیم که پیچیدهتر از چیزی است که لازم داریم، و سرعت یادگیری و تغییر را پایین میآورد.
در عین حال، فرهنگ و فضای آموزشی هم این عادت را تقویت میکند. همه جا به ما گفتهاند تکرار بد است یا باید برای reuse طراحی کنی. در حالی که در بسیاری از موقعیتها بهترین کار این است که ابتدا با سادهترین راهحل شروع کنیم و بعد، وقتی چند بار نیاز تکرار شد و الگو روشن شد، سراغ abstraction برویم.
به جای پیشبینی آینده، باید برای تغییر آماده باشیم. به جای اینکه یک معماری عمومی از روز اول طراحی کنیم، بهتر است ساختار را طوری بچینیم که refactor راحت باشد. یعنی اول مسأله را حل کنیم، بعد اگر دیدیم الگو دارد تکرار میشود، abstraction را بسازیم.
آیا ما واقعاً میخواهیم برای آیندهای که هنوز نیامده هزینه بدهیم؟ یا میخواهیم امروز ساده شروع کنیم و اجازه بدهیم کد و معماری با واقعیت رشد کند؟
✍🏻 Kayvan Alimohammadi
خیلی وقتها در تیمهای نرمافزاری میبینیم که مهندسان خیلی زود به سراغ abstraction و generalization میروند. یعنی قبل از اینکه حتی نیاز واقعی شکل بگیرد، یک لایه انتزاعی طراحی میکنند تا برای آینده آماده باشند.
این رفتار بیدلیل نیست. ذهن ما از نظر تکاملی عادت دارد الگوها را سریع تشخیص دهد و تعمیم دهد. همین باعث شده است که حتی وقتی دو سناریوی مشابه میبینیم، ناخودآگاه به فکر ساختن یک راهحل عمومی میافتیم. در زندگی روزمره این توانایی به بقای ما کمک کرده، اما در دنیای نرمافزار همیشه مفید نیست.
مشکل اصلی اینجاست که وقتی زود abstraction بسازیم، سطح اشتباه را انتخاب میکنیم. نه آنقدر بالا که به درد بخورد، نه آنقدر دقیق که واقعاً نیاز را برطرف کند. نتیجه این میشود که کدی مینویسیم که پیچیدهتر از چیزی است که لازم داریم، و سرعت یادگیری و تغییر را پایین میآورد.
در عین حال، فرهنگ و فضای آموزشی هم این عادت را تقویت میکند. همه جا به ما گفتهاند تکرار بد است یا باید برای reuse طراحی کنی. در حالی که در بسیاری از موقعیتها بهترین کار این است که ابتدا با سادهترین راهحل شروع کنیم و بعد، وقتی چند بار نیاز تکرار شد و الگو روشن شد، سراغ abstraction برویم.
به جای پیشبینی آینده، باید برای تغییر آماده باشیم. به جای اینکه یک معماری عمومی از روز اول طراحی کنیم، بهتر است ساختار را طوری بچینیم که refactor راحت باشد. یعنی اول مسأله را حل کنیم، بعد اگر دیدیم الگو دارد تکرار میشود، abstraction را بسازیم.
آیا ما واقعاً میخواهیم برای آیندهای که هنوز نیامده هزینه بدهیم؟ یا میخواهیم امروز ساده شروع کنیم و اجازه بدهیم کد و معماری با واقعیت رشد کند؟
✍🏻 Kayvan Alimohammadi
❤8✍5👍3
This media is not supported in your browser
VIEW IN TELEGRAM
یکی از دانش آموزام اینو برام فرستاده
.
.
.
من معلم هنرستان کامپیوترم 😬
.
.
.
قبول شد
البته هنرستان باید 12 بگیرن که قبول بشن
.
.
.
من معلم هنرستان کامپیوترم 😬
.
.
.
قبول شد
البته هنرستان باید 12 بگیرن که قبول بشن
😁25
آیا می دانستید که وقتی ImageField یا FileField توی جنگو دارید، و اون رکورد حذف میشه، فایل هاش حذف نمیشن
درسته؟ قبول داری؟
تا جایی که من میدونم فایل ها حذف نمیشن
یا مثلا عکس رو تغییر بدیم، عکس قبلی ع توی سرور میمونه
در واقع media حذف نمیشه
راه حل چیه؟
چند تا راه هست (من اینارو بلدم):
-متد save و delete رو override کن و دستی حذف کن.
-از سیگنال های جنگو استفاده کن و رکورد حذف شد، سیگنال فایل هارو حذف کنه.
-استفاده از پکیج django-cleanup که دقیقا کارش همینه، و از سیگنال ها استفاده میکنه.
-استفاده از پکیج django-lifecycle که کارش حذف کردن فایل نیست، ولی با قابلیت hook ش میشه فایل های بی صاحب رو حذف کرد 😁
پکیج django-lifecycle برای من جالب بود
مدل مون باید از LifecycleModel ش ارث بری کنه
بعد یه سری Hook داره و میگه بعد از فلان اتفاق، فلان کار رو انجام بده
نمیاد سیگنال کال کنه، متد save و delete رو override کرده.
من باشم از هر دوشون همزمان استفاده میکنم.
با تشکر از Hossein Neysian
نظری اگه دارید بگید. مثلا ابزار یا پکیجی که برای این موارد استفاده میشه.
یا توی پروژه های Enterprise اینو چطور هندل میکنن، اصلا این مسئله هست توی پروژه های Enterprise ؟؟؟
اسپانسر این پست 👈 لینک
درسته؟ قبول داری؟
تا جایی که من میدونم فایل ها حذف نمیشن
یا مثلا عکس رو تغییر بدیم، عکس قبلی ع توی سرور میمونه
در واقع media حذف نمیشه
راه حل چیه؟
چند تا راه هست (من اینارو بلدم):
-متد save و delete رو override کن و دستی حذف کن.
-از سیگنال های جنگو استفاده کن و رکورد حذف شد، سیگنال فایل هارو حذف کنه.
-استفاده از پکیج django-cleanup که دقیقا کارش همینه، و از سیگنال ها استفاده میکنه.
-استفاده از پکیج django-lifecycle که کارش حذف کردن فایل نیست، ولی با قابلیت hook ش میشه فایل های بی صاحب رو حذف کرد 😁
پکیج django-lifecycle برای من جالب بود
مدل مون باید از LifecycleModel ش ارث بری کنه
بعد یه سری Hook داره و میگه بعد از فلان اتفاق، فلان کار رو انجام بده
نمیاد سیگنال کال کنه، متد save و delete رو override کرده.
من باشم از هر دوشون همزمان استفاده میکنم.
با تشکر از Hossein Neysian
نظری اگه دارید بگید. مثلا ابزار یا پکیجی که برای این موارد استفاده میشه.
یا توی پروژه های Enterprise اینو چطور هندل میکنن، اصلا این مسئله هست توی پروژه های Enterprise ؟؟؟
اسپانسر این پست 👈 لینک
✍15❤10👍2🆒2
جنگولرن
آیا می دانستید که وقتی ImageField یا FileField توی جنگو دارید، و اون رکورد حذف میشه، فایل هاش حذف نمیشن درسته؟ قبول داری؟ تا جایی که من میدونم فایل ها حذف نمیشن یا مثلا عکس رو تغییر بدیم، عکس قبلی ع توی سرور میمونه در واقع media حذف نمیشه راه حل چیه؟ …
نظر دوستان در مورد این پست:
کانال django experience نوشته:
پست خیلی خوبی بود گفتم اینجا هم اشتراک بزارم
من همیشه از django clean up استفاده میکردم و django lifecycle رو اولین بار بود میشنیدم اینکه از سیگنال استفاده نمیکنه خیلی جالب بود برام
داخل پروژه های بزرگ معمولا یه تسک دوره ای مثل celery beat میزارن که پوشه ی media رو اسکن کنه و فایل هایی که بی صاحاب شدن رو حذف کنه چون همیشه هم حذف رکورد از طریق orm انجام نمیشه که سیگنال یا lifecycle بتونه واکنش نشون بده
آقای جبار زاده نوشته:
میشه کلاس storage رو override کرد و این قابلیت ها رو داخلش قرار داد
تمیز تر از سیگنال و امثالش هست
کانال django experience نوشته:
پست خیلی خوبی بود گفتم اینجا هم اشتراک بزارم
من همیشه از django clean up استفاده میکردم و django lifecycle رو اولین بار بود میشنیدم اینکه از سیگنال استفاده نمیکنه خیلی جالب بود برام
داخل پروژه های بزرگ معمولا یه تسک دوره ای مثل celery beat میزارن که پوشه ی media رو اسکن کنه و فایل هایی که بی صاحاب شدن رو حذف کنه چون همیشه هم حذف رکورد از طریق orm انجام نمیشه که سیگنال یا lifecycle بتونه واکنش نشون بده
آقای جبار زاده نوشته:
میشه کلاس storage رو override کرد و این قابلیت ها رو داخلش قرار داد
تمیز تر از سیگنال و امثالش هست
👍12
Media is too big
VIEW IN TELEGRAM
پشت صحنه دستور pip install django چیه؟
یا غوداااا اینو تقریبا 4 سال و نیم پیش ضبط کردم.
خودم تا آخرش دیدم، یادم نبود چی میشه.
✔️ کاربرد فایل های setup.py و setup.cfg چیه؟
✔️ دستور pip install چطور متوجه وابستگی یا همون dependency های پکیج ها میشه؟
✔️ چطور میتونیم django-admin رو عوض کنیم و به جای اون از milad-admin استفاده کنیم؟ 😂
✅ جواب همه سوال های بالا رو توی یه ویدئو ۱۲ دقیقه ای بهتون میگم.
لینک آپارات:
https://www.aparat.com/v/ofjc5
لینک یوتیوب:
https://youtu.be/DUP9YU7_6jo
یا غوداااا اینو تقریبا 4 سال و نیم پیش ضبط کردم.
خودم تا آخرش دیدم، یادم نبود چی میشه.
✔️ کاربرد فایل های setup.py و setup.cfg چیه؟
✔️ دستور pip install چطور متوجه وابستگی یا همون dependency های پکیج ها میشه؟
✔️ چطور میتونیم django-admin رو عوض کنیم و به جای اون از milad-admin استفاده کنیم؟ 😂
✅ جواب همه سوال های بالا رو توی یه ویدئو ۱۲ دقیقه ای بهتون میگم.
لینک آپارات:
https://www.aparat.com/v/ofjc5
لینک یوتیوب:
https://youtu.be/DUP9YU7_6jo
🔥12❤4👍3🆒1
Forwarded from سید فرندز / برنامه نویسی / هک و امنیت / تکنولوژی (Mohammad Khoshnava)
پست محسن باقری CTO شرکت irantic در لینکدین :
فروش ۲۸ هزار صندلی در کمتر از ۱۵ دقیقه!!!
یکی از نفسگیرترین لحظهها در صنعت تیکتینگ، شروع فروش یک ایونت بزرگ هستش.
روی صفحه همهچیز ساده به نظر میاد: یک دکمهی "خرید بلیت" و تمام.
ولی پشت صحنه چه اتفاقهایی باعث میشه فروشی در این مقیاس به درستی انجام بشه؟ هزاران درخواست در یک لحظه به سرورها هجوم میارن و هر ثانیهاش میتونه تعیینکننده باشه.
ما سالها در Irantic روی تیکتینگ سینما کار کردیم؛ جایی که بار روی سامانه بهصورت یکنواخت و تدریجی پخش میشه.
اما وقتی رسیدیم به کنسرت علیرضا قربانی در پارکینگ ورزشگاه آزادی، همهچیز فرق کرد.
استقبال عجیب کاربرها، محدود بودن صندلیها و رقابت شدید باعث شد تجربهای کاملاً متفاوت رو پشت سر بذاریم.
اینجا همهچیز به چند ثانیه بستگی داشت. باید اپلیکیشن رو برای خرید بیش از صد هزار کاربر همزمان مدیریت میکردیم و در عین حال جلوی Race Conditionهایی رو میگرفتیم که میتونستن کل خرید رو به هم بریزن.
برای رسیدن به این هدف، تغییرات مهمی در سیستم دادیم:
- درخواستها رو با لیستها و کلیدهای مختلف در Redis بازطراحی کردیم تا هر لیست مستقل مدیریت بشه.
-بهینهسازی حجم دادههای اپلیکیشن یکی از سختترین چالشها بود. ما باید حجم ریسپانس را طوری کاهش میدادیم که بدون از دست دادن اطلاعات حیاتی، به اندازهای کوچک بشه که معمولاً در یک سگمنت TCP منتقل بشه. وقتی داده در حجم پایین ارسال میشه، سرعت دریافت بالاتر، تأخیر کمتر و احتمال خطا نیز کمتر خواهد بود .البته در بعضی لحظات، حجم داده بیشتر از چند بایت میشد، ولی همون بهینهسازی برای چند ثانیهی طلایی فروش، تفاوت بزرگی ایجاد کرد.
- کش رو طوری تنظیم کردیم که هر لیست با سیاست خودش پاک بشه.
- یک مرحلهی میانی به رزرو اضافه کردیم تا متد اصلی سبکتر بمونه.
- در فرانتاند، مهمترین دغدغه نمایش درست و استفاده بهینه از ریسورس ها در دستگاهها بود. وقتی کاربر روی موبایل یا دسکتاپ وارد میشه، انتظار داره تجربهای روان و بینقص داشته باشه. این یعنی رندر شدن سریع صندلیها، الگوریتمهای دقیق برای جایگذاری صندلیها در حالتهای مختلف صفحه، و جلوگیری از افت کیفیت یا کندی. کوچکترین باگ در این بخش میتونست کل تجربه خرید رو خراب کنه
- در زیرساخت (DevOps)، پایداری و مانیتورینگ مهمترین بخش برای ما بود. آمادهسازی برای پیک ترافیک و مانیتورینگ لحظهای باعث شد حتی در اوج فشار، سامانه بدون مشکل کارش رو انجام بده.
- بخش مهم دیگه، انجام استرستستهای واقعی بود؛ جایی که با شبیهسازی بار سنگین روی سامانه، قبل از روز رویداد تمام نقاط ضعف احتمالی رو شناسایی و رفع کردیم. همین تستها باعث شد لحظهی اصلی، غافلگیر نشیم.
نتیجه؟
تمام ۲۸ هزار صندلی در کمتر از ۱۵ دقیقه سولد اوت شد، بدون اینکه تجربهی خرید کاربرها خدشهدار بشه.
✅ @SEYED_BAX
فروش ۲۸ هزار صندلی در کمتر از ۱۵ دقیقه!!!
یکی از نفسگیرترین لحظهها در صنعت تیکتینگ، شروع فروش یک ایونت بزرگ هستش.
روی صفحه همهچیز ساده به نظر میاد: یک دکمهی "خرید بلیت" و تمام.
ولی پشت صحنه چه اتفاقهایی باعث میشه فروشی در این مقیاس به درستی انجام بشه؟ هزاران درخواست در یک لحظه به سرورها هجوم میارن و هر ثانیهاش میتونه تعیینکننده باشه.
ما سالها در Irantic روی تیکتینگ سینما کار کردیم؛ جایی که بار روی سامانه بهصورت یکنواخت و تدریجی پخش میشه.
اما وقتی رسیدیم به کنسرت علیرضا قربانی در پارکینگ ورزشگاه آزادی، همهچیز فرق کرد.
استقبال عجیب کاربرها، محدود بودن صندلیها و رقابت شدید باعث شد تجربهای کاملاً متفاوت رو پشت سر بذاریم.
اینجا همهچیز به چند ثانیه بستگی داشت. باید اپلیکیشن رو برای خرید بیش از صد هزار کاربر همزمان مدیریت میکردیم و در عین حال جلوی Race Conditionهایی رو میگرفتیم که میتونستن کل خرید رو به هم بریزن.
برای رسیدن به این هدف، تغییرات مهمی در سیستم دادیم:
- درخواستها رو با لیستها و کلیدهای مختلف در Redis بازطراحی کردیم تا هر لیست مستقل مدیریت بشه.
-بهینهسازی حجم دادههای اپلیکیشن یکی از سختترین چالشها بود. ما باید حجم ریسپانس را طوری کاهش میدادیم که بدون از دست دادن اطلاعات حیاتی، به اندازهای کوچک بشه که معمولاً در یک سگمنت TCP منتقل بشه. وقتی داده در حجم پایین ارسال میشه، سرعت دریافت بالاتر، تأخیر کمتر و احتمال خطا نیز کمتر خواهد بود .البته در بعضی لحظات، حجم داده بیشتر از چند بایت میشد، ولی همون بهینهسازی برای چند ثانیهی طلایی فروش، تفاوت بزرگی ایجاد کرد.
- کش رو طوری تنظیم کردیم که هر لیست با سیاست خودش پاک بشه.
- یک مرحلهی میانی به رزرو اضافه کردیم تا متد اصلی سبکتر بمونه.
- در فرانتاند، مهمترین دغدغه نمایش درست و استفاده بهینه از ریسورس ها در دستگاهها بود. وقتی کاربر روی موبایل یا دسکتاپ وارد میشه، انتظار داره تجربهای روان و بینقص داشته باشه. این یعنی رندر شدن سریع صندلیها، الگوریتمهای دقیق برای جایگذاری صندلیها در حالتهای مختلف صفحه، و جلوگیری از افت کیفیت یا کندی. کوچکترین باگ در این بخش میتونست کل تجربه خرید رو خراب کنه
- در زیرساخت (DevOps)، پایداری و مانیتورینگ مهمترین بخش برای ما بود. آمادهسازی برای پیک ترافیک و مانیتورینگ لحظهای باعث شد حتی در اوج فشار، سامانه بدون مشکل کارش رو انجام بده.
- بخش مهم دیگه، انجام استرستستهای واقعی بود؛ جایی که با شبیهسازی بار سنگین روی سامانه، قبل از روز رویداد تمام نقاط ضعف احتمالی رو شناسایی و رفع کردیم. همین تستها باعث شد لحظهی اصلی، غافلگیر نشیم.
نتیجه؟
تمام ۲۸ هزار صندلی در کمتر از ۱۵ دقیقه سولد اوت شد، بدون اینکه تجربهی خرید کاربرها خدشهدار بشه.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥14❤4👍1
🛡️ محافظت از فرم لاگین با Django-Defender
حملات brute-force 🔐 یکی از رایج ترین روشهای نفوذ به وبسایت ها هستند
جایی که هکرا با تلاشهای مکرر سعی میکنن رمز عبور کاربران را حدس بزنند.
کتابخانهی Django-Defender ⚡ ابزاری سبک، سریع و مطمئن برای مقابله با این حملات در پروژههای Django است.
✨ امکانات کلیدی
🚫 شمارش تلاشهای ناموفق ورود و بلاک کردن کاربر یا ip
⚡ استفاده از کش (Redis یا Memcached) برای عملکرد سریع
⏱️ امکان تنظیم تعداد تلاشهای مجاز و زمان بلاک (cool-off)
📊 ذخیره لاگها و مشاهده آنها در پنل مدیریت Django
🔐 بلاک بر اساس ip یا ترکیب یوزرنیم + ip
⚙️ نصب و راهاندازی
در settings.py تنظیمات پایه رو برای کانفیگ django defender اضافه کنید:
تنظیمات اصلی:
1⃣ DEFENDER_REDIS_URL :
مشخص میکنه داده های تلاش نا موفق کجا ذخیره میشن "redis://127.0.0.1:6379/0" یعنی Redis روی لوکال با پورت 6379 ودیتابیس شماره 0 اجرا بشه.
2⃣ DEFENDER_LOGIN_FAILURE_LIMIT:
تعداد دفعاتی که یک کاربر یا ip میتونه رمز اشتباه وارد کنه قبل از اینکه بلاک شه.
مثال: مقدار ۵ → بعد از ۵ تلاش ناموفق، بلاک فعال میشه
3⃣ DEFENDER_COOLOFF_TIME :
مدت زمان بلاک به ثانیه.
به عنوان مثال اینجا ۳۰۰ ثانیه یعنی بعد از بلاک شدن؛کاربر یا ip برای ۵ دقیقه نمیتونه لاگین کنه
4⃣ DEFENDER_LOCK_OUT_BY_COMBINATION_USER_AND_IP :
تعیین میکنه که مکانیزم بلاک چگونه عمل کنه و معیار محدودسازی کاربران چی باشه. مثلا وقتی متغیر روی True تنظیم شه، بلاک بر اساس ترکیب یوزرنیم و ip اعمال میشه؛ یعنی حتی اگر کاربر از یک ip جدید وارد شه، اگر همان یوزرنیم را استفاده کنه همچنان محدود خواهد بود و اجازه ورود نداره. اگر این متغیر روی False باشه، بلاک فقط بر اساس ip اعمال میشود و یوزرنیم میتونه از ip دیگر بدون مشکل وارد شه. این تنظیم باعث افزایش دقت امنیتی و جلوگیری از دور زدن محدودیتها توسط تغییر ip میشود.
5⃣ DEFENDER_STORE_FAILURES :
اگر True باشه، تلاشهای ناموفق در دیتابیس ذخیره میشن و میتونیم اونارو را تو پنل ادمین ببینیم
این ویژگی کمک میکند تحلیل و بررسی حملات راحت تر باشد
مایگریشن ها رو اجرا کنید:
🧪 تست عملکرد
5 بار با اطلاعات اشتباه سعی کنید داخل پروژه جنگویی خودتون لاگین کنید 🔑
پس از رسیدن به تعداد تلاشهای مجاز، دسترسی موقت بلاک خواهد شد 🚫
لاگها در پنل مدیریت ذخیره میشوند 📊
با فعال بودن LOCK_OUT_BY_COMBINATION_USER_AND_IP، حتی با IP جدید همان یوزرنیم بلاک خواهد شد 🔒
🎯 نتیجه:
اعمال چند خط تنظیمات ساده در Django-Defender، امنیت فرم لاگین پروژه شما به شکل چشمگیری افزایش مییابد. این ابزار به طور مؤثر جلوی حملات brute-force را میگیرد، تلاشهای ناموفق کاربران را ردیابی میکند و امکان مسدودسازی موقت ip یا یوزرنیم را فراهم میکند. با ذخیره لاگها در دیتابیس و بررسی آنها در پنل مدیریت، میتوانید فعالیتهای مشکوک را شناسایی کرده و امنیت کلی سایت خود را ارتقا دهید. به این ترتیب کنترل کامل بر دسترسی کاربران و حفاظت از حسابها برای شما ساده و قابل اطمینان خواهد بود ✅
✍ @Django_Experience
حملات brute-force 🔐 یکی از رایج ترین روشهای نفوذ به وبسایت ها هستند
جایی که هکرا با تلاشهای مکرر سعی میکنن رمز عبور کاربران را حدس بزنند.
کتابخانهی Django-Defender ⚡ ابزاری سبک، سریع و مطمئن برای مقابله با این حملات در پروژههای Django است.
✨ امکانات کلیدی
🚫 شمارش تلاشهای ناموفق ورود و بلاک کردن کاربر یا ip
⚡ استفاده از کش (Redis یا Memcached) برای عملکرد سریع
⏱️ امکان تنظیم تعداد تلاشهای مجاز و زمان بلاک (cool-off)
📊 ذخیره لاگها و مشاهده آنها در پنل مدیریت Django
🔐 بلاک بر اساس ip یا ترکیب یوزرنیم + ip
⚙️ نصب و راهاندازی
pip install django-defender
در settings.py تنظیمات پایه رو برای کانفیگ django defender اضافه کنید:
INSTALLED_APPS = [
...,
"defender",
]
MIDDLEWARE = [
...,
"defender.middleware.FailedLoginMiddleware",
]
تنظیمات اصلی:
DEFENDER_REDIS_URL = "redis://127.0.0.1:6379/0"
DEFENDER_LOGIN_FAILURE_LIMIT = 5
DEFENDER_COOLOFF_TIME = 300
DEFENDER_LOCK_OUT_BY_COMBINATION_USER_AND_IP = True
DEFENDER_STORE_FAILURES = True
1⃣ DEFENDER_REDIS_URL :
مشخص میکنه داده های تلاش نا موفق کجا ذخیره میشن "redis://127.0.0.1:6379/0" یعنی Redis روی لوکال با پورت 6379 ودیتابیس شماره 0 اجرا بشه.
2⃣ DEFENDER_LOGIN_FAILURE_LIMIT:
تعداد دفعاتی که یک کاربر یا ip میتونه رمز اشتباه وارد کنه قبل از اینکه بلاک شه.
مثال: مقدار ۵ → بعد از ۵ تلاش ناموفق، بلاک فعال میشه
3⃣ DEFENDER_COOLOFF_TIME :
مدت زمان بلاک به ثانیه.
به عنوان مثال اینجا ۳۰۰ ثانیه یعنی بعد از بلاک شدن؛کاربر یا ip برای ۵ دقیقه نمیتونه لاگین کنه
4⃣ DEFENDER_LOCK_OUT_BY_COMBINATION_USER_AND_IP :
تعیین میکنه که مکانیزم بلاک چگونه عمل کنه و معیار محدودسازی کاربران چی باشه. مثلا وقتی متغیر روی True تنظیم شه، بلاک بر اساس ترکیب یوزرنیم و ip اعمال میشه؛ یعنی حتی اگر کاربر از یک ip جدید وارد شه، اگر همان یوزرنیم را استفاده کنه همچنان محدود خواهد بود و اجازه ورود نداره. اگر این متغیر روی False باشه، بلاک فقط بر اساس ip اعمال میشود و یوزرنیم میتونه از ip دیگر بدون مشکل وارد شه. این تنظیم باعث افزایش دقت امنیتی و جلوگیری از دور زدن محدودیتها توسط تغییر ip میشود.
5⃣ DEFENDER_STORE_FAILURES :
اگر True باشه، تلاشهای ناموفق در دیتابیس ذخیره میشن و میتونیم اونارو را تو پنل ادمین ببینیم
این ویژگی کمک میکند تحلیل و بررسی حملات راحت تر باشد
مایگریشن ها رو اجرا کنید:
python manage.py migrate
🧪 تست عملکرد
5 بار با اطلاعات اشتباه سعی کنید داخل پروژه جنگویی خودتون لاگین کنید 🔑
پس از رسیدن به تعداد تلاشهای مجاز، دسترسی موقت بلاک خواهد شد 🚫
لاگها در پنل مدیریت ذخیره میشوند 📊
با فعال بودن LOCK_OUT_BY_COMBINATION_USER_AND_IP، حتی با IP جدید همان یوزرنیم بلاک خواهد شد 🔒
🎯 نتیجه:
اعمال چند خط تنظیمات ساده در Django-Defender، امنیت فرم لاگین پروژه شما به شکل چشمگیری افزایش مییابد. این ابزار به طور مؤثر جلوی حملات brute-force را میگیرد، تلاشهای ناموفق کاربران را ردیابی میکند و امکان مسدودسازی موقت ip یا یوزرنیم را فراهم میکند. با ذخیره لاگها در دیتابیس و بررسی آنها در پنل مدیریت، میتوانید فعالیتهای مشکوک را شناسایی کرده و امنیت کلی سایت خود را ارتقا دهید. به این ترتیب کنترل کامل بر دسترسی کاربران و حفاظت از حسابها برای شما ساده و قابل اطمینان خواهد بود ✅
✍ @Django_Experience
👏8👍3✍1❤1