Syntax | سینتکس
3.02K subscribers
410 photos
108 videos
35 files
377 links
Download Telegram
چند نکته طلایی موقعی که دارید از django orm استفاده می کنید.

(قسمت اول)

1. کوئری ست هارو کاربردی بزنید:
از filters و annotations و aggregation استفاده کنید تا فیلد هایی که نیاز دراید رو با کمترین سربار دریافت کنید.
همچنین از متد defer و only برای محدود کردن فیلد هایی که قراره از دیتابیس بگیرید استفاده کنید تا optimize تر بشه کوئری شما و همچنین مصرف مموری نیز کمتر بشه.

# Fetches specific fields to avoid unneccessory fields fetch and store into the memory
blogs = Blog.objects.only('title', 'is_active').filter(category='tech')


2. ایندکس کردن:
استفاده کردن از ایندکس کلید افزایش کارامدی و سرعت کوئری های شما هستش.
هر فیلدی که قراره زیاد توی Where استفاده کنید رو پیشنهاد میشه ایندکس کنید.

# Adding an index to the "category" column for faster searches via category
class Blog(models.Model):
title = models.CharField(max_length=100)
category = models.CharField(max_length=50, db_index=True)
# ...


همچنین ممکنه ایندکس کردن مخرب هم باشه. به این لینک سر بزنید:
https://python.plainenglish.io/mastering-the-art-of-meeting-database-indexing-needs-8b891e74794b

3. کوئری ها بصورت defer اجرا میشن!!
جنگو orm از این روش استفاده می کند تا کوئری ها تنها زمانی اجرا بشن که شما بهشون نیاز دارید. یعنی وقتی شما مینویسید
users = User.objects.all()
این کوئری اجرا نمیشود، تا زمانی که شما از مقدار users استفاده کنید.
همچنین اگه شما حواستون نباشه ممکنه یک اشتباه خیلی بزرگ انجام بدید. به مثال زیر دقت کنید:

# Queries are executed when data is actually needed, minimizing unnecessary hits
blogs = Blog.objects.all()
for blog in blogs:
print(blog.author) # Each blog's author query is executed here

تو این مثال هربار که blog.author رو میزنیم، یک hint سمت دیتابیس زده میشه.

4. از select_related و prefetch_related استفاده کنید.
این دو متد میتونن وقتی که توی مدلتون related دارید، تعداد کوئری هایی که سمت دیتابیس زده میشن رو خیلی کاهش بدن.
از select_related زمانی استفاده میشه که شما یک تک رابطه دارید. و از prefetch_related زمانی استفاده میشه که شما چندین رابطه دارید. مثلا:

# Reduces database queries using select_related when accessing related objects 
blogs = Blog.objects.select_related('author').all()
for blog in blogs:
print(blog.author)


# Retrieves related objects in separate queries using prefetch_related, improving performance
authors = Author.objects.prefetch_related('blogs').all()
for author in authors:
for blog in author.blogs.all():
print(post)


5. از n + 1 اجتناب کنید!
مشکل n + 1 زمانی اتفاق میوفته که شما میخواید مجموعه از آبجکت هارو بگیرید. مثلا فرض کنید مدل پست رو داریم. مدل پست n تا کامنت داره.
زمانی که شما میخواید تک تک کامنت هارو بگیرید و اطلاعاتش رو نشون بدید با n + 1 مواجه میشوید.
یک یعنی کوئری که برای گرفتن پست زده شده، و n تعداد کوئری هایی که برای گرفتن کامنت ها زده شده. از این قبیل مشکلات رو خیلی راحت میتونیم با select_related و prefetch_related برطرف کنیم و با یک کوئری اطلاعات تمامی کامنت هارو هم بگیریم(این رو هم در نظر بگیرید هر چقدر کامنت ها بیشتر باشه، کوئری که میزنیم سنگین تر میشه).
# Using prefetch_related to fetch related comments efficiently
blogs = Blog.objects.prefetch_related('comments').all()
for blog in blogs:
for comment in blog.comments.all():
print(comment)


link

#django #orm

@Syntax_fa
🔥11
Syntax | سینتکس
چند نکته طلایی موقعی که دارید از django orm استفاده می کنید. (قسمت اول) 1. کوئری ست هارو کاربردی بزنید: از filters و annotations و aggregation استفاده کنید تا فیلد هایی که نیاز دراید رو با کمترین سربار دریافت کنید. همچنین از متد defer و only برای محدود کردن…
چند نکته طلایی موقعی که داری از django orm استفاده می کنی.

(قسمت دوم)

6. افزایش پرفورمنس با استفاده از کش کردن.
کش کردن باعث میشه تعداد کوئری هایی که سمت دیتابیس میزنیم کاهش پیدا کنه. همچنین ریسپانس تایم دریافت اطلاعات خیلی کمتر بشه.
براش کش کردن می تونید از کش فریم ورک built-in جنگو استفاده کنید.
from django.core.cache import cache

# Retrieve posts from cache, if available
cached_posts = cache.get('all_posts')
if cached_posts is None:
cached_posts = list(Post.objects.all())
cache.set('all_posts', cached_posts)


7. وقتی صحبت از آپدیت کردن و دیلیت کردن چندین row می شه، جنگو دو متد به اسم delete و update در اختیار ما قرار داده تا با پرفورمنس بهتر و سربار کمتر عملیات آپدیت و دیلیت کردن رو انجام بدیم.
# Updating multiple posts' status in a single query
Blog.objects.filter(category='draft').update(status='published')


8. بررسی و آنالیز کردن:
برای بررسی و دیباگ کردن، ابزار های زیادی در جنگو وجود دارد. مانند django debug toolbar. آنالیز کردن کوئری ها باعث میشه متوجه باتل نک ها شویم و بتونیم پرفومنس کوئری هارو افزایش بدیم.

9. از متد explain جنگو orm استفاده کن!!
همیشه از این متد استفاده کنید تا مطمئن شوید کوئری sql که orm برای شما ساخته است بهینه است و همان چیزی است که شما می خواهید.

10. عملیات هارو داخل دیتابیس انجام بده، نه توی زبان برنامه نویسی!!
کار های پایه رو میتونی با متد filter و exclude جنگو orm انجام بدی.
انجام یک سری عملیات ها روی فیلد هارو با F expression انجام بده
از annotation و aggregation استفاده کن

link

#django #orm

@Syntax_fa
👍11
متد iterator در django orm

در Django ORM، متد iterator() یک ابزار کارآمد برای پردازش مجموعه‌های داده بزرگ است. این متد یک ایتراتور (iterator) را برمی‌گرداند که می‌توانید آن را برای دسترسی تدریجی به رکوردهای جدول استفاده کنید. این روش در مقایسه با متدهای معمولی مانند all() یا values() که تمام رکوردها را یکباره در حافظه بارگذاری می‌کنند، کارآمدتر است.

مثال کاربردی:
فرض کنید می‌خواهید یک فایل CSV را از رکوردهای یک جدول در پایگاه داده پر کنید. اگر تعداد رکوردها بسیار زیاد باشد، بارگذاری همه آنها در حافظه ممکن است باعث مشکلات مربوط به مصرف حافظه شود. در چنین مواردی، می‌توانید از iterator() استفاده کنید تا رکوردها را به صورت تدریجی پردازش کنید.

from django.core.files import File
from myapp.models import MyModel

# باز کردن فایل CSV برای نوشتن
csv_file = open('data.csv', 'w')

# نوشتن سرآیند (headers) در فایل CSV
csv_file.write('field1,field2,field3\n')

# استفاده از iterator() برای دسترسی تدریجی به رکوردها
for obj in MyModel.objects.iterator():
# نوشتن هر رکورد در فایل CSV
csv_file.write(f'{obj.field1},{obj.field2},{obj.field3}\n')

# بستن فایل CSV
csv_file.close()


در این مثال، ما از MyModel.objects.iterator() برای دریافت یک ایتراتور استفاده می‌کنیم. سپس با یک حلقه `for`، هر رکورد را به صورت تدریجی پردازش می‌کنیم و آن را در فایل CSV می‌نویسیم.

مزایای استفاده از iterator():

1. کارآمدی حافظه: رکوردها به صورت تدریجی در حافظه بارگذاری می‌شوند، بنابراین حافظه کمتری مصرف می‌شود.
2. پردازش تدریجی: می‌توانید رکوردها را یکی یکی پردازش کنید، بدون نیاز به بارگذاری همه آنها در حافظه.
3. سرعت بالا: معمولاً سریعتر از بارگذاری همه رکوردها در حافظه و سپس پردازش آنهاست.

توجه داشته باشید که iterator() فقط یک بار قابل استفاده است و پس از پایان حلقه، دیگر قابل استفاده نیست. همچنین، شما نمی‌توانید از فیلترها یا سورت‌کردن رکوردها با iterator() استفاده کنید. برای این کارها، باید ابتدا یک QuerySet معمولی ایجاد کنید و سپس از iterator() روی آن استفاده کنید.


وقتی از iterator استفاده می کنیم، سمت دیتابیس چه اتفاقی می افتد؟

زمانی که از iterator() در Django ORM استفاده می‌کنید، Django در سمت پایگاه داده یک "Server-side Cursor" را ایجاد می‌کند. این کارسر (Cursor) در واقع یک ابزار در سمت سرور پایگاه داده است که به شما امکان می‌دهد رکوردها را یکی یکی و به صورت تدریجی از پایگاه داده بخوانید، بدون اینکه نیاز باشد همه رکوردها را یکباره در حافظه بارگذاری کنید.

فرآیند کار با Server-side Cursor به این شرح است:

1. ایجاد کارسر: زمانی که از iterator() استفاده می‌کنید، Django یک درخواست SQL برای ایجاد یک کارسر در سمت سرور پایگاه داده ارسال می‌کند.

2. اجرای درخواست: سرور پایگاه داده درخواست SQL را اجرا می‌کند و یک کارسر ایجاد می‌کند که به صورت تدریجی می‌تواند رکوردها را بازیابی کند.

3. بازیابی تدریجی رکوردها: در هر بار که در حلقه for به رکورد بعدی می‌رسید، Django از طریق کارسر ایجاد شده، درخواست بازیابی رکورد بعدی را به سرور پایگاه داده ارسال می‌کند.

4. دریافت رکورد: سرور پایگاه داده رکورد بعدی را از طریق کارسر بازیابی می‌کند و آن را به Django برمی‌گرداند.

5. تکرار گام 3 و 4: این فرآیند تا زمانی که همه رکوردها بازیابی شوند یا حلقه for متوقف شود، ادامه می‌یابد.

6. بستن کارسر: پس از اتمام حلقه، Django درخواست بستن کارسر را به سرور پایگاه داده ارسال می‌کند.

استفاده از Server-side Cursor به این معنی است که رکوردها به صورت تدریجی از پایگاه داده بازیابی می‌شوند، بدون اینکه نیاز باشد همه آنها یکباره در حافظه لود شوند. این امر باعث صرفه‌جویی در مصرف حافظه و افزایش کارایی می‌شود، به ویژه زمانی که با مجموعه‌های داده بزرگ سروکار دارید.

#django #cursor

@Syntax_fa
👍11
چرا باید از F expression توی django orm استفاده کنیم؟

در Django ORM، F expressions یا عبارات F، یک راه قدرتمند برای انجام عملیات روی فیلدهای مدل در سطح پایگاه داده هستند. با استفاده از عبارات F، می‌توانید مقادیر فیلدها را در پایگاه داده بدون بازیابی و بروزرسانی در سطح کد Python تغییر دهید. این امر می‌تواند منجر به افزایش کارایی و جلوگیری از رخ دادن مشکلات race condition شود.

مثال کاربردی:
فرض کنید یک برنامه فروشگاه آنلاین دارید و می‌خواهید در هنگام خرید، تعداد موجودی کالا را کاهش دهید. می‌توانید این کار را با استفاده از عبارات F در Django ORM به شکل زیر انجام دهید:

from django.db.models import F

# مدل Product
class Product(models.Model):
name = models.CharField(max_length=100)
stock = models.PositiveIntegerField()

# مثال خرید یک محصول
product = Product.objects.get(name='iPhone')
product.stock = F('stock') - 1
product.save()


در این مثال، ما از F('stock') استفاده می‌کنیم تا به Django بگوییم که مقدار فعلی فیلد stock را از پایگاه داده بخواند. سپس، عملگر - را به این مقدار اعمال می‌کنیم تا یک واحد از آن کم شود. در نهایت، با استفاده از `product.save()`، مقدار جدید را در پایگاه داده ذخیره می‌کنیم.

مزیت استفاده از عبارات F در این مثال این است که عملیات کاهش موجودی در سطح پایگاه داده انجام می‌شود، نه در سطح کد Python. این امر از بروز مشکلات race condition جلوگیری می‌کند، زیرا اگر چندین کاربر همزمان سعی در خرید یک محصول داشته باشند، عملیات کاهش موجودی به درستی انجام خواهد شد.

عبارات F همچنین می‌توانند برای انجام عملیات پیچیده‌تر روی فیلدهای مدل استفاده شوند. به عنوان مثال، می‌توانید از آنها برای محاسبه درصد تخفیف و کاهش قیمت یک محصول استفاده کنید:

from django.db.models import F

product.price = F('price') * (1 - F('discount_percent') / 100)
product.save()


در این مثال، ما از عبارات F برای محاسبه قیمت جدید محصول با توجه به درصد تخفیف آن استفاده می‌کنیم.

عبارات F همچنین با عملگرهای انضمامی (annotated aggregates) و عملگرهای مقایسه‌ای قابل استفاده هستند، که می‌تواند آنها را به ابزاری قدرتمند برای پردازش داده‌ها در سطح پایگاه داده تبدیل کند.

#django #orm

@Syntax_fa
🔥12
Django ORM Tips Part 2.pdf
452.9 KB
نکته های کاربردی در Django ORM (بخش دوم)

خوب در ادامه تکنیک های استفاده از Django ORM رسیدیم به اینکه چطور میشه از annotate و aggregate استفاده کرد. به قطعیت توی پروژه های بزرگتر و عموما مبتنی بر اطلاعات کاربر و شخصی سازی ها میرسید به نقطه ای که لازم باشه فیلد های متفاوتی داشته باشید که بتونید در لحظه ایجاد و مبتنی بر اونها فیلتر سازی و یا حتی مرتب سازی انجام بدید که خوب annotate این کار رو براتون انجام میده و یا اینکه بخواید محاسباتی رو مبتنی بر داده های موجود انجام بدید و در جایی دیگر استفاده کنید که در این شرایط قطعا aggregate مناسبترین هستش.
اما در شرایطی پیش میاد که اصلا از orm استفاده نکنید ولی بتونین query مستقیم به دیتابیس بزنین در این صورت می تونین با استفاده از متد raw این کار رو انجام بدید. البته که بیشتر مواقع توصیه نمیشه ولی دونستنش بد نیست. یه زمانی دیده بودم که query raw لزوما سریعتر عمل می کرد.

موارد بررسی شده:

- aggregate
- annotate
- raw query

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

link

#django

@Syntax_fa
👍6
چه زمانی از gettex_lazy استفاده کنیم و چه زمانی از pgettext_lazy !

در جنگو، pgettext_lazy و gettext_lazy هر دو برای ترجمه متن‌ها استفاده می‌شوند، اما با یک تفاوت کلیدی:

gettext_lazy:
این تابع برای ترجمه ساده متن‌ها استفاده می‌شود. هنگامی که یک متن را با gettext_lazy فراخوانی می‌کنید، جنگو آن را برای ترجمه در زمان اجرا نگه می‌دارد.

مثال:
from django.utils.translation import gettext_lazy as _

my_text = _("Hello, World!")


pgettext_lazy:
این تابع برای ترجمه متن‌هایی استفاده می‌شود که در زمینه‌های مختلف معانی متفاوتی دارند. برای مثال، کلمه "book" می‌تواند به معنی "کتاب" یا "رزرو کردن" باشد. pgettext_lazy به شما امکان می‌دهد تا زمینه (context) را برای متن تعریف کنید تا مترجم بتواند ترجمه صحیح را انتخاب کند.

مثال:
from django.utils.translation import pgettext_lazy

book_obj = pgettext_lazy("Noun", "book") # معنی "کتاب"
book_verb = pgettext_lazy("Verb", "book") # معنی "رزرو کردن"


در این مثال، pgettext_lazy اولین آرگومان را به عنوان زمینه و دومین آرگومان را به عنوان متن برای ترجمه در نظر می‌گیرد.

#django

@Syntax_fa
👍10🔥1
نحوه ذخیره کردن slug تو یکی از پکیج های معروف جنگویی رو با هم ببینیم.

توضیح پست بعدی

#django

@Syntax_fa
😱4👍1
Syntax | سینتکس
نحوه ذخیره کردن slug تو یکی از پکیج های معروف جنگویی رو با هم ببینیم. توضیح پست بعدی #django @Syntax_fa
1. if self._state.adding and not self.slug:
- قسمت اول چک کردن یعنی self._state.adding اگر در حال ساختن یک شی جدید در دیتابیس باشیم مساوی با True هستش همچنین اسلاگ هم باید None باشه.

2. self.slug = self.slugify(self.name)
- این خط یک slug جدید را بر اساس فیلد name با استفاده از تابع slugify تولید می‌کند.

3. using = kwargs.get("using" or router.db_for_write(type(self), instance=self))
- این خط مشخص می‌کند که داده‌ها باید در کدام پایگاه داده ذخیره شوند، با استفاده از router.db_for_write.
(درباره B router بعدا توضیح میدم)

4. kwargs["using"] = using
- این خط، پارامتر using را در kwargs قرار می‌دهد تا در ادامه به super().save منتقل شود.

5. try: ... except IntegrityError:
- این بلوک try/except یک تراکنش atomic را برای ذخیره داده‌ها ایجاد می‌کند.
- اگر خطای IntegrityError (مانند تکراری بودن slug) رخ دهد، بلوک except اجرا می‌شود.

6. slugs = set(...)
- در صورت رخ دادن `IntegrityError`، این خط تمام `slug`‌های موجود در پایگاه داده که اولشون شبیه به اسلاگ ما هستش رو بازیابی می کنه.

7. while True: ... i += 1
- این حلقه یک slug جدید تولید می‌کند تا زمانی که یک slug منحصر به فرد پیدا شود.- slug جدید با افزودن یک شماره انتهایی به slug قبلی تولید می‌شود (مانند my-slug-1, my-slug-2, و غیره).

8. return super().save(*args, **kwargs)
- بعد از یافتن یک slug منحصر به فرد، شیء با فراخوانی متد save پایه ذخیره می‌شود.

9. else: return super().save(*args, **kwargs)
- اگر شیء در حال به‌روزرسانی است (نه ایجاد)، متد save پایه بدون هیچ تغییری فراخوانی می‌شود.

این کد به این دلیل طراحی شده است تا یک slug منحصر به فرد برای هر شی ایجاد کند، حتی اگر نام‌های مشابهی در پایگاه داده وجود داشته باشد. همچنین از تراکنش‌های اتمیک برای حفظ یکپارچگی داده‌ها در طول عملیات ذخیره‌سازی استفاده می‌کند.

#django

@Syntax_fa
👍7
معرفی پکیج d_jwt_auth

پکیج d_jwt_auth برای کار با jwt در جنگو هستش.

چه قابلیت هایی داره؟
۱.سادگی. تمامی کارهارو تنها با 4 فانکشن میتونید انجام بدید.
۲. حداقل دوبرابر simple_jwt پرفورمنس بهتری داره!
۳. امنیت بیشتر بواسطه رمزنگاری کردن توکن
۴. چک کردن آی پی و دستگاهی که توکن برای اون صادر شده با آی پی آدرس و دیوایسی که ریکوئست زده.
۵. نحوه نامعتبر کردن توکن به شیوه خیلی کارآمد تر
و ...

مثال از نحوه استفاده:

اول از همه نصبش می کنیم:
pip install d_jwt_auth

تو لیست اپ ها اضافش می کنم:
INSTALLED_APPS = [
    ...
    "d_jwt_auth",
]

بعدش migrate بزنید.

کلاس Authentication رو قرار میدیم:
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'd_jwt_auth.authenticate.JWTAuthentication',
        ...
    ),
}

نحوه ساخت توکن:
from d_jwt_auth.token import generate_token 

class LoginView(APIView):
    def post(self, request):
        ...
        token = generate_token(request=request, user=user)
        return Response(data=token, status=status.HTTP_200_OK)

Github:
https://github.com/alireza-fa/django-jwt-auth

Pypi:
https://pypi.org/project/d-jwt-auth/

(برای حمایت ستاره فراموش نشه)

قبل استفاده حتما داکیومنت رو کامل بخونید

#django #jwt

@Syntax_fa
🔥8👍4
نکته:
میدونستید جنگو translation بر اساس زبان دیفالت مروگر کاربر، زبانی که باید نشون بده رو انتخاب می کنه؟

اگه زبان دیفالت مرورگرش توی لیست زبان های برناممون نبود میره سراغ دومین زبانی که تو مرورگرش ست کرده

و اگه کلا اون زبانه نبود، اون زبانی که دیفالت توی settings.py ست کردیمو نشون میده

#Note #Django

@Syntax_fa
😱11👍8
آموزش پکیج django-debug-toolbar


پکیج django-debug-toolbar یک ابزار قدرتمند برای دیباگ کردن وب‌اپلیکیشن‌های Django است. این ابزار اطلاعات مفصلی در مورد درخواست‌ها، پاسخ‌ها، قالب‌ها، پرس‌وجوهای SQL و موارد دیگر ارائه می‌دهد که می‌تواند به شما در یافتن و رفع اشکالات در کد Django شما کمک کند.

نصب django-debug-toolbar

برای نصب django-debug-toolbar، باید مراحل زیر را انجام دهید:

پکیج را با pip نصب کنید:
pip install django-debug-toolbar
پکیج را در فایل settings.py خود اضافه کنید:
INSTALLED_APPS = [
    # ...
    'debug_toolbar',
]

MIDDLEWARE = [
    # ...
    'debug_toolbar.middleware.DebugToolbarMiddleware',
]

INTERNAL_IPS = [
    # ...
    "127.0.0.1",
    # ...
]

سرور وب خود را مجدداً راه‌اندازی کنید.

استفاده از django-debug-toolbar

پس از نصب django-debug-toolbar، یک نوار ابزار در بالای صفحه نمایش شما ظاهر می شود. این نوار ابزار شامل تعدادی پنل است که اطلاعات مختلفی در مورد درخواست فعلی را نشان می دهد.

برای مشاهده اطلاعات بیشتر در مورد یک پنل، می توانید روی آن کلیک کنید. به عنوان مثال، اگر روی پنل "SQL Queries" کلیک کنید، لیستی از تمام پرس و جوهای SQL که برای پردازش درخواست اجرا شده اند را مشاهده خواهید کرد.

پکیج django-debug-toolbar همچنین شامل تعدادی ابزار مفید دیگر است، مانند:

خطایاب قالب: این ابزار به شما امکان می دهد کد قالب Django خود را گام به گام اشکال زدایی کنید.
پروفیلر: این ابزار به شما امکان می دهد عملکرد کد Django خود را پروفایل کنید.
کنسول: این ابزار به شما امکان می دهد کد Python را در محیط تعاملی اجرا کنید.

نکته:
تنطیماتشو جوری انجام بدید که تو حالت Debug == false میدلور و کلا پکیجه کانفیگ نشه چون نیاز ندارید بهش

[@Awmirsn]

#django

@Syntax_fa
👍6🔥1
سوال مصاحبه جنگویی:

سطح: سخت

تو جنگو میخوایم هر درخواست HTTP بصورت خودکار توی یک تراکنس دیتابیس قرار بگیره. یعنی اگه هرکدوم از عملیات های دیتابیس در طول پردازش یک درخواست HTTP با خطا مواجه بشه، تموم تغییراتی که توی دیتابیس اعمال شده rollback شه.
بنظرت چیکار میتونیم بکنیم؟

قبل اینکه جوابو ببینی یکم فکر کن یا سرچ کن 😒:
و اما جواب:

میتونیم با اضافه کردن این خط تو settings.py این قابلیت رو اضافه کنیم:
DATABASES["default"]["ATOMIC_REQUESTS"] = True

و اما یه جواب خفن و درست تر توسط [abbasi_ai]:
Atomic request
جواب اصلی سوال نیست، بنظرم چیزی جا افتاده

با توجه به صورت سوال؛ فکر می‌کنم یک session manager هم نیاز هست.
و اگر توی درخواست‌های بعدی یوزر هم چیزی به خطا بخوره تا درخواست اصلی همه چیز باید
Rollback
بخوره


اگه فقط بخوایم تو ویو های خاصی atomic requets رو داشته باشیم چیکار کنیم؟
و جواب این سوال:
میتونیم از دکوریتور atomic استفاده کنیم:
from django.db import transaction
from django.views import View

class MyView(View):

@transaction.atomic
def get(self, request, *args, **kwargs):
...


#interview_question #django

@Syntax_fa
Please open Telegram to view this post
VIEW IN TELEGRAM
👀8👍6👌32
Foodanywhere

پروژه Foodanywhere یک پروژه food delivery جنگویی هستش.

- از Postgis برای ثبت اطلاعات جغرافیایی استفاده میکنه.
- این پروژه برای مانیتورینگ از prometheus استفاده میکنه.
- برای مدیریت لاگ ها از loki استفاده میکنه.
- برای دیپلویمنت از kubernetes استفاده میشه و برای ci/cd از github actions.
- اکثر بخش ها هم تست شده و تمامی تستا با pytest نوشته شدن

لطفاً نظراتتون رو جهت بهتر کردن پروژه، حتما در میون بذارید🙏

سورس کد پروژه:
(برای حمایت از محمد، استار فراموش نشه🍸)
https://github.com/mohamad-liyaghi/FoodAnywhere

#django #project

@Syntax_fa
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13👏21❤‍🔥1🎉1
از اونجا که بچه های گروه زیادی از جنگو خوششون میاد، اینم چند تا نکته جنگویی(قسمت اول):

۱. چطور از ایمپورت circular تو مدل هامون جلوگیری کنیم؟
برای جلوگیری از این مشکل، جنگو برامون یه راه حل گذاشته. فرض کنید به یه مدل دیگه فارن کی زدید. بجای اینکه مستقیم ایمپورتش کنید. میایم داخل استرینگ بهش میگیم که به کدوم مدل فارن کی بخوره.
مثال:
app1/models.py
class ModelOne(models.Model):
...

app2/models.py
class ModelTwo(models.Model):
model_one = models.ForeignKey("app1.ModelOne")


2. مدل های داخل یک اپ رو بشکنید!
پیشنهاد اینه مدل های یک اپ خیلی زیاد نشه. اما اگه دلایل مشخصی دارید، بهتره مدل هارو داخل یک پکیج قرار بدید تا زیادی شلوغ نشه.
برای اینکار داخل اپ یک پکیج به اسم models میسازیم و داخل فایل های مختلف مدل هامون رو قرار میدیم. در نهایت داخل init ایمپورتشون میکنیم:
#### blog_app/models/__init__.py
from .comment import Comment
from .post import Post
#### blog_app/models/comment.py
class Comment(models.Model):
# comment fields
#### blog_app/models/post.py


3. کوئری هامون چقدر بهینه هستن؟
خب بیاید با نوشتن یدونه دکوریتور بررسی کنیم:
from django.db import connection
from django.db import reset_queries
def database_debug(func):
def inner_func(*args, **kwargs):
reset_queries()
results = func(*args, **kwargs)
query_info = connection.queries
print(f'function_name: {func.__name__}')
print(f'query_count: {len(query_info)}')
queries = [f'{ query["sql"]}\n' for query in query_info]
print(f'queries: \n{"".join(queries)}')
return results
return inner_func

خروجی دکوریتور در دو حالت مختلف:
@database_debug
def regular_query():
blogs = models.Blog.objects.all()
return [blog.author.name for blog in blogs]

## OUTPUT
function_name: regular_query
query_count: 4
queries:
SELECT "blog_blog"."id", "blog_blog"."title",
"blog_blog"."content", "blog_blog"."author_id",
"blog_blog"."created_at", "blog_blog"."updated_at" FROM
"blog_blog"
SELECT "author_author"."id", "author_author"."name",
"author_author"."email", "author_author"."bio" FROM
"author_author" WHERE "author_author"."id" = 1 LIMIT 21
SELECT "author_author"."id", "author_author"."name",
"author_author"."email", "author_author"."bio" FROM
"author_author" WHERE "author_author"."id" = 2 LIMIT 21
SELECT "author_author"."id", "author_author"."name",
"author_author"."email", "author_author"."bio" FROM
"author_author" WHERE "author_author"."id" = 2 LIMIT 21

میبینیم که پدر دیتابیسو درآورده. ولی با استفاده از select_related تعداد کوئری ها از 4 تا به یکی میرسه.
پس همیشه از روش هایی استفاده کنید برای اینکه کوئری هایی که میزنید رو بررسی کنید.

#django

@Syntax_fa
🔥6👍3
نکات مهم اجرای جنگو با Gunicorn

توضیح درباره Gunicorn
نمیخوام توضیحات زیادی بدم حوصلتون سر بره پس همون سه خط معرفی که تو وب سایت gunicorn نوشته رو براتون یکم شفافش میکنم:
اسمش مخفف green unicorn هستش
جی یونیکورن یک http سرور هستش که از استاندارد WSGI(Web server gateway interface) برای اجرای برنامه های وب پایتون استفاده میکنه.
استاندارد WSGI برای این بوجود اومد تا هر فریم ورک وب پایتونی روش خودشو واسه ارتباط پیاده نکنه و همه از یه استاندارد مشخص استفاده کنن.

در ادامه میگه gunicorn برای unix هستش و برای سیستم عامل هایی مثل مک و لینوکس طراحی شده.

بعدش میگه که جی یونیکورن از مدل pre-fork worker استفاده میکنه حالا این به چه معنیه؟
جی یونیکورن کاری که میکنه اینه قبل اینکه شروع به پردازش درخواست ها کنه، میاد و به اندازه ای که تنظیم کردید worker ایجاد میکنه که هر worker درخواست هارو بطور مستقل پردازش میکنه.

بعدشم میگه با فریم ورک های وب مختلفی سازگاره که اینم میتونیم دلیلش رو این بدونیم داره برای ارتباط از استاندارد WSGI استفاده میکنه.

قسمت آخرشم میگه light resource هستش و منابع کمی مصرف میکنه همچنین برای ترافیک بالا عملکرد خوبی داره.

خب جی یونیکورن این ادعا هارو میکنه اما بیاید با چند تا مثال شرایطی رو بررسی کنیم که شما به غلط دارید از جی یونیکورن استفاده میکنید:

مثال اول
gunicorn --chdir config config.wsgi:application -b 0.0.0.0:8000

اگه با این دستور جی یونیکورن رو اجرا کنید باید به این نکته دقت کنید بصورت پیشفرض براتون فقط یدونه worker میسازه که این اصلا خوب نیست. خود جی یونیکورن پیشنهاد میده حتی اگه یدونه core دارید 4 تا ورکر بسازید و یه فرمولی هم داده که میگه«تعداد هسته های سی پی یو رو ضربدر 2 به علاوه یک کنید»
همچنین به شما اطمینان داده همین تعداد ورکر هزاران ریکوئست رو میتونن پاسخ بدن پس تعداد ورکر هارو الکی زیادش نکنید.
البته به کیس شما هم بستگی داره.
دستور بهتر برای اجرا اینه تعداد ورکر هارو مشخص کنیم:
gunicorn --workers 5 --chdir config config.wsgi:application -b 0.0.0.0:8000


مثال دوم:
فرض کنید کاربر ها تو اپلیکیشن شما فایل هایی رو آپلود میکنن. شما پنج تا ورکر دارید.
وقتی پنج تا کاربر همزمان فایل آپلود کنن بنظرتون چه اتفاقی میوفته؟
پنج تا ورکر شما گیر یه io افتادن و مشغولن و درخواست های دیگه کاربرا انجام نمیشه. خب این وضعیتی نیست که باب میلیتون باشه!
برای حل این مشکل کافیه از gevent توی جی یونیکرون استفاده گنید؛
gunicorn --workers 1 -k gevent --chdir config config.wsgi:application -b 0.0.0.0:8000

با فلگ -k نوع کلاس ورکر رو مشخص میکنیم. حالا چرا از gevent استفاده میکنیم؟
کتابخونه gevent برای مدریریت همزمانی طراحی شده. میشه گفت یک نمونه lightweight thread هستش که این مدل موقع عملیات های IO سوئیچینگ انجام میده و در این صورت اگه به io خوردید براتون هندل میکنه.

کلی نکات دیگه هم قطعا هست که تو یه پست جا نمیشه
امیدوارم براتون مفید باشه

#python #django #gunicorn #gevent

@Syntax_fa
👍154🔥1🙏1
یه شخصی تو لینکدین این پست رو گذاشته که قراره با هم بررسیش کنیم:
چرا نباید از Signals ها در جنگو استفاده کنیم؟

اگر تجربه کار با Django را داشته باشید، احتمالاً با Signals آشنا هستید. سیگنال‌ها به شما این امکان را می‌دهند که بعد از رخ دادن یک رویداد خاص، مانند ذخیره یا حذف یک شی، کدی را اجرا کنید. اما آیا همیشه بهترین انتخاب هستند؟ بیایید با هم بررسی کنیم.

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

چرا نباید از سیگنال‌ها استفاده کنیم؟
با وجود کاربردهای سیگنال‌ها، استفاده از آن‌ها معایب خودشون رو هم دارن. یکی از مشکلات اساسی سیگنال‌ها این است که پیچیدگی و عدم پیش‌بینی‌پذیری را افزایش میدن. کدهایی که به‌وسیله سیگنال اجرا می‌شوند، ممکن است در جریان اصلی کد ما نباشند و ما به‌راحتی متوجه نشیم که چه زمانی و چرا آن‌ها فراخوانی می‌شوند. این موضوع نه تنها کار دیباگ کردن رو سخت میکنه، بلکه ممکنه رفتار ناخواسته‌ای هم که ازش انتظار نداریم رو هم داشته باشه.

یکی دیگه از مشکل های سیگنال‌ها اینه که همگام (Synchronous) اجرا میشن. برخلاف تصوری که ممکنه داشته باشیم، سیگنال‌ها به‌صورت غیرهمگام اجرا نمیشن و هیچ پروسه پس‌زمینه‌ای برای آن‌ها وجود ندارد. این موضوع باعث میشه که اگر سیگنال با خطا مواجه بشن، این خطا مستقیما در جریان اصلی کد شما بروز کند و حتی ممکن است رفتارهای ناخواسته به وجود بیاد.

به‌عنوان مثال، فرض کنید شما در حال توسعه کدی هستید که تعداد فروش یک نوع تاپینگ پیتزا را هنگام ایجاد پیتزای جدید به‌روزرسانی می‌کند. اگر از سیگنال استفاده کنید، ممکن است در مواردی که از متدهای bulk مانند bulk_create یا .update() استفاده می‌کنید، این سیگنال فراخوانی نشود و این به داده‌های ناهماهنگ منجر شود.

همچنین سیگنال‌ها ممکنه که نگهداری کد را سخت‌تر کنند. توسعه‌دهندگانی که کد شما را بعدا نگهداری می‌کنند، ممکنه زمان زیادی را صرف پیدا کردن محل تعریف و اتصال سیگنال‌ها کنند، به‌خصوص اگر سیگنال‌ها در فایل‌های مختلف پخش شده باشند.

چه چیزی می‌تواند جایگزین باشد؟
به جای استفاده از سیگنال‌ها، یکی از راهکارهای بهتر استفاده از متدهای مدل مثل save() هست. زمانی که بیزینس لاجیک خود را درون متد save() مدل قرار می‌دهید، همه چیز شفاف‌تر و قابل پیش‌بینی‌تر خواهد بود. به این ترتیب، کد جلو چشم شما قرار دارد و نیازی نیست نگران اجرا شدن یا نشدن سیگنال‌ها باشید. این کار باعث می‌شود کد تمیزتر و خواناتر باشد و همچنین به‌راحتی قابل تست و نگهداری شود.

برای مثال، می‌توانید یک متد در مدل خود تعریف کنید که منطق به‌روزرسانی را مدیریت کند و سپس این متد را در متد save() فراخوانی کنید. این روش نه تنها ساختار کد شما را ساده‌تر می‌کند، بلکه به توسعه‌دهندگان آینده هم کمک می‌کند تا به‌راحتی جریان کد را دنبال کنند.
————————————-

نظر من راجب این پست:
استفاده از سیگنال ها تو برخی شرایط بنظرم خیلیم مفید هستش.

برای مثال میتونیم با استفاده از سیگنال ها، سرویس ها و اجزای مختلف رو از هم decouple تر کنیم.
فرض کنید موقعی که یک یوزر جدید ساخته میشه، چند تا سرویس دیگه هم یه سری عملیات انجام میدن. مثلا نوتیف خوش آمد گویی ارسال میکنیم.
ساختار پروژمونم یکپارچه هستش.

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

اینطوری سرویس ها نسبت به هم decouple تر شدن و دیگه یوزر کاری نداره زمانی که یوزری جدیدی ساخته شد، بقیه سرویس ها چیکار کنن، فقط سیگنالو ارسال میکنه هر کی علاقه مند بود دریافتش میکنه.

الگوی observer:
سیگنال ها درواقع پیاده سازی الگوی observer هستن که برای ارتباط بین اجزای مخنلف سیستم خیلی مفیده.

فقط چند تا نکته باقی میمونه اینکه از سیگنال ها هوشمندانه استفاده کنیم، تو استفاده ازشون زیاده روی نکنیم و حتما داکیومنت کنیم تا باعث سردرگمی نشه

#django #Signals

@Syntax_fa
👍5🔥3
ساختار پروژه های جنگویی تیم سینتکس‌فا

در پروژه‌های نرم‌افزاری، به ویژه پروژه‌های بزرگ، ساختار مناسب کد نقش کلیدی داره. ساختار پروژه تأثیر مستقیمی به خوانایی، قابلیت نگهداری، و مقیاس‌پذیری کد داره.

در جنگو، یک ساختار مناسب تضمین میکنه که تیم توسعه‌دهنده به راحتی میتونن کد رو گسترش بدن اشکالات رو رفع کنن و ویژگی‌های جدیدی به پروژه اضافه کنن. بدون معماری منسجم و اصولی، مدیریت کد پیچیده و زمان‌بر میشه.

تیم سینتکس در حال حاضر از ساختاری که توی این ریپو بصورت پابلیک قرار دادیم استفاده میکنه.

امیدوارم براتون مفید باشه 🙏

اگه اشکالی توی ساختار میبینید و جای بهبود داره حتما پول ریکوئست بزنید یا بهمون اطلاع بدید.

همچنین به مرور زمان داکیومنت رو هم اضافه میکنیم و سعی میکنیم همیشه آپدیت باشه.

برای حمایت از ما ستاره فراموش نشه 🍸

https://github.com/syntaxfa/django-structure

#django #structure

@Syntax_fa
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥14👍93👻2👎1😱1
📢 معرفی CONN_MAX_AGE در Django

متغیر CONN_MAX_AGE یکی از تنظیمات مهم Django است که برای مدیریت اتصالات پایدار (Persistent Connections) به پایگاه داده استفاده می‌شود. این تنظیم مشخص می‌کند که یک اتصال به پایگاه داده برای چه مدت زمان زنده بماند و پس از آن بسته شود.

🔍 CONN_MAX_AGE چیست و چگونه عمل می‌کند؟

- مقدار CONN_MAX_AGE نشان‌دهنده مدت زمان (بر حسب ثانیه) است که یک اتصال به پایگاه داده در حالت باز باقی می‌ماند.
- اگر مقدار آن روی ۰ تنظیم شود، اتصال به پایگاه داده پس از هر درخواست بسته می‌شود (رفتار پیش‌فرض).
- اگر مقدار CONN_MAX_AGE روی `None` تنظیم شود، اتصال به پایگاه داده هرگز بسته نمی‌شود و دائماً زنده می‌ماند (تا زمانی که فرآیند Worker یا برنامه بسته شود).

⚙️ مقدار پیش‌فرض CONN_MAX_AGE

به صورت پیش‌فرض، مقدار CONN_MAX_AGE برابر با ۰ است. یعنی Django پس از پایان هر درخواست، اتصال به پایگاه داده را می‌بندد و برای درخواست جدید، اتصال دیگری باز می‌کند. این رفتار برای پروژه‌های کوچک یا آزمایشی مناسب است ولی در محیط تولید (Production) ممکن است باعث کاهش عملکرد شود.

✏️ نحوه تنظیم CONN_MAX_AGE

مقدار CONN_MAX_AGE در تنظیمات پایگاه داده تعریف می‌شود. مثال زیر نحوه استفاده از آن را نشان می‌دهد:

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'your_database',
'USER': 'your_user',
'PASSWORD': 'your_password',
'HOST': 'your_host',
'PORT': 'your_port',
'CONN_MAX_AGE': 600, # 600 seconds
}
}



چند سناریو برای تنظیم CONN_MAX_AGE

1. پروژه کوچک یا محیط توسعه
- سناریو: اگر پروژه شما تعداد کمی از درخواست‌ها را مدیریت می‌کند یا در حال توسعه هستید.
- مقدار پیشنهادی:

     'CONN_MAX_AGE': 0

- توضیح: اتصال پس از هر درخواست بسته می‌شود. این کار به شما کمک می‌کند که رفتار واقعی برنامه را در محیط توسعه مشاهده کنید.

2. پروژه با بار متوسط
- سناریو: اگر برنامه شما درخواست‌های متوسطی (نه کم، نه زیاد) دارد و پایگاه داده شما برای تعداد اتصالات زیاد محدودیت خاصی ندارد.
- مقدار پیشنهادی:

     'CONN_MAX_AGE': 300  # 5 minutes

- توضیح: این تنظیم باعث می‌شود که اتصالات برای چندین درخواست استفاده شوند و هزینه باز و بسته کردن اتصال کاهش یابد.

3. پروژه با بار زیاد (High Traffic)
- سناریو: اگر برنامه شما تعداد زیادی درخواست دارد و می‌خواهید عملکرد را بهینه کنید.
- مقدار پیشنهادی:

     'CONN_MAX_AGE': 600  # 10 minutes

- توضیح: این مقدار کمک می‌کند که هزینه باز و بسته کردن مکرر اتصالات کاهش یابد، اما همچنان اتصالات پس از مدتی بسته می‌شوند تا از مشکلات احتمالی جلوگیری شود.

4. پروژه‌های با درخواست‌های خیلی کم
- سناریو: اگر برنامه شما به ندرت به پایگاه داده متصل می‌شود (مثلاً به دلیل استفاده از کش یا تعامل کم با پایگاه داده).
- مقدار پیشنهادی:

     'CONN_MAX_AGE': 0  # each http request

- توضیح: نگه‌داشتن اتصال در این موارد منطقی نیست و بهتر است اتصال پس از هر درخواست بسته شود.

5. استفاده از Connection Pooling خارجی
- سناریو: اگر از ابزارهای خارجی مدیریت اتصال مانند pgbouncer (برای PostgreSQL) یا ProxySQL (برای MySQL) استفاده می‌کنید.
- مقدار پیشنهادی:

     'CONN_MAX_AGE': None

- توضیح: در این حالت، مدیریت اتصالات به ابزارهای خارجی سپرده شده است و Django نیازی به بستن اتصالات ندارد.

⚠️ نکات مهم:

1. مراقب تعداد اتصالات باشید:
اگر مقدار CONN_MAX_AGE را روی مقدار زیاد یا None تنظیم کنید، مطمئن شوید که سرور پایگاه داده شما می‌تواند تعداد زیادی اتصال همزمان را مدیریت کند. در غیر این صورت ممکن است با خطای "too many connections" مواجه شوید.

2. محیط production:
در محیط تولید، معمولاً مقدار CONN_MAX_AGE روی چند دقیقه (مثلاً ۵ تا ۱۰ دقیقه) تنظیم می‌شود تا عملکرد بهینه باشد و اتصالات مکرر ایجاد نشوند.

3. ابزارهای خارجی مدیریت اتصال:
اگر از Connection Pooling خارجی استفاده می‌کنید، مقدار CONN_MAX_AGE را روی None تنظیم کنید تا Django اتصال را مدیریت نکند.

conn_max_age

#database #django

@Syntax_fa
19👍8🔥1
امروز یه باگ بامزه تو پروژه Django خورد تو صورتم که گفتم باهاتون درمیون بذارم، شاید یه روزی به دادتون برسه!

اگه بعد از ساختن یه آبجکت توی ویو (مثلاً با متد create) بلافاصله آی‌دی اون رو بدی به یه تسک Celery، ممکنه توی محیط پروداکشن با ارور DoesNotExist مواجه بشی — در حالی که لوکال همه چیز درست کار می‌کنه!

چرا این اتفاق می‌افته؟

چون وقتی تنظیماتی مثل ATOMIC_REQUESTS = True فعال باشه، Django تا زمانی که ریکوئست کامل نشه، اطلاعات رو به دیتابیس commit نمی‌کنه.
از اون طرف Celery تسک رو بلافاصله بعد از پاسخ 201 اجرا می‌کنه؛ یعنی قبل از اینکه دیتابیس واقعاً اطلاعات رو ذخیره کرده باشه.

راه‌حل درست و اصولی:
به جای اینکه تسک رو همون لحظه اجرا کنیم، باید صبر کنیم تا commit تموم بشه.
و Django خودش این ابزار رو بهمون داده:

transaction.on_commit(lambda: my_task.delay(obj_id))

این خط یعنی: «بعد از اینکه commit شد، حالا برو سراغ تسک.»

یه نکته ساده ولی حیاتی که می‌تونه جلوی کلی باگ دردسرساز رو بگیره — مخصوصاً وقتی کد رو از dev می‌بریم روی production!

Source

#django

@Syntax_fa
👍39🔥1👌1
Syntax | سینتکس
ساختار پروژه های جنگویی تیم سینتکس‌فا در پروژه‌های نرم‌افزاری، به ویژه پروژه‌های بزرگ، ساختار مناسب کد نقش کلیدی داره. ساختار پروژه تأثیر مستقیمی به خوانایی، قابلیت نگهداری، و مقیاس‌پذیری کد داره. در جنگو، یک ساختار مناسب تضمین میکنه که تیم توسعه‌دهنده…
آپدیت شد:

احراز هویت JWT
مدیریت خطای پیشرفته
داکرایز
پردازش غیرهم‌زمان با استفاده از celery و تسک های زمانبندی با استفاده از celery beat
مستندسازی API با استفاده از drf-spectacular
هوک‌های pre-commit از قبل تنظیم شدن؛ شامل pylint برای بررسی کیفیت کد و gitlint برای استاندارد کردن پیام‌های کامیت.
با GitHub Actions یه CI ساده راه افتاده که روی Pull Requestها تست‌ها و Lint‌ها رو اجرا می‌کنه

#django

@Syntax_fa
👍61