How to access reversed relationship using Django rest framework - python

Here are my models :
class Profile(models.Model):
user = models.ForeignKey(User, related_name="profile", on_delete=PROTECT)
plan = models.ForeignKey(Plans, on_delete=PROTECT)
full_name = models.CharField(max_length=2000)
company_name = models.CharField(max_length=50, null=True, blank=True)
activation_token = models.UUIDField(default=uuid.uuid4)
activated = models.BooleanField(default=False)
thumb = models.ImageField(upload_to='uploads/thumb/', null=True, blank=True)
renew_data = models.DateField()
is_paid = models.BooleanField(default=False)
And as you see the Profile model have user field that is related to the Abstract user of django framework. now here is how i call them using an API :
Serializers
class ProfileSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Profile
fields = ['company_name']
class UserSerializer(serializers.HyperlinkedModelSerializer):
profile_set = ProfileSerializer(
read_only=True, many=True) # many=True is required
class Meta:
model = User
depth = 1
fields = ['username', 'id', 'profile_set']
But when I call the API it shows only the fields username and 'id but not the profile_set

Your UserSerializer should like this,
class UserSerializer(serializers.HyperlinkedModelSerializer):
# no need to set `profile.all` as you have related name profile defined in your model
profile_set = ProfileSerializer(source='profile', many=True)
class Meta:
model = User
depth = 1
fields = ['username', 'id', 'profile_set']
OR,
class UserSerializer(serializers.HyperlinkedModelSerializer):
profile = ProfileSerializer(many=True) # as you have related name `profile`
class Meta:
model = User
depth = 1
fields = ['username', 'id', 'profile']

Try setting the source of your serializer:
profile_set = ProfileSerializer(
source='profile.all',
read_only=True, many=True
)

It looks like you've set the related_name on your foreign key:
user = models.ForeignKey(User, related_name="profile", on_delete=PROTECT)
This defines the reverse relation name, so that's how you need to refer to it in DRF, too:
class UserSerializer(serializers.HyperlinkedModelSerializer):
profile = ProfileSerializer(read_only=True, many=True)
class Meta:
model = User
depth = 1
fields = ['username', 'id', 'profile']
Since it's clearly a plural, I'd also suggest you rename profile to profiles.

Related

how to serialize two classes have one to many relation in django

this is my models
class Users(models.Model) :
name = models.CharField(max_length=20 , blank=False , null=False)
email = models.EmailField(max_length=50 , blank=True , null=True)
password = models.CharField(max_length=30 , blank=False , null=False)
birthday = models.DateField(null=False)
photo = models.ImageField(upload_to = 'user_photos/%y/%m/%d')
#friend = models.ManyToManyField('self',through='Notif',null=True,related_name='friend')
class Product(models.Model):
pub_date = models.DateTimeField(default=datetime.now)
price = models.DecimalField(max_digits=100000,decimal_places=5,null=False,blank=False)
size = models.IntegerField(null=True,blank=True,default='undefined')
photo = models.ImageField(upload_to = 'product_photos/%y/%m/%d',null=True)
#for 1--n relation with users
user_id = models.ForeignKey(Users,on_delete=models.CASCADE,null=True,related_name='user')
this is my serializers.py
class ProductSerializer (serializers.ModelSerializer):
class Meta :
model = Product
fields = '__all__'
class UsersSerializer(serializers.ModelSerializer):
class Meta:
model = Users
fields = '__all__'
i want to send product object with the email of his user
what i have to do in serializers and views to make it
note i use function based views in my views
First of all, you should change user_id to user.
in serializers.py
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = Users
fields = ['id','email']
class ProductSerializer(serializers.ModelSerializer):
user = UserSerializer(read_only=True)
class Meta :
model = Product
fields = '__all__'
in function based views:
def get_product(request,product_id):
instance = Product.objects.select_related('user').get(id=product_id)
serializer = ProductSerializer(instance)
return Response(serializer.data)
NOTE: select_related is used to get product with user at the same query (join query).

Django error while serializing image model of child field

I am new to this tech, while working on django project i got some issues when i try to serialize Ticket's account.profile_pic
models.py
class Account(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE
profile_pic = models.ImageField(upload_to='images/profile_pics/', blank=True, null=True)
created_at = models.DateTimeField(auto_now_add=True)
class Ticket(models.Model):
author = models.ForeignKey(Account, on_delete=models.CASCADE)
descr = models.TextField(blank=False, null=False)
likes = models.ManyToManyField(User)
serializers.py
class DetailedTicketSerializer(serializers.ModelSerializer):
# Error occurs on below line: No file associated with ImageField
author_profile_pic = serializers.ReadOnlyField(source='author.profile_pic')
author_username = serializers.ReadOnlyField(source='author.user.username')
class Meta:
model = Ticket
fields = ['id', 'author_profile_pic', 'author_username', 'likes', 'descr']
Anyone knows how do i serialize Account.profile_pic's url???
serialize the account class. in your ticketserializer call the account serializer.
Here an example:
class
HobbySerializer(serializers.ModelSerializer):
class Meta:
model = Hobby
fields = '__all__'
class ProfileSerializer(serializers.ModelSerializer):
user_hobby = HobbySerializer(many=True)
class Meta:
model = Profile
fields = '__all__'

pass user data to serializer in nested serializers when creating object in django rest framework

When User tries to add an Announcement, should i pass all the informations of the user in the form ?
i'm using token authentification.
So for adding an Announcement the user must be authenticated.
Models.py
class User(AbstractUser):
username = None
email = models.EmailField(max_length=100, verbose_name='email',
unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = UserManager()
class Announcement(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=100)
photo = models.ManyToManyField(Photo, blank=True)
class Photo(models.Model):
name = models.CharField(max_length=100)
content_type = models.CharField(max_length=100)
path = models.CharField(max_length=100)
class Parameter(models.Model):
name = models.CharField(max_length=100)
value = models.FloatField(blank=True, null=True)
announcement = models.ForeignKey(
Announcement,related_name='parameters', on_delete=models.CASCADE)
Serializers.py
class AnnouncementSerializer(serializers.ModelSerializer):
author = UserSerializer(required=True)
parameters = ParameterSerializer(many=True,
required=False)
photo = PhotoSerializer(many=True,
required=False)
class Meta:
model = Announcement
fields = ['id', 'name', 'author',
'parameters', 'photo']
class UserSerializer(serializers.ModelSerializer):
photo = PhotoSerializer()
class Meta:
model = User
fields = ['id', 'email','photo', ]
class ParameterSerializer(serializers.ModelSerializer):
class Meta:
model = Parameter
fields = '__all__'
class PhotoSerializer(serializers.ModelSerializer):
class Meta:
model = Photo
fields = '__all__'
Views.py
class AnnouncementCreate(CreateAPIView):
permission_classes = [IsAuthenticated]
queryset = models.Announcement.objects.all()
serializer_class = AnnouncementSerializer
When trying the browsable API. to create a new announcement i have to enter all the informations of the user. But if the user is already authenticated. is there any solution to create the announcement for only this user and show it to the other users ?
If you don't want to create a User when creating an Announcement, omit the author field from your AnnouncementSerializer, then pass the current user when saving serializer object:
serializer.py
class AnnouncementSerializer(serializers.ModelSerializer):
parameters = ParameterSerializer(many=True, required=False)
photo = PhotoSerializer(many=True, required=False)
class Meta:
model = Announcement
fields = ['id', 'name', 'parameters', 'photo']
views.py
class AnnouncementCreate(CreateAPIView):
permission_classes = [IsAuthenticated]
queryset = models.Announcement.objects.all()
serializer_class = AnnouncementSerializer
def perform_create(self, serializer):
serializer.save(author=self.request.user)

I cannot register a user using Django-Rest-Framework

I can't add a new user using Django Rest Framework. Here is my code from models.py:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
password = models.CharField(max_length=15, default= None)
first_name = models.CharField(max_length=100, validators=[name_validator])
last_name = models.CharField(max_length=100, validators=[name_validator])
email = models.CharField(max_length=100, validators=[mail_validator])
created_at = models.DateTimeField(auto_now_add=True)
As you can see I am using models.OneToOneField cause I want to extend the default user to add some more fields.
Bellow is my serializers.py file:
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
permissions_classes = [
permissions.AllowAny
]
fields = '__all__'
The viewset is the following:
class UserViewset(viewsets.ModelViewSet):
queryset = Profile.objects.all()
serializer_class = ProfileSerializer
When I go to my endpoints and try to add a new user, I cannot put anything in the "user" field:
Click for image
I am a beginner and it would be of great help.
Thank you!
you can to this
from django.contrib.auth.models import User
class Profile(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
password = models.CharField(max_length=15, default= None)
first_name = models.CharField(max_length=100, validators=[name_validator])
last_name = models.CharField(max_length=100, validators=[name_validator])
email = models.CharField(max_length=100, validators=[mail_validator])
created_at = models.DateTimeField(auto_now_add=True)
serializer.py
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = "__all__"
class ProfileSerializer(serializers.ModelSerializer):
user = UserSerializer(read_only=True)
class Meta:
model = Profile
fields = '__all__'
views.py
class UserViewset(viewsets.ModelViewSet):
queryset = Profile.objects.all()
serializer_class = ProfileSerializer
permission_classes = [permission. AllowAny,]
When you want to extend the default user to add some more fields, the best way for that is substituting a custom User model by inheritance the AbstractUser model. Using this way, you can CRUD the user easily.

Django Rest - Serializer: must be a instance on create

I'm trying to create create a nested serializer using the Django Rest framework. The relationship is Profile X User but when i use Profile.objects.create(user=profile, **user_data) i get ValueError: Cannot assign "<Profile: Profile object (7)>": "Profile.user" must be a "User" instance..
This should be some rookie misunderstanding of models relationship definitions or the serializer declaration itself but I can't find anything around the docs. If someone can point me a direction I'll be gracefull.
models.py
class User(models.Model):
name = models.CharField(max_length=100, blank=False)
email = models.CharField(max_length=100, blank=True, default='')
password = models.CharField(max_length=100, blank=True, default='')
timestamp = models.DateTimeField(default= timezone.now)
class Meta:
ordering = ['timestamp']
class Profile(models.Model):
# choices [...]
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True)
profile_type = models.CharField(max_length=2,choices=PROFILE_CHOICES,default=TEAMMEMBER)
authentication_token = models.CharField(max_length=100, null=True)
avatar_url = models.CharField(max_length=100, default='')
permissions = models.CharField(max_length=100, null=True)
timestamp = models.DateTimeField(default= timezone.now)
class Meta:
ordering = ['timestamp']
serializer.py
class UserSerlializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['name', 'email', 'password']
class ProfileSerializer(serializers.ModelSerializer):
user = UserSerlializer()
class Meta:
model = Profile
fields = ['user', 'profile_type']
def create(self, validated_data):
user_data = validated_data.pop('user')
profile = Profile.objects.create(**validated_data)
Profile.objects.create(user=profile, **user_data)
return Profile
POST
{
"profile_type" : "ST",
"user": {
"name" : "test",
"email" : "test#test.com",
"password" : "123456"
}
}
You are creating instances in wrong way. Change your create(...) method as,
class ProfileSerializer(serializers.ModelSerializer):
user = UserSerlializer()
class Meta:
model = Profile
fields = ['user', 'profile_type']
def create(self, validated_data):
user_data = validated_data.pop('user')
user_instance = User.objects.create(**user_data)
profile_instance = Profile.objects.create(user=user_instance, **validated_data)
return profile_instance
Profile.user should beUser instance, but you are assigning Profile instance.
Change your create method to this:
class ProfileSerializer(serializers.ModelSerializer):
user = UserSerlializer()
class Meta:
model = Profile
fields = ['user', 'profile_type']
def create(self, validated_data):
user_data = validated_data.pop('user')
profile = Profile.objects.create(**validated_data)
user = User.objects.create(**user_data) # 1. creating user
profile.user = user # 2. assigning user
profile.save() # 3. saving profile after adding user
return profile # returning Profile instance.
inherit your user model from django contrib auth module also, and make a one to one relation with profile
from django.contrib.auth.models import User

Categories

Resources