رابطه‌ی OneToOne


در مدل‌های رابطه‌ای، رابطه یک به یک (One-to-One) زمانی استفاده می‌شود که هر رکورد از جدول A دقیقا با یک رکورد از جدول B مرتبط باشد و برعکس. این نوع رابطه در جنگو با استفاده از فیلد OneToOneField پیاده‌سازی می‌شود.

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

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

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE) # OneToOne Field

✺✳ دسترسی‌های رایج در رابطه یک به یک ✳✺

 

⮜ دسترسی به پروفایل از طریق کاربر


user = User.objects.get(username="admin")
profile = user.profile
⚠️ اگر پروفایل برای کاربر وجود نداشته باشد، این خط با خطای DoesNotExist مواجه می‌شود. برای جلوگیری، می‌توان از hasattr یا get_or_create استفاده نمود.
 

⮜ دسترسی به کاربر از طریق پروفایل


profile = Profile.objects.get(id=1)
user = profile.user

⚠️ این دسترسی همیشه ممکن است (چون هر پروفایل حتماً به یک کاربر مرتبط است).

 

✺✳ فیلتر کردن بر اساس روابط (Lookups across relationships) ✳✺ 

جنگو اجازه می‌دهد تا با استفاده از lookupهای معکوس (__)، بر اساس فیلدهای مدل‌های مرتبط جستجو کنیم.

⚠️ اگر related_name را در OneToOneField تغییر داده باشیم (مثلا به user_profile)، باید از همان نام در lookup استفاده کنیم

users = User.objects.filter(profile__birth__lte="2000-01-01")

— پیدا کردن کاربرانی که قبل از سال ۲۰۰۰ متولد شده‌اند.

profiles = Profile.objects.filter(user__date_joined__gte="2023-01-01")

— دریافت تمام پروفایل‌هایی که کاربری‌شان بعد از تاریخ خاصی ایجاد شده‌اند.