Django test: Residence() got an unexpected keyword argument 'hotel_id' - django

class Hotel (models.Model):
name = models.CharField()
country = models.CharField()
city = models.CharField()
street = models.CharField()
class Residence(models.Model):
hotel_id = models.ForeignKey(Hotel, on_delete=models.DO_NOTHING, related_name='hotel')
house_number = models.CharField()
I want to join two models (Hotel and Residence) and then post it. I wrote the folowing code:
serializers.py
class HotelSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Hotel
fields = ['name', 'country', 'city', 'street']
class ResidenceSerializer(serializers.HyperlinkedModelSerializer):
hotel_id = HotelSerializer()
class Meta:
model = Residence
fields = ['house_number', 'hotel_id']
def create(self, validated_data):
return Residence.objects.create(**validated_data)
views.py
class ResidenceViewSet(viewsets.ModelViewSet):
serializer_class = ResidenceSerializer
queryset = Residence.objects.all()
When I try to post data in my api I got the following error: Residence() got an unexpected keyword argument 'hotel_id'. Can someone help me?

Replacing hotel_id with hotel. And still, you can pass hotel from view
class ResidenceSerializer(serializers.HyperlinkedModelSerializer):
hotel = HotelSerializer()
class Meta:
model = Residence
fields = ['house_number', 'hotel']
Also if you are not interested in hyper links(urls) then replace
`serializers.HyperlinkedModelSerializer` with `serializers.ModelSerializer`.
Difference between HyperlinkedModelSerializer and ModelSerializer is serializer is posted here by Serjik
A simple example:
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ('url', 'username', 'email', 'groups')
class GroupSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Group
fields = ('url', 'name')
bash> http -a admin:yourpassword http://127.0.0.1:8000/users/
"results": [
{
"email": "admin#min.com",
"groups": [
"http://127.0.0.1:8000/groups/1/",
"http://127.0.0.1:8000/groups/2/"
],
"url": "http://127.0.0.1:8000/users/1/",
"username": "admin"
}
]
But if you change
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('url', 'username', 'email', 'groups')
The result will be:
"results": [
{
"email": "admin#min.com",
"groups": [
1,
2
],
"url": "http://127.0.0.1:8000/users/1/",
"username": "admin"
}
]

Related

I want to retrieve related fields as JSON format using Rest

I want to retrieve Student user fields, but I am having a hard time
trying to figure out how to do that I tried reading docs but still
confused
Studentserializer
class StudentSerializer(serializers.Serializer):
class Meta:
model = Student
fields = ['id', 'user', 'name', 'course']
def create(self, validated_data):
Student_det = Student.objects.create(**validated_data)
return Student_det
serializer view
def Student_list(request):
if request.method == 'GET':
stud = Student.objects.all()
serialized = StudentSerializer(stud, many=True)
print(serialized.data)
return JsonResponse(serialized.data, safe=False)
Student Model
class Student (models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
name = models.CharField(max_length=255)
course = models.CharField(max_length=255)
You can check here. I think the part about nested serializers is what you need.
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ("id", "first_name", "last_name", ) # and you can add other fields here "email", "date_joined", etc.
class StudentSerializer(serializers.ModelSerializer):
user = UserSerializer()
class Meta:
model = Student
fields = ("id", "user", "name", "course", )
This will serialize your Student model like
{
"id": 1,
"user": {
"id": 1,
"first_name": "Example",
"last_name": "User"
}
"name": "student name",
"course": "course name"
}

How to add data from one model to other django?

I am using generics to represent views
class PersonRetrieveView(generics.ListAPIView):
queryset = Person.objects.all()
serializer_class = PersonSerializer
and
class CommentRetrieveView(generics.RetrieveAPIView):
queryset = Comment.objects.all()
serializer_class = CommentSerializer
Person data looks like
{
"id": 2,
"user": {
"first_name": "Testuser",
"last_name": "TestUser1",
"id": 2
},
"name": "Test 2",
"city": "California",
"status": "NotActive",
"phone_number": "9876543222",
"age": 22,
"height": 180
}
and Comment
{
"id": 1,
"comment": "test",
"person": 2
}
Comment linked to Person by id. How can i add data from comment to PersonRetrieveView ?
Serializers looks like this
class PersonSerializer(serializers.ModelSerializer):
user = UserSerializer()
# comment = CommentSerializer()
class Meta:
model = Person
fields = '__all__'
class CommentSerializer(serializers.ModelSerializer):
class Meta:
model = Comment
fields = '__all__'
Model looks like
class Person(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=20)
city = models.CharField(max_length=20)
status = models.CharField(max_length=9, default='NotActive')
phone_number = models.CharField(max_length=10)
class Comment(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
comment = models.CharField(max_length=255)
You have Many-to-one relationship and you did not set related_name on Foreign key so your comments are accessible through comment_set which can be used to nest serializer
class PersonSerializer(serializers.ModelSerializer):
user = UserSerializer()
comments = CommentSerializer(source='comment_set', many=True)
class Meta:
model = Person
fields = [ 'user', 'city', 'comments', ...]
Provided that your Person model has a relation to Comment models, simply add depth = 1 in your Person serializer as follows:
class PersonSerializer(serializers.ModelSerializer):
user = UserSerializer()
class Meta:
model = Person
fields = '__all__'
depth = 1

Django REST framework reverse relationship object instance

Let's say that we have models like below
class Movie(models.Model):
"""Stores a single movie entry."""
title = models.CharField(max_length=200, blank=False)
class Watchlist(models.Model):
"""Stores a user watchlist."""
user = models.ForeignKey(settings.AUTH_USER_MODEL,
related_name='watchlist',
on_delete=models.CASCADE)
movie = models.ForeignKey(Movie, related_name='watchlist',
on_delete=models.CASCADE)
added = models.BooleanField(default=False)
Serializer
class CustomUserSerializer(serializers.HyperlinkedModelSerializer):
"""Serializer for a custom user model with related user action."""
url = serializers.HyperlinkedIdentityField(
view_name='customuser-detail', lookup_field='username')
watchlist = serializers.HyperlinkedRelatedField(
many=True, view_name='watchlist-detail', read_only=True)
class Meta:
model = CustomUser
fields = ('url', 'username', 'watchlist')
and the view:
class CustomUserViewSet(viewsets.ReadOnlyModelViewSet):
"""
list:
Return a list of all the existing users.
retrieve:
Return the given user with user's watchlist.
"""
queryset = CustomUser.objects.all()
permissions = (IsAdminOrReadOnly)
lookup_field = 'username'
serializer_class = CustomUserSerializer
That all will give us a user and hyperlinked filed to the particular watchlist.
{
"url": "http://127.0.0.1:8000/api/v1/users/John/",
"username": "John",
"favorites": [
"http://127.0.0.1:8000/api/v1/watchlist/2/",
"http://127.0.0.1:8000/api/v1/watchlist/1/"
]
},
but instead of that I would like to get a particular movie instance like that.
{
"url": "http://127.0.0.1:8000/api/v1/users/John/",
"username": "John",
"favorites": [
"http://127.0.0.1:8000/api/v1/movies/33/",
"http://127.0.0.1:8000/api/v1/movies/12/"
]
},
so my question is how can I achieve that? I tried with hyperlinkedrelatedfield but nothing seems to work as expected.
You could use the SerializerMethodField along with reverse.
from rest_framework.reverse import reverse
class CustomUserSerializer(serializers.HyperlinkedModelSerializer):
"""Serializer for a custom user model with related user action."""
url = serializers.HyperlinkedIdentityField(
view_name='customuser-detail', lookup_field='username')
favorites = serializers.SerializerMethodField()
def get_favorites(self, obj):
movie_urls = [
reverse("movie-view", args=[watchlist.movie.id], request=self.context['request'])
for watchlist in obj.watchlist.all()
]
return movie_urls
class Meta:
model = CustomUser
fields = ('url', 'username', 'favorites')

Django Rest Api - display the username for every user

So I have a model called 'Task' and the task has 'UserProfile's working on them. These 'UserProfile' models are just normal Users but inside the App of the 'Task'.
This is the API I have right now:
"tasks": [
{
"id": 1,
"name": "Läs På Internet",
"description": "asdasdasdasa",
"created": "2019-06-08",
"deadline": "2019-06-19",
"state": "new",
"stickers": [
{
"id": 1,
"name": "Detta är en sticker",
"content": "Sillicon Valley",
"created": "2019-06-08",
"creator": {
"id": 1,
"user": 1
}
}
],
"checkmarks": [
{
"id": 1,
"name": "Googla",
"checked": false
}
],
"workers": [
{
"id": 1,
"user": 1
}
]
},
{
"id": 2,
"name": "Läs i böcker",
"description": "aaa",
"created": "2019-06-10",
"deadline": "2019-06-25",
"state": "done",
"stickers": [],
"checkmarks": [],
"workers": [
{
"id": 1,
"user": 1
}
]
}
],
As you can see every user now just has 'id' and 'user', which are both the ID. How do I get the username for every user and display them in the rest api?
# Users
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
class Meta:
verbose_name_plural = 'All Users'
def __str__(self):
return self.user.username
#receiver(post_save, sender=User)
def create_user_data(sender, update_fields, created, instance, **kwargs):
if created:
user = instance
profile = UserProfile.objects.create(user=user)
#Tasks
class Task(models.Model):
name = models.CharField(max_length=200)
description = models.CharField(max_length=2000)
created = models.DateField(default=date.today)
deadline = models.DateField(default=date.today)
state = models.CharField(max_length=20, default='new')
stickers = models.ManyToManyField(Sticker, blank=True)
checkmarks = models.ManyToManyField(Checkmark, blank=True)
workers = models.ManyToManyField(UserProfile, blank=True, related_name='TaskWorkers')
class Meta:
verbose_name_plural = 'Tasks'
def __str__(self):
return "{name}".format(name=self.name)
serializers:
class UserProfileSerializer(serializers.ModelSerializer):
class Meta:
model = UserProfile
fields = ('id', 'user')
class TaskSerializer(serializers.ModelSerializer):
stickers = StickerSerializer(many=True, read_only=True)
checkmarks = CheckmarkSerializer(many=True, read_only=True)
workers = UserProfileSerializer(many=True, read_only=True)
class Meta:
model = Task
fields = ('id', 'name', 'description', 'created', 'deadline', 'state', 'stickers', 'checkmarks', 'workers')
views:
class TaskView(viewsets.ModelViewSet):
http_method_names = ['get', 'post', 'put', 'delete', 'patch']
queryset = Task.objects.all()
serializer_class = TaskSerializer
class UserTaskView(TaskView):
def get_queryset(self):
return Task.objects.filter(workers__user=self.request.user)
The User Views are for displaying only for the users that are assigned!
You can either update the user serializer inside your UserProfileSerializer with something like this (creating a serializer with the fields you want for the User):
class UserProfileSerializer(serializers.ModelSerializer):
user = UserSerializer()
class Meta:
model = UserProfile
fields = ('id', 'user')
or this (accessing user fields from within the UserProfileSerializer):
class UserProfileSerializer(serializers.ModelSerializer):
username = serializers.CharField(source='user.username')
class Meta:
model = UserProfile
fields = ('id', 'user', 'username')
As documented below in
https://www.django-rest-framework.org/api-guide/serializers/#writable-nested-representations
You can get the user profile details inside the tasks as:
class TaskSerializer(serializers.ModelSerializer):
......
user = UserSerializer()
class Meta:
model = Task
fields = (...., 'user',....., 'workers')
This will return all the fields in the the user model as part of the task nested json

Django rest framewor deal with many=True serializer data to list

I get data like this.
{
"id": 1,
"fields": [
{"id": 1, "name": "att1"},
{"id": 2, "name": "att2"}
]
}
And I need fields without keys like fields: ["att1", "att2"].
I could use SerializerMethod do this. Is there some method like source='form.fields.name'?
CharField(source='form.fields.name') not work with many=True objects.
Code:
class EavForm(models.Model):
name = models.CharField(max_length=300)
class EavAttribute(models.Model):
form = models.ForeignKey(EavForm, on_delete=models.CASCADE, related_name='fields')
name = models.CharField(max_length=300)
class EavAttributeSerializer(serializers.ModelSerializer):
class Meta:
model = EavAttribute
fields = '__all__'
class EavFormSerializer(serializers.ModelSerializer):
fields = EavAttributeSerializer(many=True)
class Meta:
model = EavForm
fields = '__all__'
I have a EavValue object related_to EavForm. How get fields like eav_value_obj.fields as a list?
class EavValue(models.Model):
form = models.ForeignKey(EavForm, on_delete=models.CASCADE, related_name='values')
fields = serializers.SlugRelatedField(
many=True,
read_only=True,
slug_field='form.fields.name' # not work like this.
)
You can use SlugRelatedField:
class EavFormSerializer(serializers.ModelSerializer):
fields = serializers.SlugRelatedField(
many=True,
read_only=True,
slug_field='name'
)
class Meta:
model = EavForm
fields = '__all__'