having two lookup field in viewset in DRF

Hi everyone
I have three models as fallow

customuser

class CustomUser(AbstractUser):

    class Trust_Level_choices(models.TextChoices):
        basic_user = 'basic_user', 'عضو ابتدایی'
        member = 'member', 'عضو'
        moderator = 'moderator', 'ناظر'
        admin = 'admin', 'راهبر'

    class Personal_Message_Choices(models.TextChoices):
        always = 'always', 'همیشه'
        when_away = 'when_away', 'زمانی که نیستم'
        never = 'never', 'هرگز'
    
    class Previous_Replies_Choices(models.TextChoices):
        always = 'always', 'همیشه'
        unless_previously_send = 'unless_previously_send', 'مگر اینکه قبلا ارسال شده باشد'
        never = 'never', 'هرگز'
    
    class Mailing_list_mode_Choices(models.TextChoices):
        send_email_for_new_post = 'send_email_for_new_post', 'ارسال ایمیل برای هر پست جدید'
        send_email_for_new_post_except_mine = 'send_email_for_new_post_except_mine', 'ارسال ایمیل برای هر پست جدید به جز پست های خودم'

    class Topic_As_New_Choices(models.TextChoices):
        i_have_not_viewed_them_yet = 'I_have_not_viewed_them_yet', 'آنهایی که هنوز ندیده ام'
        created_in_the_last_day = 'Created_in_the_last_day', 'در روز گذشته ایجاد شده باشد'
        created_in_the_last_2_days = 'Created_in_the_last_2_days', 'در دو روز گذشته ایجاد شده باشد'
        created_in_the_last_week = 'Created_in_the_last_week', 'در هفته گذشته ایجاد شده باشد'
        created_in_the_last_2_weeks = 'Created_in_the_last_2_weeks', 'در دو هفته گذشنه ایجاد شده باشد'
        created_since_i_was_here_last = 'Created_since_i_was_here_last', 'پس از آخرین باری که اینجا بودم ایجاد شده باشد'
    
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    email = models.EmailField(max_length=256 , unique=True)
    # username = None
    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['USERNAME_FIELD']
    session_token = models.CharField(max_length=10, default=0)
    date_joined = models.DateTimeField(verbose_name='تاریخ عضویت',auto_now_add=True, editable=True)
    trust_level = models.CharField(choices=Trust_Level_choices, verbose_name='سطح اعتماد', max_length=20)
    profile_picture = models.ImageField(verbose_name='تصویر پروفایل')
    send_email_for_p_m = models.CharField(choices=Personal_Message_Choices, 
                                          verbose_name='ارسال ایمیل برای پیام های شخصی', 
                                          max_length=20)
    send_email_when_q_r_m_na_in_w = models.CharField(choices=Personal_Message_Choices,
        verbose_name='ارسال ایمیل زمانی که کاربر منع شده، پاسخ داده شده، یادآوری شده، فعالیت جدید انجام داده، عنوان یا موضوعی را زیر نظر دارد',
        max_length=20)
    previous_reply_b_of_email = models.CharField(choices=Previous_Replies_Choices, verbose_name='نمایش پاسخ های قبلی زیر ایمیل',
                                                 max_length=30)
    excerp_of_replies_in_email = models.BooleanField(null=True, blank=True, verbose_name='ارسال خلاصه پاسخ ها در ایمیل')
    send_email_for_policy_review = models.CharField(choices=Personal_Message_Choices, 
                                                    verbose_name='ارسال ایمیل زمانی که سیاست های سایت بازبینی شده است',
                                                    max_length=20)
    send_email_summary_for_t_r_status = models.BooleanField(null=True, blank=True, verbose_name='ارسال خلاصه وضعیت موضوع و پاسخ ها در ایمیل')
    mailing_list_mode_status = models.BooleanField(null=True, blank=True, verbose_name='وضعیت حالت فهرست ارسال ایمیل')
    mailing_list_mode = models.CharField(choices=Mailing_list_mode_Choices,verbose_name='حالت فهرست ارسال ایمیل', max_length=50)
    nofity_when_liked = models.BooleanField(null=True, blank=True, verbose_name='ارسال یادآور زمانی که پیام های کاربر پسندیده شده اند')
    live_nofification = models.BooleanField(null=True, blank=True, verbose_name='آگاهی های زنده')
    notification_schedile_status = models.BooleanField(null=True, blank=True, verbose_name='وضعیت زمان بندی آگاهی ها')
    topic_as_new = models.CharField(choices=Topic_As_New_Choices, verbose_name='چگونگی برخورد با موضوعات جدید',
                                    max_length=50)
    auto_track_user_topics = models.BooleanField(null=True, blank=True, verbose_name='ردگیری خودکار موضوعات کاربر')
    closed_topic_as_unread = models.BooleanField(null=True, blank=True, 
                                                 verbose_name='موضوعات بسته شده به عنوان خوانده نشده در نظر گرفته شود')

userprofle

class UserProfile(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    user = models.OneToOneField(CustomUser, on_delete=models.CASCADE, verbose_name='شناسه کاربر')
    about_me = models.TextField(verbose_name='درباره من', max_length=200, null=True, blank=True)
    timezone = models.ForeignKey(Timezone, on_delete=models.CASCADE, verbose_name='منطقه زمانی', null=True, blank=True)
    location = models.CharField(verbose_name='مکان', max_length=20, null=True, blank=True)
    website = models.CharField(verbose_name='وب سایت', max_length=100, null=True, blank=True)
    profile_header = models.ImageField(verbose_name='تصویر سرآیند پروفایل', null=True, blank=True)
    usercard_background = models.ImageField(verbose_name='تصویر پس زمینه کارت کاربر', null=True, blank=True)
    month_of_birth = models.SmallIntegerField(verbose_name='ماه تولد', null=True, blank=True)
    day_of_birth = models.SmallIntegerField(verbose_name='روز تولد', null=True, blank=True)    

and useremails

class UserEmails(models.Model):    
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) 
    profile = models.ForeignKey(UserProfile, on_delete=models.CASCADE, verbose_name='شناسه پروفایل کاربر',default=0)  
    email = models.EmailField(verbose_name='ایمیل')
    is_primary = models.BooleanField(null=True, blank=True, verbose_name='ایمیل اصلی')
    email_verified = models.BooleanField(null=True, blank=True, verbose_name='تاییدیه ایمیل')

customeuser and userprofile have a one-to-one relationship
what i want to do is to get user emails based on his/her user_id and profile id
i search for solution and find out that i could use two lookup fields in DjangoRestFramework
and i implement it as bellow

serializers.py

class CustomUserSerializer(serializers.HyperlinkedModelSerializer):      
    class Meta:
        model = CustomUser                
        fields = ['id', 'email','username', 'date_joined', 'trust_level', 'profile_picture']  

class UserProfileSerializer(serializers.HyperlinkedModelSerializer):
    user = serializers.PrimaryKeyRelatedField(queryset=CustomUser.objects.all())
    
    class Meta:
        model = UserProfile        
        fields = ['user', 'id', 'about_me'] 

class UserEmailSerializer(serializers.HyperlinkedModelSerializer):
    
    def retrieve(self, request, *args, **kwargs):
        instance = self.get_object()
        self.kwargs.get('profile_lookup'))
        serializer = self.get_serializer(instance, context={'user_lookup': self.kwargs.get('user_lookup'), 'profile_lookup': self.kwargs.get('profile_lookup')})
        return Response(serializer.data)
    
    class Meta:
        model = UserEmails
        fields = ['profile' ,'email', 'user_lookup', 'profile_lookup' ]  

and views.py

class CustomUserViewSet(viewsets.ModelViewSet):
    queryset = CustomUser.objects.all()
    serializer_class = CustomUserSerializer  
    lookup_field = 'id'

class UserProfileViewSet(viewsets.ModelViewSet):
    queryset = UserProfile.objects.all()   
    serializer_class = UserProfileSerializer
    user_lookup = 'customuser_id'
    profile_lookup = 'userprofile_id'
    lookup_value_converter = 'uuid'
    
    def get_object(self):
        # Get the lookup parameters from the URL
        user_lookup = self.kwargs.get('user_lookup')
        profile_lookup = self.kwargs.get('profile_lookup')       
        # Perform the lookup using both fields
        try:
            obj = UserProfile.objects.get(user=user_lookup, id=profile_lookup)
            return obj
        except UserProfile.DoesNotExist:
            raise Http404('رکورد مربوطه یافت نشد') 

class UserEmailViewSet(viewsets.ModelViewSet):
    queryset = UserEmails.objects.all()
    serializer_class = UserEmailSerializer
    lookup_field = 'profile__id'

also urls.py

users_router = routers.DefaultRouter()
users_router.register(r'users', views.CustomUserViewSet, basename='customuser')
profile_router = routers.DefaultRouter()
profile_router.register(r'profile', views.UserProfileViewSet, basename='profile')
user_email_router = routers.DefaultRouter()
user_email_router.register(r'<uuid:user_id>/profile', views.UserEmailViewSet)

urlpatterns = [
    path('', views.CustomUserViewSet.as_view({'get': 'list', 'post': 'create'}), name='user-list'),
    path('profile/', views.UserProfileViewSet.as_view({'get': 'retrieve'}), name='user-profile'),    
    path('timezone/', views.TimezoneViewSet.as_view({'get': 'list', 'post': 'create'}), name='timezone'),
    path('user_emails/', views.UserEmailViewSet.as_view({'get': 'retrive', 'post': 'create'}), name='user_emails'),
]
# Include the router URLs
urlpatterns = profile_router.urls + user_email_router.urls

the problem is user_lookup and profile_lookup are always None so no records was retrived
any help would be appriciated
thanks

Hello Mr @MohammadAsadi4
I hope this message finds you well

I want to help with this issue
but need more details about your use case
what is the result you want to get?
how would you like to use these two lookups?
why do we need two while one can do the work?

that may help me find with you the best solution for it

1 Like

Thanks for your reply @suliman-99
you mentioned a good point actually when i think about my models i find out there is no need for two model that do the same thing