رابطهی 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")
— دریافت تمام پروفایلهایی که کاربریشان بعد از تاریخ خاصی ایجاد شدهاند.