Django REST - Resolving Foreign Keys and M2M's in a Serializer - json

I have the following Models:
class Player(models.Model):
name = models.CharField(max_length=30)
class Achievement(models.Model):
name = models.CharField(max_length=30)
class UnlockedAchievement(models.Model):
achievement = models.ForeignKey(Achievement)
date = models.DateTimeField()
class PlayerAchievements(models.Model):
player = models.ForeignKey(Player)
unlocked_achievements = models.ManyToManyField(UnlockedAchievement, related_name="unlocked_achievements", blank=True, null=True)
With a PUT, I'm trying to resolve both the Player's foreign key as well as the nested relationship of all the Achievements. My JSON data effectively looks like this:
{"name":"playername",
"achievements":
{
"ach1":"timestamp",
"ach2":"timestamp",
}
}
What I can't figure out is the magic combination of which kinds of Serializers to use and, when using them, which serializer fields or nested Serializers to use to be able to resolve Players by name, and the unlocked achievements (and then their Achievement foreign keys) by providing a name.
In this case I don't have access to id numbers, hence why things are done by names.
Such a strange mixture it seems. Can anyone lend a hand? Thanks in advance!

You can use nested relationships to fully include the serialization of a related model:
class AchievementSerializer(serializers.ModelSerializer):
class Meta:
model = Achievement
class UnlockedAchievementSerializer(serializers.ModelSerializer):
achievement = AchievementSerializer(many=False)
class Meta:
model = UnlockedAchievement
class PlayerAchievementsSerializer(serializers.ModelSerializer):
unlocked_achievements = UnlockedAchievementSerializer(many=True)
class Meta:
model = PlayerAchievements
class PlayerSerializer(serializers.ModelSerializer):
player_achievements = PlayerAchievementsSerializer(many=False)
class Meta:
model = Player
Then just filter the Player object by name and serialize it.

Related

FilterSet for ManyToMany relationship existence

Basic models:
class ModelA(Model):
name = CharField(...)
class ModelB(Model):
model_a = ManyToManyField(ModelA, blank=True)
class ModelBFilter(filters.FilterSet):
unassigned = BooleanFilter(field_name='model_a', lookup_expr='isnull')
class Meta:
model = ModelB
fields = ['unassigned']
How do I filter (with django-filter) to find the ModelB's that do not have a corresponding related model?
It looks to me that what you have should work. Perhaps the fields = ['unassigned'] is unnecessary? According to the documentation you can also negate the filter thusly:
class ModelBFilter(filters.FilterSet):
assigned = BooleanFilter(field_name='model_a', lookup_expr='isnull', exclude=True)
class Meta:
model = ModelB

Django: Can you create a relationship with an auto-generated through table?

My code looks something like this:
from django.db import models
from django.conf import settings
User = settings.AUTH_USER_MODEL
class Dish(models.Model):
name = models.CharField(max_length=200)
class Meal(models.Model):
name = models.CharField(max_length=200)
dishes = models.ManyToManyField(Dish)
The many-to-many dishes field will result in a database table called 'myapp_meal_dishes' being created that includes id, meal_id, and dish_id fields.
I would like to add a MealDishEater model that connects with that auto-generated table:
class MealDishEater(models.Model):
meal_dish = models.ForeignKey(MealDishes, on_delete=models.CASCADE)
eater = models.ForeignKey(User, on_delete=models.PROTECT)
ate_meal = models.BooleanField(default=False)
Of course, that doesn't work, because MealDishes is not defined. Is there a way to do this or do I have to create my own through table?
You can access the ManyToManyField intermediate model with the through attribute. So this should work:
class MealDishEater(models.Model):
meal_dish = models.ForeignKey(Meal.dishes.through, on_delete=models.CASCADE)
Personally, though, I always create explicit through models for ManyToManyFields rather than allowing such magic.

How to implement ForeignKey with Django serializer

I have this models:
class Discipline(models.Model):
name = models.CharField(max_length=200)
class Lesson(models.Model):
discipline = models.ForeignKey(Discipline, on_delete=models.CASCADE, null=True)
date = models.DateField()
regular_slot = models.BooleanField(default=False)
And these serializers:
class DisciplineSerializer(serializers.ModelSerializer):
class Meta:
model = Discipline
fields = ('name')
class LessonSerializer(serializers.ModelSerializer):
discipline = serializers.RelatedField(source='Discipline', read_only=True);
class Meta:
model = Lesson
fields = ('discipline', 'date', 'regular_slot')
I have a view to process a JSON request and to save the data:
def cours_list(request):
if request.method == 'POST':
data = JSONParser().parse(request)
serializer = LessonSerializer(data=data)
if serializer.is_valid():
serializer.save()
return JSONResponse(serializer.data, status=201)
return JSONResponse(serializer.errors, status=400)
My JSON request is as follows:
{"discipline":"Mathematiques","date":"2017-12-03"}
However, I have an error saying that:
'Lesson' object has no attribute 'Discipline'
I believe this is because attribute discipline in Lesson refers only to the id and is not of type Discipline. I could'nt find how to solve this. Is the way I define foreignKey is not correct ?
How to insert a foreignKey reference here while I receive a Discipline object from the JSON request ?
I'm going to help you also with this :)
class DisciplineSerializer(serializers.ModelSerializer):
class Meta:
model = Discipline
fields = ('name')
class LessonSerializer(serializers.ModelSerializer):
discipline = DiscliplineSerializer()
class Meta:
model = Lesson
fields = ('discipline', 'date', 'regular_slot')
Doing this is enough as far as I know.
Edit: Reason of your error is that you write "source="Discipline"" but there is no field named Discipline in your Lesson model. Therefore, it gives an error.

Django Model: What is a efficient way to list Foreign Key?

I have three models below. I omit some irrelative fields.
class Team(models.Model):
name = models.CharField(max_length=100)
class Player(models.Model):
name = models.CharField(max_length=100)
class Match(models.Model):
home = models.ForeignKey(Team)
away = models.ForeignKey(Team)
home_players = models.CharField(max_length=100, null=True)
away_players = models.CharField(max_length=100, null=True)
home_players and away_players have the type of player id list, such as [1,2,3,...,15].
I want to know better ways like using Foreign Key List.
Because, I have some troubles in manually inserting players IDs at Django Admin Page. It takes much time finding player name in Player() and matching player's ID. I guess the task would be easier if I can assign a certain relationship between Player() and Team().
That would be a many-to-many relationship.
https://docs.djangoproject.com/en/1.9/topics/db/examples/many_to_many/
class Match(models.Model):
home = models.ForeignKey(Team)
away = models.ForeignKey(Team)
home_players = models.ManyToManyField(Player)
away_players = models.ManyToManyField(Player)

assign list elements to database entity in sqlalchemy from a list

I have a simple model as follows, i have a list of games and i want all the players to assign one and only one game, from the list of games. How would i do it in sqlalchemy.
As of now i am using flask sqlalchemy, but the question does not limit to flask-sqlalchemy.
games = ['soccer', 'hockey', 'baseball', 'cricket', 'basketball']
from flask.ext.sqlalchemy import SQLAlchemy
class Gamer(db.Model):
id = db.Column(db.Integer, primary_key=True)
team_name = db.Column(db.String(80))
game_name = db.Column(db.String(80))
game = db.Column(db.String(80), i want only games from the list of games)
The analogous django functionality is found here.
First of all, the django functionality you refer to is not really analogous to the model you list. The reason for this is that Gamer is a model whereas SimpleForm is a UI form.
However, below are few ways you can validate the model:
1) Create a separate tabbe for Games, add the values as rows, and create a N-to-1 relationship from Gamer to the Game. This is readable, and will validate your data on both the business and DB levels
class Game(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(80))
class Gamer(db.Model):
# ...
game_id = db.Column(db.Integer, ForeignKey('game.id'))
game = relationship(Game)
2) Create and use a simple validator
from sqlalchemy.orm import validates
class Gamer(db.Model):
# ...
#validates('game')
def validate_game(self, key, address):
assert address in games
return address
edit-1: alternatively, take a look at the The Enum Recipe. But again this is on a model level, not UI validation.