import json from rest_framework import serializers from .models import Material, MaterialCategory, MaterialSubcategory class JSONListField(serializers.ListField): def to_internal_value(self, data): if isinstance(data, str): try: data = json.loads(data) except json.JSONDecodeError: data = [data] return super().to_internal_value(data) class MaterialSerializer(serializers.ModelSerializer): """ 材料序列化器 """ factory_name = serializers.CharField(source='factory.factory_name', read_only=True) factory_short_name = serializers.CharField(source='factory.factory_short_name', read_only=True) major_category_display = serializers.CharField(source='get_major_category_display', read_only=True) replace_type_display = serializers.CharField(source='get_replace_type_display', read_only=True) application_scene = JSONListField( child=serializers.ChoiceField(choices=Material.APPLICATION_SCENE_CHOICES), required=False, allow_empty=True ) advantage = JSONListField( child=serializers.ChoiceField(choices=Material.ADVANTAGE_CHOICES), required=False, allow_empty=True ) advantage_display = serializers.SerializerMethodField() application_scene_display = serializers.SerializerMethodField() brochure_url = serializers.SerializerMethodField() class Meta: model = Material fields = ['id', 'name', 'major_category', 'major_category_display', 'material_category', 'material_subcategory', 'spec', 'standard', 'application_scene', 'application_scene_display', 'application_desc', 'replace_type', 'replace_type_display', 'advantage', 'advantage_display', 'advantage_desc', 'cost_compare', 'cost_desc', 'cases', 'brochure', 'brochure_url', 'quality_level', 'durability_level', 'eco_level', 'carbon_level', 'score_level', 'connection_method', 'construction_method', 'limit_condition', 'factory', 'factory_name', 'factory_short_name', 'status', 'created_at', 'updated_at'] read_only_fields = ['id', 'created_at', 'updated_at'] def get_brochure_url(self, obj): """ 获取宣传页图片URL """ if obj.brochure: request = self.context.get('request') if request: return request.build_absolute_uri(obj.brochure.url) return None def _display_list(self, codes, choices): mapping = dict(choices) if not codes: return [] if isinstance(codes, str): codes = [codes] return [mapping.get(code, code) for code in codes] def get_application_scene_display(self, obj): return self._display_list(obj.application_scene, Material.APPLICATION_SCENE_CHOICES) def get_advantage_display(self, obj): return self._display_list(obj.advantage, Material.ADVANTAGE_CHOICES) class MaterialListSerializer(serializers.ModelSerializer): """ 材料列表序列化器(简化版) """ factory_name = serializers.CharField(source='factory.factory_name', read_only=True) factory_short_name = serializers.CharField(source='factory.factory_short_name', read_only=True) major_category_display = serializers.CharField(source='get_major_category_display', read_only=True) status_display = serializers.CharField(source='get_status_display', read_only=True) class Meta: model = Material fields = ['id', 'name', 'major_category', 'major_category_display', 'material_category', 'material_subcategory', 'factory', 'factory_name', 'factory_short_name', 'status', 'status_display'] class MaterialCategorySerializer(serializers.ModelSerializer): """ 材料分类序列化器 """ subcategory_count = serializers.SerializerMethodField() class Meta: model = MaterialCategory fields = ['id', 'name', 'value', 'created_at', 'updated_at', 'subcategory_count'] read_only_fields = ['id', 'created_at', 'updated_at', 'subcategory_count'] def get_subcategory_count(self, obj): return obj.subcategories.count() class MaterialSubcategorySerializer(serializers.ModelSerializer): """ 材料子分类序列化器 """ category_name = serializers.CharField(source='category.name', read_only=True) class Meta: model = MaterialSubcategory fields = ['id', 'category', 'category_name', 'name', 'value', 'created_at', 'updated_at'] read_only_fields = ['id', 'created_at', 'updated_at', 'category_name']