I am trying to create an api, where user can create programs and add rules to them. Rules has to be executed in order of priority. I am using Django rest framework to achieve this and I am trying to achieve this using Serializer without using ModelSerializer. Provide your solution using serializers.Serializer class
One program can have many rules and one rule can be in many programs. So, I am using many_to_many relationship and also I want the user to change the order of rules in a program, to achieve this I am using a through table called Priority, where I keep track of relationship between a rule and a program using priority field
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)
When I make a get request to http://localhost:8000/api/programs/, I got this response
[
{
"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": []
},
]
I got list of rules under rules field, but when I make post request with this request.data to create a new program with rules with the help of rule.id,
Post data:
{
"name": "DAI=AS",
"description": "Date and Invoice equal Amount Sumif",
"rules": [
{
"rule_id": 1
},
{
"rule_id": 2
}
]
}
After the serialization process, validated_data contains priority_set field instead of rules field, like below
{
'name': 'DAI=AS',
'description': 'Date and Invoice equal Amount Sumif',
'priority_set': [
OrderedDict([('rule', {'id': 1})]),
OrderedDict([('rule', {'id': 2})])
]
}
I don't want the serializer to change rules to priority_set
And also, I am getting list of OrderedDict in priority_set, instead I need dictionary of rule objects
This is what I want after serialization process,
{
"name": "DAI=AS",
"description": "Date and Invoice equal Amount Sumif",
"rules": [
{
"rule_id": 1
},
{
"rule_id": 2
}
]
}
Thanks in advance