我正在尝试创建一个API,用户可以创建程序并向其中添加规则。规则必须按优先级顺序执行。我正在使用Django rest框架实现这一目标,并尝试在不使用ModelSerializer的情况下使用Serializer类来实现。请提供您使用serializers.Serializer类的解决方案。
一个程序可以有多个规则,而一个规则也可以出现在多个程序中。因此,我使用了many_to_many关系。我还希望用户能够更改程序中规则的顺序。为了实现这一点,我使用了一个称为Priority的联结表,通过priority字段跟踪规则和程序之间的关系。 models.py
当我向 http://localhost:8000/api/programs/ 发送一个GET请求时,我收到了这个响应。
在序列化过程后,validated_data包含priority_set字段而不是rules字段,如下所示。
谢谢您提前的帮助。
一个程序可以有多个规则,而一个规则也可以出现在多个程序中。因此,我使用了many_to_many关系。我还希望用户能够更改程序中规则的顺序。为了实现这一点,我使用了一个称为Priority的联结表,通过priority字段跟踪规则和程序之间的关系。 models.py
class Program(models.Model):
name = models.CharField(max_length=32)
description = models.TextField(blank=True)
rules = models.ManyToManyField(Rule, through='Priority')
class Rule(models.Model):
name = models.CharField(max_length=20)
description = models.TextField(blank=True)
rule = models.CharField(max_length=256)
class Priority(models.Model):
program = models.ForeignKey(Program, on_delete=models.CASCADE)
rule = models.ForeignKey(Rule, on_delete=models.CASCADE)
priority = models.PositiveIntegerField()
def save(self, *args, **kwargs):
super(Priority, self).save(*args, **kwargs)
serializers.py
class RuleSerializer(serializers.Serializer):
name = serializers.CharField(max_length=20)
description = serializers.CharField(allow_blank=True)
rule = serializers.CharField(max_length=256)
def create(self, validated_data):
return Rule.objects.create(**validated_data)
def update(self, instance, validated_data):
instance.name = validated_data.get('name', instance.name)
instance.description = validated_data.get('description', instance.description)
instance.rule = validated_data.get('rule', instance.rule)
instance.save()
return instance
class PrioritySerializer(serializers.Serializer):
rule_id = serializers.IntegerField(source='rule.id')
rule_name = serializers.CharField(source='rule.name')
rule_rule = serializers.CharField(source='rule.rule')
priority = serializers.IntegerField()
class ProgramSerializer(serializers.Serializer):
id = serializers.IntegerField()
name = serializers.CharField(max_length=32)
description = serializers.CharField(style={'base_template': 'textarea.html'})
rules = PrioritySerializer(source='priority_set', many=True)
def create(self, validated_data):
rules_data = validated_data.pop('rules')
program_obj = Program.objects.create(**validated_data)
priority = 0
for rule in rules_data:
rule_obj = Rule.objects.get(pk=rule.rule_id)
priority += 1
Priority.objects.create(program=program_obj, rule=rule_obj, priority=priority)
return program_obj
views.py
class ProgramList(APIView):
"""
List all programs, or create a new program.
"""
def get(self, request, format=None):
programs = Program.objects.all()
serializers = ProgramSerializer(programs, many=True)
return Response(serializers.data)
def post(self, request, format=None):
serializer = ProgramSerializer(data=request.data, partial=True)
print(serializer.initial_data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
当我向 http://localhost:8000/api/programs/ 发送一个GET请求时,我收到了这个响应。
[
{
"id": 1,
"name": "some",
"description": "hahah",
"rules": [
{
"rule_id": 3,
"rule_name": "DAIEA",
"rule_rule": "date,and,invoice,equal,amount",
"priority": 1
},
{
"rule_id": 2,
"rule_name": "DAIEA",
"rule_rule": "date,and,invoice,equal,amount",
"priority": 2
},
{
"rule_id": 1,
"rule_name": "DAI=A",
"rule_rule": "date,and,invoice,equal,amount",
"priority": 3
}
]
},
{
"id": 2,
"name": "DAI=AS",
"description": "Date and Invoice equal Amount Sumif",
"rules": []
},
]
在规则字段中,我获得了一系列规则列表,但是当我使用 request.data 进行POST请求来创建一个新程序时,需要借助规则ID与规则相对应。
POST数据:
{
"name": "DAI=AS",
"description": "Date and Invoice equal Amount Sumif",
"rules": [
{
"rule_id": 1
},
{
"rule_id": 2
}
]
}
在序列化过程后,validated_data包含priority_set字段而不是rules字段,如下所示。
{
'name': 'DAI=AS',
'description': 'Date and Invoice equal Amount Sumif',
'priority_set': [
OrderedDict([('rule', {'id': 1})]),
OrderedDict([('rule', {'id': 2})])
]
}
我不希望序列化器改变对priority_set的规则。
同时,我在priority_set中获取了OrderedDict对象列表,而我需要rule对象的字典。
这是我在序列化过程中想要的结果:
{
"name": "DAI=AS",
"description": "Date and Invoice equal Amount Sumif",
"rules": [
{
"rule_id": 1
},
{
"rule_id": 2
}
]
}
谢谢您提前的帮助。
Priority
模型中的program
外键中包含related_name
,因为你必须通过Program
模型对象访问它。但是,这个related_name
应该与rules
不同,否则会冲突。我正在添加第三种解决方案。 - kamran890