I have the following json that I want to deserialize in order to insert data into 3 tables.
{
"id":"game_id",
"rated":true,
"variant":"standard",
"speed":"fast",
"perf":"fast",
"createdAt": 1234,
"lastMoveAt":1234,
"status":"resign",
"players":{
"white":{
"user":{
"name":"player1",
"id":"player1"
},
"rating":1000,
"ratingDiff":-5
},
"black":{
"user":{
"name":"player2",
"id":"player2"
},
"rating":1001,
"ratingDiff":5
}
},
"winner":"black",
"opening":{
"eco":"Z99",
"name":"my opening",
"ply":2
},
"moves":"1, 2, 3, 4",
"clock":{
"initial":60,
"increment":0,
"totalTime":60
}
}
Here are my models :
class User(models.Model):
class Meta:
ordering = ["id"]
id = models.CharField(primary_key=True, max_length=100)
name = models.CharField(max_length=100)
def __repr__(self):
return f"User(id={self.id!r}, name={self.name!r})"
class Opening(models.Model):
class Meta:
ordering = ["eco"]
constraints = [
models.UniqueConstraint(
fields=["name", "eco"], name="eco_name"
)
]
name = models.CharField(max_length=200)
eco = models.CharField(max_length=3)
def __repr__(self):
return f"User(name={self.name!r}, eco={self.eco!r})"
class Game(models.Model):
class Meta:
ordering = ["last_move_at"]
id = models.CharField(primary_key=True, max_length=15)
rated = models.BooleanField(default=True)
variant = models.CharField(max_length=200)
speed = models.CharField(max_length=50)
perf = models.CharField(max_length=50)
created_at = models.IntegerField()
last_move_at = models.IntegerField()
status = models.CharField(max_length=50)
winner = models.CharField(max_length=100)
moves = models.TextField(max_length=1000)
white_rating = models.IntegerField()
white_rating_diff = models.IntegerField()
white = models.ForeignKey(User, related_name="white_id", on_delete=models.CASCADE)
black_rating = models.IntegerField()
black_rating_diff = models.IntegerField()
black = models.ForeignKey(User, related_name="black_id", on_delete=models.CASCADE)
opening = models.ForeignKey(Opening, related_name="eco_name", on_delete=models.CASCADE)
initial_time = models.IntegerField(null=True)
increment = models.IntegerField(null=True)
total_time = models.CharField(max_length=200)
Here are my serializers :
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ["id", "name"]
class OpeningSerializer(serializers.ModelSerializer):
class Meta:
model = Opening
fields = ["name", "eco"]
def create(self, validated_data):
return Opening.objects.get_or_create(**validated_data)[0]
class GameSerializer(serializers.ModelSerializer):
class Meta:
model = Game
fields = ['id', 'rated', 'variant', 'speed', 'perf', 'created_at', 'last_move_at',
'status', 'winner', 'moves', 'white_rating', 'white_rating_diff',
'white', 'black_rating', 'black_rating_diff', 'black', "opening",
'initial_time', 'increment', 'total_time']
def to_internal_value(self, data):
internal_value = {"opening": data.pop("opening")}
del data["pgn"]
white_data = data.get("players")["white"]
internal_value["white"] = white_data["user"]
internal_value["white_rating"] = white_data["rating"]
internal_value["white_rating_diff"] = white_data["ratingDiff"]
black_data = data.pop("players")["black"]
internal_value["black"] = black_data["user"]
internal_value["black_rating"] = black_data["rating"]
internal_value["black_rating_diff"] = black_data["ratingDiff"]
internal_value["created_at"] = data.pop("createdAt")
internal_value["last_move_at"] = data.pop("lastMoveAt")
internal_value["initial_time"] = data.get("clock").get("initial")
internal_value["increment"] = data.get("clock").get("increment")
internal_value["total_time"] = data.pop("clock").get("totalTime")
return {**internal_value, **data}
def create(self, validated_data):
white = validated_data.pop("white")
white_user, is_created = User.objects.get_or_create(id=white["id"], name=white["name"])
black = validated_data.pop("black")
black_user, is_created = User.objects.get_or_create(id=black["id"], name=black["name"])
opening = validated_data.pop("opening")
opening_model, is_created = Opening.objects.get_or_create(name=opening["name"], eco=opening["eco"])
return Game.objects.get_or_create(white=white_user, black=black_user, opening=opening_model, **validated_data)[0]
I have two problems :
The first one is that I am new to django and DRF so I don’t know if I am following good practices here.
The second one is that sometimes the json I receive contains additional fields, like:
"players":{
"white":{
"user":{
"name":"player1",
"id":"player1",
**"moderator": True**
}
}
}
and my deserialization process fails because it contains an unexpected field.
How can I handle it ?