从django中的许多表链接select_related

7vhp5slm  于 2023-03-04  发布在  Go
关注(0)|答案(1)|浏览(156)

这里我有以下模型:

class GenericUserData(AbstractUser):
    username = None
    id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
    email = models.EmailField(max_length=100, unique=True)
    date_joined = models.DateTimeField(auto_now_add=True)
   ....

class NormalSellerDetails(models.Model):
    userid = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, primary_key=True,db_column='UserID', unique=True)  # from table user.
    mobileauthenticationenabled = models.IntegerField(db_column='MobileAuthenticationEnabled', default=0)  # Field name made lowercase.
   .....

class UserBan(models.Model):
    user_id =  models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, primary_key=True,db_column='UserID', unique=True)  # from table user.
    from_date = models.DateField(null=False)

我想执行如下选择:

SELECT * FROM genericuserdata, normalsellerdetails, userban 
WHERE genericuserdata.id = normalsellerdetails.UserID AND genericuserdata.id = userban.UserID

我也有三seializers:

class GenericUserRetrievalSerializer(serializers.ModelSerializer):
    class Meta:
        model = GenericUserData    
        fields = [ "email", "first_name", 'last_name', 'is_seller', 'is_normal', 'is_emp', 'is_male', 'bdate']

class AccountNormalSerializer(serializers.ModelSerializer):
    userid = GenericUserRetrievalSerializer(many=False)
    class Meta:
        model = NormalSellerDetails
        fields = ['mobileauthenticationenabled',
                'emailauthenticationenabled',
                'mobilephone',
                'profilepiclink',
                'userid',
                'userban'
                ]

我可以这样做来链接GenericUserData和NormalSellerDetails:

class NormalAccountList(generics.ListAPIView):
    serializer_class = AccountNormalSerializer

    def get_queryset(self):
         queryset = NormalSellerDetails.objects.all().select_related('userid')
         return queryset

但我无法将所有这三个查询链接到一个查询中,注意到模型NormalSellerDetails与GenericUserData相关,而GenericUserData又与UserBan具有相反的关系
我的问题是:1-如何做那个链接?
2-userban表中只有被禁止的用户的行,如何创建一个输出字段,当行存在时为true,当行不存在时为false?
我也尝试这样做链接,但没有工作

class NormalAccountList(generics.ListAPIView):
    serializer_class = AccountNormalSerializer
    authentication_classes = [JWTAuthentication]
    permission_classes = [IsEmpReadAllUsersOrPost]

    def get_queryset(self):
        queryset= NormalSellerDetails.objects.select_related('userid').select_related('userid__userban_set').all()
        
        return queryset

class AccountNormalSerializer(serializers.ModelSerializer):
    userid = GenericUserRetrievalSerializer(many=False)
    userban = UserBanSerializer(many=False, read_only=True)
    class Meta:
        model = NormalSellerDetails
        fields = ['mobileauthenticationenabled',
                'emailauthenticationenabled',
                'mobilephone',
                'profilepiclink',
                'userid',
                'userban'
                ]

它告诉我"select_related中给出的字段名无效:'userban_set'。选项包括:linkcounter,normalsellerdetails,permissions,userban ",当我删除关键字集时,它实际上不会从userban表返回任何内容。

nhaq1z21

nhaq1z211#

您的查询集应该如下所示:

queryset = NormalSellerDetails.objects.select_related('userid', 'userid__userban').all()

这里请注意,如您得到的错误所示,userban是您要查找的字段,而不是userban_set
关于您的第二个问题,为了有一个字段指示用户是否被禁止,您可以在查询集上注解此字段,如:

from django.db.models import Case, When, BooleanField

queryset = NormalSellerDetails.objects.select_related(
    'userid', 'userid__userban').all().annotate(
     is_banned=Case(
         When(userid__userban__isnull=False, then=True),
         default=False,
         output_field=BooleanField()
     )
)

然后,您可以将此字段添加到序列化程序字段中,它应该出现在API响应中。
注意,理想情况下,在NormalSellerDetails模型中的属性应该命名为user,而不是userid。当然,在SQL级别上,这些关系是通过外键来实现的,外键本质上是一个ID,然而,将其命名为user意味着您将访问用户表,然后在该表中对属性进行一些操作。这将使Django代码更具可读性。

相关问题