سرمایه گذاری متفاوت در سال نو 🍎🌱 ۳۵٪ تخفیف نوروزی ➕ حضور رایگان در مسترمایند نخبگان صنعت نرم‌افزار 💻✅
۰ ثانیه
۰ دقیقه
۰ ساعت
۳ Mohamad Mahdi Yazdani
مشکل برای نشون دادن اگهی ها
جامعه پایتون (وب) ایجاد شده در ۱۴ مرداد ۱۴۰۰

سلام خسته نباشید.
من دارم یه پروژه مثل دیوار میزنم توی قسمت ارتقا اگهی ها(فوری ، نردبان) یه مشکلی دارم من دوتا جدول دارم یکی Promotion که این جدول برای اضافه کردن انواع ارتقا‌ها در نظر گرفته شده (فوری ، نردبان ، نردبان و فوری ، تمدید)
و یک جدول AdvertisementPromotion دارم که کاربر بعد از پرداخت اون اگهی با اون نوع از ارتقا توی این جدول ذخیره میشن که عکس مدلاشو گذاشتم حالا من یه کویری دارم :
 

Advertisement.objects.filter(status=Advertisement.ACCEPTED).annotate(
            time=Case(
                When(promotions__promotion=Promotion.LADDER, then='promotions__created_time'), default='created_time'
            )
        ).order_by('-time')

 

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

اما مشکل اینه که اگه من بیام دستی به طور مثال برای یک اگهی هم نردبانش کنم هم فوری کنم توی جدول AdvertisementPromotion  دوتا فیلد ساخته میشه که مشکلی نیس اما با این کویری که من زدم وقتی جوینشون میکنه مثلا اگهی X یه بار تو خود Advertisement  دوبار تو  AdvertisementPromotion و وقتی جوین میخورن سه تا اگهی رو نشون میده من چیزی که کویری برمیگردونه و خود کویری رو عکسشو میزارم

میخوام ببینم مشکل از دیزاین دیتابیسه و دیزاین و باید عوض کنم

 یا کویری دیگه ای باید بزنم.

امیدوارم کامل و واضح شرح داده باشم خسته نباشید مرسی.

 

سلاااااااااااااااااااام محمد جان

خدا قوت

مساله از کوئری عه

توی کوئری ات باید از distinct یا distinct on استفاده کنی. و حواست باشه که هر وقت از distinct on استفاده میکنی خیلی مهمه که از order by هم درست استفاده کنی، همون طور که تو داکیومنت PostgreSQL قسمت DISTINCT Clause گفته شده:

SELECT DISTINCT ON ( expression [, ...] ) keeps only the first row of each set of rows where the given expressions evaluate to equal. The DISTINCT ON expressions are interpreted using the same rules as for ORDER BY (see above). Note that the "first row" of each set is unpredictable unless ORDER BY is used to ensure that the desired row appears first.

ترجمه:

دستور SELECT DISTINCT ON ( expression [, ...] ) فقط رکورد اول هر مجموعه از رکوردهایی که با عبارت (که معمولا یک یا چند ستون هستن) داخل پرانتز نتیجه شون یکسان بشه رو نگه میداره. عبارت‌های DISTINCT ON با استفاده از همان قوانین ORDER BY تفسیر میشن. حواستون باشه که «اولین رکورد» از هر مجموعه قابل پیش بینی نخواهد بود مگر اینکه از ORDER BY استفاده شده باشه برای اطمینان از اینکه رکوردهای خواسته شدن اول بیان.

 

ساده‌تر بخواهیم بگیم یعنی، دستور DISTINCT ON رکوردهایی رو حذف میکنه که مقدار ستون، ستون‌ها یا عبارتی که داخل پرانتز DISTINCT ON شون هست یکسان باشه. و حتما از دستور ORDER BY همراه DISTINCT ON استفاده کنید. چون دستور DISTINCT ON رکوردهایی بالایی رو نگه میداره.

 

سوال:

فرق DISTINCT و DISTINCT ON چیه؟ تو این مثال از کدومش باید استفاده بشه؟

یه کوئری و دستور ORM برای این کاری که گفتی بنویس و بفرس تا بیشتر در موردش صحبت کنیم.

 

محمد جان در خدمتم :)

 

منابع:

https://www.postgresqltutorial.com/postgresql-select-distinct/

https://www.postgresql.org/docs/9.5/sql-select.html

محمدعلی رضا ۱۴ مرداد ۱۴۰۰، ۱۳:۳۶

سلااااااام دوباره و خسته نباشیددد

 

من چندتا کویری تست کردم و سرچ زدم اما خب الان مشکل اینه که برای مرتب سازی من از time باید استفاده کنم اما برای distinct  از advertisement_id و خوب چند مدل تست کردم اما خروجی که میخواستم و نگرفتم

 

 

Advertisement.objects.filter(status=Advertisement.ACCEPTED).annotate(
            time=Case(
                When(promotions__promotion=Promotion.LADDER, then='promotions__created_time'), default='created_time'
            )).order_by('-time', 'promotions__advertisement').distince('promotions__advertisement')

و چند مدل دیگه اما فقط اینجوری نتیجه گرفتم که کدم به نظرم خیلی درست نیس و وقتی حجم رکوردا زیاد باشه خب خیلی مشکل ایجاد میکنه

 

advertisement=Advertisement.objects.filter(status=Advertisement.ACCEPTED).distinct('promotions__advertisement').annotate(
    time=Case(
        When(promotions__promotion=Promotion.LADDER, then='promotions__created_time'), default='created_time'
    ))
advertisement = sorted(advertisement, key=operator.attrgetter('time'), reverse=True)

 

راه دیگه ای پیدا نکردم

Mohamad Mahdi Yazdani ۱۸ مرداد ۱۴۰۰، ۰۹:۴۰

سلااااااااااااااااااااااام محمد جان

خداقوت

ایول به تلاشت

یه راه حل دیگه هم من دارم یه ستون به نام ad_datetime اضافه کنی که بصورت پیش فرض مقدار datetime.now رو میگیره و وقتی آگهی ای ارتقا نردبان پیدا میکنه. مقدار این فیلدش رو با datetime.now آپدیت کنی. و طبق این ستون order by کنی.

محمدعلی رضا ۲۱ مرداد ۱۴۰۰، ۱۱:۵۵