首页 > 解决方案 > Django Rest 框架:SerializerMethodField 和 get_queryset

问题描述

在我的数据库中,我有两个表 -usersuser_properties

我需要使用 GET 参数过滤输出phone。但是这两个表都有列phone并且具有不同的值。

当我执行 GET 请求(例如“?phone=123456789”)时,我不仅需要使用 user_properties.phone,还需要使用 user.phone 通过电话号码搜索用户!

我用谷歌搜索并找到了一种使用get_queryset(过滤)和SerializerMethodField(修改输出)的方法:

模型.py

class User(models.Model):
    balance = models.DecimalField(decimal_places=35, max_digits=40)
    fio = models.CharField(max_length=64)
    phone = models.CharField(max_length=64, blank=True, null=True)

    class Meta:
        managed = False
        db_table = 'user'


class UserProperties(models.Model):
    user_id = models.IntegerField(primary_key=True)
    phone = models.CharField(max_length=11)

    class Meta:
        managed = False
        db_table = 'user_properties'

视图.py

class UserPropertiesViewSet(viewsets.ModelViewSet):
queryset = UserProperties.objects.all()
serializer_class = serializers.UserPropertiesSerializer

def get_queryset(self):
    queryset = self.queryset
    # phone number from GET
    phone = self.request.query_params.get('phone')

    # Search users matches in user_properties using by phone number
    if phone:
        queryset = UserProperties.objects.all()
        users = queryset.filter(phone__contains=phone)
        return users
    else:
        return queryset

序列化程序.py

class UserPropertiesSerializer(serializers.ModelSerializer):
all_phones = serializers.SerializerMethodField()

class Meta:
    model = models.UserProperties
    fields = ['user_id', 'phone', 'fio', 'url', 'all_phones',]

# phone numbers from user and user_properties tables
def get_all_phones(self, obj):
    # search phones in <user> table by user_id
    user_phones = models.User.objects.filter(id__exact=obj.user_id).values_list('phone', flat=True)
    # add phones from user_properties table
    result = [obj.phone,]
    # add phones from user table
    for phone in user_phones[0].split(','):
        result.append(''.join(filter(lambda x: x.isdigit(), phone)))

    # return list with all phones
    return set(result)

all_phones在过滤结果中得到列:

{
"count": 1,
"next": null,
"previous": null,
"results": [
    {
        "user_id": 17897,
        "phone": "123456789", <--- user_properties table
        "fio": "....",
        "url": "....",
        "all_phones": [
            "123456789",
            "5512222",
            "49543"
        ] <--- user_properties.phone + user.phone
    }
]

}

但是在get_queryset我只使用 user_properties 表中的“真实”phone列进行过滤时。如何使用“虚拟”all_phones列过滤结果?或者在两个表中搜索并获取拥有此电话号码之一的用户?有可能吗?还是我的方法不对?

谢谢!

标签: djangorestapidjango-rest-framework

解决方案


这个问题更多的是关于 Django ORM 而不是 Django REST 框架,但是get_queryset像这样重写方法将搜索phone两个模型的字段:

from django.db.models import Q

...

def get_queryset(self):
    queryset = self.queryset
    # phone number from GET
    phone = self.request.query_params.get('phone')

    if phone:
        queryset = queryset.filter(
            Q(phone__contains=phone)
            | Q(user__phone__contains=phone)
        )

    return queryset

推荐阅读