最新消息:20210816 当前crifan.com域名已被污染,为防止失联,请关注(页面右下角的)公众号

【已解决】Django的Serializer中如何序列化Script中的Author的Function Group

Django crifan 956浏览 0评论
折腾:
【未解决】剧本编写系统中优化全部剧本列表页
期间,想要给当前:
添加一列 剧本组,结果发现还有点点麻烦:
因为此处从后台返回的数据中:
        serializer = ScriptSerializer(queryset, many=True)
        logger.info("serializer=%s", serializer)
        serializedData = serializer.data
        logger.info("serializedData=%s", serializedData)

        respData = None
        if page is not None:
            respData = self.get_paginated_response(serializedData)
        else:
            respData = Response(serializedData)

        logger.info("respData=%s", respData)
        return respData
是通过ScriptSerializer:
class ScriptSerializer(serializers.ModelSerializer):
    author = serializers.CharField(source='author.username', read_only=True)
    topic = serializers.CharField(source='topic.name', read_only=False)
    second_level_topic = serializers.SerializerMethodField()
    publish_status = serializers.SerializerMethodField()
    edit_status = serializers.SerializerMethodField()
    review = ReviewSerializer(many=False, read_only=True)
    dialog_count = serializers.SerializerMethodField()

    class Meta:
        model = Script
        fields = ('id', 'place', 'title', 'topic', 'second_level_topic',
                  'age_start', 'version', 'age_end', 'author',
                  'publish_status', 'edit_status', 'review', 'dialog_count',
                  'created_at', 'updated_at')
很明显,其中只有author的名字,而没有author所在的script的function group
需要去加上这个字段,才可以返回给前端。
而参考:
review = ReviewSerializer(many=False, read_only=True)

class ReviewSerializer(serializers.ModelSerializer):
    reviewer = serializers.CharField(source='reviewer.username',
                                     read_only=True)
    result = serializers.SerializerMethodField()

    class Meta:
        model = Review
        fields = ('id', 'reviewer', 'remark', 'result')
        read_only_fields = ('id', 'created_at', 'updated_at')

    def get_result(self, obj):
        return obj.get_result_display()
好像是可以通过把author去改为:
author = UserSerializer(many=False, read_only=True)

class UserSerializer(serializers.ModelSerializer):

    class Meta:
        model = User
        fields = ('id', 'mobile_phone_number', 'email', 'password', 'username',
                  'name', 'is_superuser', 'is_active', 'date_joined')
        read_only_fields = ('id', 'is_superuser', 'date_joined')
        extra_kwargs = {'password': {'write_only': True}}
但是发现此处的user,并不能很好的找到其所加入的scritp function group
Serializer relations – Django REST framework
貌似可以用其中的自定义的RelatedField去实现:
从script的author找到其是否有加入script的function group,然后返回对应的group的id和name
结果试了半天:
class ScriptFuctionGroup(serializers.RelatedField):
    def to_representation(self, value):
        logger.info("ScriptFuctionGroup to_representation: self=%s, value=%s", self, value)
        # find current script author joined script function group
        return {
            "groupId": "",
            "groupName": "",
        }

class ScriptSerializer(serializers.ModelSerializer):
    author = serializers.CharField(source='author.username', read_only=True)
    # author = UserSerializer(many=False, read_only=True)
    joinedScriptGroup = ScriptFuctionGroup(many=False, read_only=True)
不起效果:to_representation都运行不到。
但是对于ScriptFuctionGroup倒是可以看到的:
INFO|20180802 11:08:12|views:list:150|after ScriptSerializer serializer=ScriptSerializer(<QuerySet [<Script: 儿歌>, <Script: 儿歌>, <Script: 儿歌>, <Script: 1>, <Script: 1>, <Script: 1>, <Script: wer>]>, many=True):
    id = UUIDField(read_only=True)
    place = CharField(max_length=128)
    title = CharField(max_length=128)
    topic = CharField(read_only=False, source='topic.name')
    second_level_topic = SerializerMethodField()
    age_start = IntegerField(max_value=2147483647, min_value=-2147483648, required=False)
    version = IntegerField(read_only=True)
    age_end = IntegerField(max_value=2147483647, min_value=-2147483648, required=False)
    author = CharField(read_only=True, source='author.username')
    joinedScriptGroup = ScriptFuctionGroup(read_only=True)
    publish_status = SerializerMethodField()
    edit_status = SerializerMethodField()
    review = ReviewSerializer(read_only=True):
        id = UUIDField(read_only=True)
        reviewer = CharField(read_only=True, source='reviewer.username')
        remark = CharField(style={'base_template': 'textarea.html'})
        result = SerializerMethodField()
    dialog_count = SerializerMethodField()
    created_at = DateTimeField(read_only=True)
    updated_at = DateTimeField(read_only=True)
而此处看到:
class User(AbstractUser):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    is_active = models.BooleanField(default=False)
    name = models.CharField(blank=True, max_length=128)
    mobile_phone_number = models.CharField(blank=False, null=False,
                                           max_length=11, unique=True)

class FunctionGroup(TimestampedModel):
    TYPE_VALUE_ADMIN = "0"
    TYPE_VALUE_SCRIPT = "1"
    TYPE_NAME_ADMIN = "admin_function_group"
    TYPE_NAME_SCRIPT = "script_function_group"

    CHOICES = {
        (TYPE_VALUE_ADMIN, TYPE_NAME_ADMIN),
        (TYPE_VALUE_SCRIPT, TYPE_NAME_SCRIPT),
    }

    owner = models.ForeignKey(settings.AUTH_USER_MODEL,
                              on_delete=models.PROTECT,
                              related_name='user_function_group')
    name = models.CharField(null=False, blank=False, max_length=128)
    function = models.CharField(
        null=False, blank=False,
        # choices=FUNCTION_GROUP_CHOICES,
        choices=CHOICES,
        max_length=128,
        # default=FUNCTION_GROUP_CHOICES_DEFAULT
        default=TYPE_VALUE_SCRIPT
    )
    description = models.CharField(null=True, blank=True, max_length=128)
    members = models.ManyToManyField(User)
User中没有直接可以获取到FunctionGroup
但是貌似FunctionGroup中有间接的user_function_group,或许可以获取到?
去试试
另外同时看到了:
script_script中有:
author_id
history_id
review_id
好像都可以直接在:
ScriptSerializer中直接用类似于:
review = ReviewSerializer(many=False, read_only=True)
直接调用到别的serializer的感觉
那或许author也可以
然后author再去用user_function_group,找到function group?
去试试:
class UserFunctionGroupSerializer(serializers.ModelSerializer):

    class Meta:
        model = User
        fields = ('id', 'username', 'name', 'user_function_group', 'is_active')
        read_only_fields = ('id', 'username', 'name', 'user_function_group', 'is_active')

from apps.user.serializers import UserFunctionGroupSerializer


class ScriptSerializer(serializers.ModelSerializer):
    author = serializers.CharField(source='author.username', read_only=True)
    # author = UserSerializer(many=False, read_only=True)
    # joinedScriptGroup = ScriptFuctionGroup(many=False, read_only=True)
    authorObj = UserFunctionGroupSerializer(many=False, read_only=True)
结果
没用。去加上source:
authorObj = UserFunctionGroupSerializer(source='author', many=False, read_only=True)
结果:
是可以获得group数据了:
但是很明显:
只有group的id,缺少我们要的group的name,且没有完全排除掉 非script的function group
所以还要去想办法,自定义
试试:
class ScriptFuctionGroup(serializers.RelatedField):
    def to_representation(self, value):
        logger.info("ScriptFuctionGroup to_representation: self=%s, value=%s", self, value)
        # find current script author joined script function group
        return {
            "groupId": "",
            "groupName": "",
        }

class UserFunctionGroupSerializer(serializers.ModelSerializer):
    user_function_group = ScriptFuctionGroup(many=False, read_only=True)

    class Meta:
        model = User
        fields = ('id', 'username', 'name', 'user_function_group', 'is_active')
        read_only_fields = ('id', 'username', 'name', 'user_function_group', 'is_active')
能否运行到to_representation
前端显示的效果是:
表示执行到了,所以去看Django的log
INFO|20180802 11:34:03|serializers:to_representation:27|ScriptFuctionGroup to_representation: self=ScriptFuctionGroup(read_only=True), value=user.FunctionGroup.None
value不是我们以为的之前的function group的id的list:
[4,3]
而是None
django serializer Custom fields
python – Django Rest Framework – How to add custom field in ModelSerializer – Stack Overflow
去试试serializers.SerializerMethodField()
class UserFunctionGroupSerializer(serializers.ModelSerializer):
    # user_function_group = ScriptFuctionGroup(many=False, read_only=True)
    # user_function_group = FunctionGroupSimpleSerializer(many=True, read_only=True)
    user_function_group = serializers.SerializerMethodField()

    class Meta:
        model = User
        fields = ('id', 'username', 'name', 'user_function_group', 'is_active')
        read_only_fields = ('id', 'username', 'name', 'user_function_group', 'is_active')

    def get_user_function_group(self, obj):
        logger.info("ScriptFuctionGroup to_representation: self=%s, obj=%s", self, obj)

        return {
            "groupId": obj,
        }
结果:
还是不行。
后来试了:
# class ScriptFuctionGroup(serializers.RelatedField):
#     def to_representation(self, value):
#         logger.info("ScriptFuctionGroup to_representation: self=%s, value=%s", self, value)
#         # find current script author joined script function group
#         return {
#             "groupId": "",
#             "groupName": "",
#         }

class ScriptSerializer(serializers.ModelSerializer):
    author = serializers.CharField(source='author.username', read_only=True)
    # author = UserSerializer(many=False, read_only=True)
    # joinedScriptGroup = ScriptFuctionGroup(many=False, read_only=True)
    authorObj = UserFunctionGroupSerializer(source='author', many=False, read_only=True)
    topic = serializers.CharField(source='topic.name', read_only=False)
    second_level_topic = serializers.SerializerMethodField()
    publish_status = serializers.SerializerMethodField()
    edit_status = serializers.SerializerMethodField()
    review = ReviewSerializer(many=False, read_only=True)
    dialog_count = serializers.SerializerMethodField()

    class Meta:
        model = Script
        fields = ('id', 'place', 'title', 'topic', 'second_level_topic',
                  'age_start', 'version', 'age_end', 'author',
                   'authorObj',
                  'publish_status', 'edit_status', 'review', 'dialog_count',
                  'created_at', 'updated_at')
        read_only_fields = ('id', 'version', 'publish_status', 'edit_status',
                            'authorObj',
                            'created_at', 'updated_at')

    def get_publish_status(self, obj):
        return obj.get_publish_status_display()

    def get_edit_status(self, obj):
        return obj.get_edit_status_display()

    def get_dialog_count(self, obj):
        return obj.script_dialogs.all().count()

    def get_second_level_topic(self, obj):
        if obj.second_level_topic_id:
            return obj.second_level_topic.name
        else:
            return ''


class FunctionGroupSimpleSerializer(serializers.ModelSerializer):
    function = serializers.SerializerMethodField()

    class Meta:
        model = FunctionGroup
        fields = ('id', 'name', 'function')
        read_only_fields = ('id', 'name', 'function')

    def get_function(self, obj):
        return obj.get_function_display()

class UserFunctionGroupSerializer(serializers.ModelSerializer):
    # user_function_group = ScriptFuctionGroup(many=False, read_only=True)
    # user_function_group = FunctionGroupSimpleSerializer(source="user_function_group", many=True, read_only=True)
    user_function_group = FunctionGroupSimpleSerializer(many=True, read_only=True)
    # user_function_group = serializers.SerializerMethodField()

    class Meta:
        model = User
        fields = ('id', 'username', 'name', 'user_function_group', 'is_active')
        read_only_fields = ('id', 'username', 'name', 'user_function_group', 'is_active')

    # def get_user_function_group(self, obj):
    #     logger.info("UserFunctionGroupSerializer get_user_function_group: self=%s, obj=%s", self, obj)
    #     functionGroupIdList = obj.user_function_group
    #     logger.info("functionGroupIdList=%s", functionGroupIdList)

    #     return {
    #         "groupId": functionGroupIdList,
    #     }
可以得到我们要的多个group了:
但是别的账号,却找不到user_function_group
所以还是有问题。
Serializer fields – Django REST framework
期间,遇到:
【已解决】Django中查询model中字段是数组对象出错:django.core.exceptions.FieldError: Related Field got invalid lookup: contains
【总结】
至此,是通过序列化Script中author的字段,单独去处理,解析和获取对应的所加入的script的fucntion group,去实现找到对应的一个剧本的作者所加入的(唯一的一个)剧本组:
# class ScriptFuctionGroup(serializers.RelatedField):
class ScriptFuctionGroup(serializers.Field):
    def to_representation(self, value):
        logger.info("ScriptFuctionGroup to_representation: self=%s, value=%s", self, value)
        # find current script author joined script function group
        curUser = value
        logger.info("curUser=%s", curUser)
        # joinedScriptGroup = FunctionGroup.objects.get(members__contains=curUser, function=FunctionGroup.TYPE_VALUE_SCRIPT)
        joinedScriptGroup = FunctionGroup.objects.get(members__id=curUser.id, function=FunctionGroup.TYPE_VALUE_SCRIPT)
        logger.info("joinedScriptGroup=%s", joinedScriptGroup)
        return {
            "groupId": joinedScriptGroup.id,
            "groupName": joinedScriptGroup.name,
        }

class ScriptSerializer(serializers.ModelSerializer):
    author = serializers.CharField(source='author.username', read_only=True)
    # author = UserSerializer(many=False, read_only=True)
    # authorObj = UserFunctionGroupSerializer(many=False, read_only=True)
    joinedScriptGroup = ScriptFuctionGroup(source='author')
    # joinedScriptGroup = ScriptFuctionGroup(many=False, read_only=True)
    # authorObj = UserFunctionGroupSerializer(source='author', many=False, read_only=True)
    topic = serializers.CharField(source='topic.name', read_only=False)
    second_level_topic = serializers.SerializerMethodField()
    publish_status = serializers.SerializerMethodField()
    edit_status = serializers.SerializerMethodField()
    review = ReviewSerializer(many=False, read_only=True)
    dialog_count = serializers.SerializerMethodField()

    class Meta:
        model = Script
        fields = ('id', 'place', 'title', 'topic', 'second_level_topic',
                  'age_start', 'version', 'age_end', 'author',
                #    'authorObj',
                    'joinedScriptGroup',
                  'publish_status', 'edit_status', 'review', 'dialog_count',
                  'created_at', 'updated_at')
        read_only_fields = ('id', 'version', 'publish_status', 'edit_status',
                            # 'authorObj',
                            'joinedScriptGroup',
                            'created_at', 'updated_at')

    def get_publish_status(self, obj):
        return obj.get_publish_status_display()

    def get_edit_status(self, obj):
        return obj.get_edit_status_display()

    def get_dialog_count(self, obj):
        return obj.script_dialogs.all().count()

    def get_second_level_topic(self, obj):
        if obj.second_level_topic_id:
            return obj.second_level_topic.name
        else:
            return ''
从而使得前端返回的script中,可以有多余的字段能保存当前作者已加入的功能组:

转载请注明:在路上 » 【已解决】Django的Serializer中如何序列化Script中的Author的Function Group

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
83 queries in 0.181 seconds, using 22.11MB memory