I have a few models to represent a user. A user has a garden, a profile and a gardener_profile. When serialising the user objects, garden and profile are getting showed, but gardener_profile is not. All of them are one to one relations. In my swagger doc the gardener_profile is recognized, but not in the response object.
Here are the serializers:
class WorkingHoursSerializer(serializers.ModelSerializer):
gardener_profile = serializers.StringRelatedField(read_only=True)
class Meta:
model = WorkingHours
fields = '__all__'
class GardenSerializer(serializers.ModelSerializer):
user = serializers.PrimaryKeyRelatedField(read_only=False, queryset=GardreamUser.objects.all())
class Meta:
model = Garden
fields = ['id', 'url', 'grass', 'beds', 'terrace', 'tracks', 'entry', 'user']
class GardenerProfileSerializer(serializers.ModelSerializer):
user = serializers.PrimaryKeyRelatedField(read_only=False, queryset=GardreamUser.objects.all())
working_hours = WorkingHoursSerializer(many=True)
class Meta:
model = GardenerProfile
fields = ['id', 'url', 'working_radius', 'salary', 'iban', 'contract', 'user', 'working_hours']
def create(self, validated_data):
working_hours_data = validated_data.pop('working_hours')
gardener_profile = GardenerProfile.objects.create(**validated_data)
for working_hour_data in working_hours_data:
WorkingHours.objects.create(gardener_profile=gardener_profile, **working_hour_data)
return gardener_profile
class UserProfileSerializer(serializers.ModelSerializer):
user = serializers.StringRelatedField(read_only=True)
class Meta:
model = UserProfile
fields = '__all__'
class UserSerializer(serializers.HyperlinkedModelSerializer):
profile = UserProfileSerializer(required=True)
garden = GardenSerializer(read_only=True)
gardener_profile = GardenerProfileSerializer(read_only=True)
class Meta:
model = CustomUser
fields = ['id', 'url', 'username', 'email', 'first_name', 'last_name', 'password', 'groups', 'profile',
'garden', 'gardener_profile']
extra_kwargs = {'password': {'write_only': True}}
And here are the models:
class CustomUser(AbstractUser):
email = models.EmailField(unique=True)
class UserProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='profile')
address = models.CharField(max_length=255)
country = models.CharField(max_length=50)
city = models.CharField(max_length=50)
zip = models.CharField(max_length=5)
class Garden(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
grass = models.DecimalField(max_digits=6, decimal_places=2)
terrace = models.DecimalField(max_digits=6, decimal_places=2)
class GardenerProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
salary = models.DecimalField(max_digits=6, decimal_places=2)
contract = models.FileField(null=True, blank=True)
class WorkingHours(models.Model):
gardener_profile = models.ForeignKey(GardenerProfile, related_name='working_hours', on_delete=models.CASCADE)
weekday = models.IntegerField(choices=WEEKDAYS)
from_hour = models.TimeField()
to_hour = models.TimeField()
class Meta:
ordering = ('weekday', 'from_hour')
unique_together = ('weekday', 'gardener_profile')
I found the solution: add related_name='gardener_profile' to the user field at GardenerProfile
Related
I am currently trying to implement the following serializer to the Profile serializer. But I would like to add a condition to it.
Profile serializer
class UserProfileSerializer(serializers.ModelSerializer):
role = serializers.ChoiceField(choices=(('Reader', u'Reader'), ('Author', u'Author'), ('Admin', u'Admin')))
role_display = serializers.SerializerMethodField()
class Meta:
model = Profile
fields = ('gender', 'birthday', 'icon', 'role', 'role_display')
depth = 1
Author serializer
class AuthorSerializer(serializers.ModelSerializer):
class Meta:
model = Author
fields = '__all__'
Reader serializer
class ReaderSerializer(serializers.ModelSerializer):
class Meta:
model = Reader
fields = '__all__'
Both author and reader table has a one-to-one relationship towards profile table.
Depending on the role option I would like to show a specific nested serializer.
Example:
{
"id": 19,
"username": "maoji1",
"password": "pbkdf2_sha256$180000$YhzDiqzJ4OyC$syzkwR5X3/H2p5NTB0JEK2zS5nvYu5ddHrTgy3cYU/E=",
"email": "pbkdf2_sha256$180000$YhzDiqzJ4OyC$syzkwR5X3/H2p5NTB0JEK2zS5nvYu5ddHrTgy3cYU/E=",
"profile": {
"gender": "male",
"birthday": "2020-03-10",
"icon": null,
"role": {
is_vip:True,
validate_date:...
}
}
}
Reader model
class Reader(models.Model):
user = models.OneToOneField(Profile, on_delete=models.CASCADE, related_name='reader', verbose_name='user')
is_user_vip = models.CharField(choices=(('normal', u'Normal'), ('vip', u'VIP')),
default='normal',
max_length=10,
verbose_name=u'Vip status')
vip_validate = models.DateField(verbose_name=u"Validate Until",
auto_now_add=True, null=True,
editable=False)
Author model
class Author(models.Model):
user = models.OneToOneField(Profile, on_delete=models.CASCADE, related_name='author')
book = models.ForeignKey(Book, on_delete=models.CASCADE, related_name='Book', null=True)
contract_number = models.IntegerField(verbose_name='Contact number', null=True, blank=True)
Profile model
class Profile(models.Model):
role_choice = (
('Reader', u'Reader'),
('Author', u'Author'),
('Editor', u'Editor'),
('Admin', u'Admin')
)
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile', verbose_name='user')
gender = models.CharField(choices=(("male", u"Male"), ("female", u"Female")),
default="Female",
max_length=150, verbose_name='Gender')
birthday = models.DateField(null=True, blank=True, verbose_name="Birthday")
icon = models.ImageField(upload_to="media/image/%Y/%m",
default=u"media/image/default.png",
max_length=1000,
verbose_name=u"User icon", null=True)
role = models.CharField(choices=role_choice,
max_length=150,
default='Admin',
verbose_name='Role')
You can use SerializerMethodField and decide which serializer you must use inside it's method:
class UserSerializer(serializers.ModelSerializer):
profile = serializers.MethodField()
class Meta:
model = Profile
fields = ('id', 'username', 'password', 'email','profile')
def get_profile(self,obj):
return ProfileSerializer(obj.profile).data
class AuthorSerializer(serializers.ModelSerializer):
class Meta:
model = Author
fields ='__all__'
class ReaderSerializer(serializers.ModelSerializer):
class Meta:
model = Reader
fields ='__all__'
class ProfileSerializer(serializers.ModelSerializer):
role = serializers.MethodField()
class Meta:
model = Profile
fields = ('gender', 'birthday', 'icon', 'role')
def get_role(self,obj):
if hasattr(obj, 'author')
serializer = AuthorSerializer(obj.author)
return serializer.data
elif hasattr(self,'reader'):
serializer = ReaderSerializer(obj.reader)
return serializer.data
return {} # if your profile doesn't have any relation with author or reader
class UserSerializer(serializers.ModelSerializer):
profile = serializers.MethodField()
class Meta:
model = User
fields = ('id', 'username', 'password', 'email','profile')
def get_profile(self,obj):
return ProfileSerializer(obj.profile).data
I have the following object inheritance model.
class Room:
name = models.CharField(db_index=True, unique=True, max_length=255)
status = models.CharField(default=RoomStatus.ACTIVE, max_length=256, null=True)
members = models.ManyToManyField(User)
last_activity = models.DateTimeField(default=timezone.now)
And the inherited models are,
class LeagueRoom(Room):
league = models.ForeignKey(League, on_delete=models.CASCADE, null=True)
location = models.ForeignKey(Location, on_delete=models.CASCADE, null=True)
logo_url = models.CharField(max_length=1024, null=True)
and
class ClubRoom(Room):
club = models.ForeignKey(Club, on_delete=models.CASCADE, null=True)
location = models.ForeignKey(Location, on_delete=models.CASCADE, null=True)
logo_url = models.CharField(max_length=1024, null=True)
The respective Serializers are as follows,
class RoomSerializer(serializers.ModelSerializer):
members = UserSerializer(read_only=True, many=True)
class Meta:
model = Room
fields = ('id', 'name', 'status', 'members', 'created', 'modified', 'last_active')
and
class LeagueRoomSerializer(serializers.ModelSerializer):
location = LocationSerializer(read_only=True)
league = LeagueSerializer(read_only=True)
room = RoomSerializer(read_only=True)
class Meta:
model = LeagueRoom
fields = ('id', 'name', 'location', 'status', 'league',
'logo_url', 'room', 'created', 'modified',)
and
class ClubRoomSerializer(serializers.ModelSerializer):
location = LocationSerializer(read_only=True)
club = ClubSerializer(read_only=True)
room = RoomSerializer(read_only=True)
class Meta:
model = ClubRoom
fields = ('id', 'name', 'location', 'club', 'logo_url',
'status', 'room', 'created', 'modified',)
My problem is that I have fetched all rooms for an user in the following manner.
rooms = user.room_set.order_by('-last_activity')
Now I want to Serialize this data based on the room type. Thus instead of using the RoomSerializer I want to traverse the list of rooms and if the room is ClubRoom, then use ClubRoomSerializer or else LeagueRoomSerializer.
I'm not sure how to determine the child object from the parent.
Can someone help me with this.
class RoomSerializer(serializers.Serializer):
def to_representation(self, instance):
if isinstance(instance, LeagueRoom)
serializer_class = LeagueRoomSerializer
elif isinstance(instance, ClubRoom):
serializer_class = ClubRoomSerializer
return serializer_class(instance=instance).data
queryset = user.room_set.order_by('-last_activity')
serialized = RoomSerializer(queryset, many=True).data
I was trying to add new relation to many to many records,
for example i have these models:
models.py
class Team(models.Model):
name = models.CharField(blank=True, unique=True, max_length=100)
players = models.ManyToManyField(User, blank=True, related_name='players')
class TeamInvite(models.Model):
from_user = models.ForeignKey(User, on_delete=models.DO_NOTHING, related_name='invite_by', blank=True, null=True)
to_user = models.ForeignKey(User, on_delete=models.DO_NOTHING, related_name='invite_to', blank=True, null=True)
team = models.ForeignKey(Team, on_delete=models.CASCADE, related_name='invite_to_team', blank=True, null=True)
status = models.NullBooleanField(blank=True, null=True, default=None,)
and my serializer:
serializers.py
class TeamInviteCreateSerializer(serializers.ModelSerializer):
team = serializers.PrimaryKeyRelatedField(queryset=Team.objects.all())
from_user = serializers.PrimaryKeyRelatedField(queryset=User.objects.all())
class Meta:
model = TeamInvite
fields = ('id', 'from_user', 'to_user', 'team', 'status')
after that the user which in to_user will take an action to TeamInvite like accept or decline.
I need the serializer which will take the new user and add him to the existing team like the following serializer:
class TeamInviteAcceptDeclineSerializer(serializers.ModelSerializer):
method_name = serializers.SerializerMethodField()
class Meta:
model = TeamInvite
fields = ('id', 'from_user', 'date_time', 'team', 'method_name', 'status')
def get_method_name(self, *args, **kwargs):
method_name = None # kwargs['context']['request'].method_name
return method_name
def update(self, instance, validated_data):
instance.team = validated_data.get('team', instance.team)
method_name = validated_data.get('method_name')
instance.status = validated_data.get('status', instance.status)
instance.to_user = validated_data.get('to_user', instance.to_user)
if method_name == 'decline':
instance.status = False
else:
instance.status = True
team = Team.objects.get(pk=instance.team.pk)
team.players.add(instance.to_user)
# team.players.create(team_id=team, user_id=instance.to_user)
team.save()
instance.save()
return instance
update function does not add the user to existing team and doesn't raise any error either. What am i missing here?
my request was:
{
"from_user": 1,
"to_user": 23
"team": 64,
"method_name": "accept",
"status": null
}
thank you
I got the missing point in my code..
it was in:
class TeamInviteAcceptDeclineSerializer(serializers.ModelSerializer):
method_name = serializers.SerializerMethodField()
class Meta:
model = TeamInvite
fields = ('id', 'from_user', 'date_time', 'team', 'method_name', 'status')
fields = missed 'to_user' pram
I have a model named tranasaction.
class transactions(models.Model):
id = models.AutoField(primary_key=True)
date = models.DateTimeField(default=datetime.now, blank=True)
saleduser = models.ForeignKey('UserData',on_delete=models.CASCADE, related_name='vclouduser_data', blank=True, null=True)
brand = models.CharField(max_length=50,blank=True)
type = models.CharField(max_length=50,blank=True)
quantity = models.DecimalField(blank=True,null=True,max_digits=20,decimal_places=2)
amount = models.DecimalField(blank=True,null=True,max_digits=20,decimal_places=2)
And I need to create a summary report,
so I create a new Model.
class SaleSummary(transactions):
class Meta:
proxy = True
verbose_name = 'Sale Summary'
verbose_name_plural = 'Sales Summary'
what i need that i need to get the total amount of each type as a new model.
please help me to solve this.
Thanks in advance.
Here is an example of a proxy model for a normal model, with a filtering example. I hope it will be helpful for you that how can you create the proxy model and how can you filter specific data from any model for the admin site. You also can apply this for your custom API response, Then you should write this code in serializers. Best of luck.
models.py
class UserModel(AbstractBaseUser):
"""
Purpose: create a custom auth user table
"""
name = models.CharField('name of user',max_length=256)
email = models.EmailField('email address', unique=True)
date_joined = models.DateTimeField('user creation date', auto_now_add=True)
is_admin = models.BooleanField('is a admin', default=False)
is_staff = models.BooleanField('is a staff', default=False)
is_superuser = models.BooleanField('if a superuser', default=False)
status = models.ForeignKey(SesameUserStatus, on_delete = models.CASCADE, related_name='sesame_user_status_type', default=2)
organization = models.ForeignKey(Organization, on_delete = models.CASCADE, related_name='sesame_user_organization_info', default=1)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['name']
def has_perm(self,prm,obj=None):
return self.is_active and self.is_admin
def has_module_perms(self,app_level):
return self.is_active and self.is_admin
def __str__(self):
return f'{self.name} // {self.email} // {self.organization.name}'
class Meta:
verbose_name = "User"
verbose_name_plural = "Users"
indexes = [
models.Index(fields=['email']),
]
class UserProxyModel(UserModel):
"""
Purpose: create proxy model to visualize only pending user
"""
class Meta:
proxy = True
verbose_name = "Pending User"
verbose_name_plural = "Pending Users"
###########################################################################
admin.py
class UserAdmin(admin.ModelAdmin):
list_display = ['id', 'name', 'email', 'date_joined', 'is_admin', 'is_staff']
class Meta:
model = UserModel
class UserProxyModelAdmin(admin.ModelAdmin):
list_display = ['id', 'name', 'email', 'date_joined', 'is_admin', 'is_staff', 'organization', 'status']
def get_queryset(self, request):
qs = super().get_queryset(request)
if request.user.is_superuser:
return qs.filter(status=SESAME_USERS["status"]["PENDING"]).order_by('id')
return None
class Meta:
model = UserProxyModel
admin.site.register(UserModel, UserAdmin)
admin.site.register(UserProxyModel, UserProxyModelAdmin)
I have the following User,
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True, max_length=255)
username = models.CharField(null=False, unique=True, max_length=255)
full_name = models.CharField(max_length=255, blank=True, null=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_active = models.BooleanField(default=False)
And the following UserProfile model,
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, )
level = models.CharField(default="Noob", max_length=255)
reputation = models.IntegerField(default=0)
status = models.CharField(max_length=255, null=True, blank=True)
The User has a one to one relationship with Profile.
This is the UserSerializer,
class UserSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True)
location = LocationSerializer(read_only=True)
profile = UserProfileSerializer(read_only=True)
class Meta:
model = models.User
fields = (
'id', 'email', 'mobile', 'username', 'full_name', 'password', 'is_active', 'profile',
)
And this is the profile serializer.
class UserProfileSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserProfile
fields = ('level', 'reputation', 'status',)
The issue is that in the serialized output for the user there is no nested profile data. How do I fix this. Any help appreciated.
all you need is set source for profile:
class UserSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True)
location = LocationSerializer(read_only=True)
profile = UserProfileSerializer(source='userprofile', read_only=True)
the userprofile is name of relation of your model User by onetoone to the UserProfle, other way you can set related_name for attribute user in the
UserProfle.
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='profile', on_delete=models.CASCADE)
then your serializer will work fine as is.