I get some troubles with post and save serializer - python

serializers.py:
class SnippetSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')
class Meta:
model = Snippet
fields = ('id', 'title','owner', 'code', 'linenos', 'language', 'style')
def create(self, validated_data):
owner=validated_data.pop('owner')
try:
owner=User.objects.get(username=owner)
snippet=Snippet.objects.create(owner=owner,**validated_data)
return snippet
except:
return Http404
view.py:
class SnippetList(APIView):
"""
List all snippets, or create a new snippet.
"""
permission_classes = (permissions.IsAuthenticatedOrReadOnly,IsOwnerOrReadOnly,)
def get(self, request, format=None):
snippets = Snippet.objects.all()
serializer = SnippetSerializer(snippets, many=True)
return Response(serializer.data)
def post(self, request, format=None):
data=request.data
data['owner']=request.user
serializer = SnippetSerializer(data=data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Models:
class Snippet(models.Model):
created = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=100, blank=True, default='')
code = models.TextField()
linenos = models.BooleanField(default=False)
language = models.CharField(choices=LANGUAGE_CHOICES, default='python', max_length=100)
style = models.CharField(choices=STYLE_CHOICES, default='friendly', max_length=100)
owner = models.ForeignKey(User)
highlighted = models.TextField()
Post data:
{
"title": "dfhhtryres",
"owner": "admin",
"code": "hfdsadfghdfh",
"linenos": false,
"language": "python",
"style": "friendly"
}
Error: KeyError at /snippets/ 'owner'

Related

Django Rest Framework: How to request data validate before serializers?

I want to validate email variable before UserSerializer, and then return filtered data. The following code works; but I declared "serializer" twice. If I want to use serializer once, how can I do it?
views.py
#api_view(['GET'])
def get_user(request):
email = request.data.get('email')
serializer = UserSerializer(data=request.data)
if serializer.is_valid():
Users = User.objects.filter(email=email)
serializer = UserSerializer(Users, many= True)
return Response({"status": "success", "data": serializer.data})
else:
return Response({"status": "errors", "data": serializer.errors})
serializers.py
class UserSerializer(serializers.ModelSerializer):
email = serializers.EmailField(required=True)
phone = serializers.CharField(required=False)
sex = ChoiceField(required=False, choices=User.TYPE_CHOICES)
class Meta:
model = User
fields = ('id', 'email', 'phone', 'name','sex', 'updated', 'created')
models.py
class User(models.Model):
TYPE_CHOICES = (
('0', 'men'),
('1', 'girl'),
('2', 'nobody'),
)
email = models.EmailField(unique=True, max_length=50)
phone = models.TextField(unique=True, max_length=11)
name = models.TextField(default="AKA")
sex = models.CharField(
max_length=2,
choices=TYPE_CHOICES,
default="0"
)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
class Meta:
db_table = "users"
User anether serializer for Validating Email
class EmailSerializer(serializers.Serializer):
email = serializers.EmailField(required=True)
#api_view(['GET'])
def get_user(request):
serializer = EmailSerializer(data=request.data)
if serializer.is_valid():
email = serializer.validated_data['email']
Users = User.objects.filter(email=email)
serializer = UserSerializer(Users, many= True)
return Response({"status": "success", "data": serializer.data})
else:
return Response({"status": "errors", "data": serializer.errors})

Django Rest Framework. added new list element to request.data, but getting the new element as a nested list

I am building a small Django Rest Framework API with APIView.
It generates a post with tags that are gotten from the DB, but if there are no tags or I want to add a new tag, a list of tag names is passed into the payload and creates them along with the post, then the new tag IDs are added to the request.data['tags'].
These are the Models:
class Tag(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
name = models.CharField(max_length=255, unique=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
slug = models.SlugField(unique=True, null=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['name']
def __str__(self):
return self.name
def get_absolute_url(self):
return f'/{self.slug}'
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.name)
return super().save(*args, **kwargs)
class Post(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
user = models.ForeignKey(settings.AUTH_USER_MODEL,
null=True,
on_delete=models.SET_NULL)
tags = models.ManyToManyField('Tag', related_name='posts')
title = models.CharField(max_length=255)
slug = models.SlugField(unique=True, null=False)
body = models.TextField()
description = models.CharField(max_length=255)
publish = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.title
def get_absolute_url(self):
return f'/{self.slug}'
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
return super().save(*args, **kwargs)
class Meta:
ordering = ['-title']
These are the Serializers:
class TagSerializer(serializers.ModelSerializer):
""" Serializer for Tag get model """
class Meta:
model = Tag
fields = ('name',)
class PostSerializer(serializers.ModelSerializer):
""" Serializer for Post create, update, delete model """
class Meta:
model = Post
fields = ('title', 'body', 'description', 'publish', 'tags')
This is the payload I am passing for new tags:
{
'title': 'Test Creating with new tags',
'new_tags': ['newest', 'newer']
}
This is the post method:
def post(self, request, format=None):
""" Creates a Post instance """
if isinstance(request.data, QueryDict):
request.data._mutable = True
tmp_new_tags = request.data.get('new_tags', None)
if tmp_new_tags:
new_tags = request.data.pop('new_tags')
request.data.update({'tags': []})
for new_tag in new_tags:
tag = Tag.objects.create(name=new_tag, user=self.request.user)
request.data['tags'].append(str(tag.id))
serializer = PostSerializer(data=request.data)
if serializer.is_valid():
serializer.save(user=self.request.user)
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
this is the request.data with existing tags that I am expecting for new tags:
<QueryDict: {'title': ['Test Creating'], 'tags': ['1', '2']}>
But I got the tags in a nested list,
<QueryDict: {'title': ['Test Creating with new tags'], 'tags': [['3', '4']]}>
This is the response.data:
{'tags': [ErrorDetail(string="“['3', '4']” is not a valid UUID.", code='invalid')]}
How can I append a List(1D) instead of nested list to request.data['tags']?
In this case, you just have to create a new list and append values to it.
and then call setlist() method to set the list to your request.data.
for example:
def post(self, request, format=None):
""" Creates a Post instance """
if isinstance(request.data, QueryDict):
request.data._mutable = True
tmp_new_tags = request.data.pop('new_tags')
if tmp_new_tags:
tag_list = []
for new_tag in temp_new_tags:
tag = Tag.objects.create(name=new_tag, user=self.request.user)
tag_list.append(tag.id)
request.data.setlist('tags', tag_list)
serializer = PostSerializer(data=request.data)
if serializer.is_valid():
serializer.save(user=self.request.user)
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

Django Rest Access Model Values in Another Model

I am new on Django and I have some issues about Rest API. I want to access User Model Values from Project Model. I have User JSON like this:
[
{
"id": 15,
"first_name": "Ebrar",
"last_name": "Bilgili",
"university": "Bahçeşehir University",
"faculty": "Software Engineering",
"user": 17
},
]
And also I have Project JSON like this:
{
"id": 4,
"title": "teammate",
"city": "istanbul",
"user": 17,
"user_profile": 15
}
But I want to access User First name, Last name, University and Faculty values in Project JSON like this:
{
"id": 4,
"title": "teammate",
"city": "istanbul",
"user": 17,
"user_profile": {
"first_name": "Ebrar",
"last_name": "Bilgili",
"university": "Bahçeşehir University",
"faculty": "Software Engineering",
}
}
I have many researched but I could not find any solution. I searched all the methods that came to my mind.. I hope you help me. Thanks.
My models.py:
class User(AbstractUser):
username = models.CharField(max_length=250, unique=True)
email = models.EmailField(max_length=50, unique=True)
password = models.CharField(max_length=250)
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email']
class UserProfile(models.Model):
user = models.OneToOneField(User, null=True, on_delete=models.CASCADE)
first_name = models.CharField(max_length=250)
last_name = models.CharField(max_length=250)
university = models.CharField(max_length=250)
faculty = models.CharField(max_length=250)
class Meta:
ordering = ["first_name"]
def __str__(self):
return "%s %s" % (self.first_name, self.last_name)
class Project(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
user_profile = models.ForeignKey(
'UserProfile', related_name='name', on_delete=models.CASCADE)
title = models.CharField(max_length=200)
city = models.CharField(max_length=50)
def __str__(self):
return self.title
and my serializers.py:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = '__all__'
extra_kwargs = {
'password': {'write_only': True}
}
def create(self, validated_data):
password = validated_data.pop('password', None)
instance = self.Meta.model(**validated_data)
if password is not None:
instance.set_password(password)
instance.save()
return instance
class UserProfileSerializer(serializers.ModelSerializer):
class Meta:
model = UserProfile
fields = '__all__'
class ProjectSerializer(serializers.ModelSerializer):
class Meta:
model = Project
fields = '__all__'
and views.py:
class RegisterView(APIView):
def post(self, request):
serializer = UserSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data)
class LoginView(APIView):
def post(self, request):
email = request.data['email']
password = request.data['password']
user = User.objects.filter(email=email).first()
if user is None:
raise AuthenticationFailed('User not found!')
if not user.check_password(password):
raise AuthenticationFailed("Incorrect password!")
payload = {
'id': user.id,
'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=60),
'iat': datetime.datetime.utcnow()
}
token = jwt.encode(payload, 'secret', algorithm='HS256')
response = Response()
response.set_cookie(key='token', value=token, httponly=True)
response.data = {
'id': user.id,
'username': user.username,
'token': token
}
return response
class UserView(APIView):
def get(self, request):
token = request.COOKIES.get('token')
if not token:
raise AuthenticationFailed('Unauthenticated!')
try:
payload = jwt.decode(token, 'secret', algorithms=['HS256'])
except jwt.ExpiredSignatureError:
raise AuthenticationFailed('Unautheticated!')
user = User.objects.filter(id=payload['id']).first()
serializer = UserSerializer(user)
return Response(serializer.data)
class UserProfileView(APIView):
def post(self, request):
serializer = UserProfileSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def put(self, request):
serializer = UserProfileSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def get(self, request):
try:
id = request.query_params['id']
if id != None:
user = UserProfile.objects.get(id=id)
serializer = UserProfileSerializer(user)
except:
users = UserProfile.objects.all()
serializer = UserProfileSerializer(users, many=True)
return Response(serializer.data)
class ProjectView(APIView):
def post(self, request):
serializer = ProjectSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def get(self, request):
try:
id = request.query_params['id']
if id != None:
project = Project.objects.get(id=id)
serializer = ProjectSerializer(project)
except:
projects = Project.objects.all()
serializer = ProjectSerializer(projects, many=True)
return Response(serializer.data)
Try this:
class ProjectSerializer(serializers.ModelSerializer):
user_profile = UserProfileSerializer()
class Meta:
model = Project
fields = '__all__'

Django Rest framework nested serializer not returning relation values in validated_data

I have defined everything correctly. (GET is working correctly) I can get the user detail through nested serializer. But when I do PUT I am not getting validated_data in update method which is in UserSerializer.
models.py
class UserProfile(models.Model):
user = models.ForeignKey(User, related_name='users',
on_delete=models.CASCADE)
phone_number = models.CharField(max_length=15)
known_languages = models.CharField(max_length=100)
date_updated = models.DateTimeField(auto_now=True)
user_domain = models.CharField(max_length=100, default=None)
serializers.py
class UserProfileSerializer(serializers.ModelSerializer):
class Meta:
model = UserProfile
fields = ['phone_number', 'known_languages', 'user_domain']
class UserSerializer(serializers.ModelSerializer):
users = UserProfileSerializer()
class Meta:
model = User
fields = ['first_name', 'last_name', 'username', 'email', 'users']
def update(self, instance, validated_data):
import pdb;pdb.set_trace()
#here I am not getting users value. it is returning empty list
return instance
views.py
def put(self, request, pk):
user_obj = self.get_object(pk)
request.POST._mutable = True
request.data['users'] = { 'phone_number': request.data.pop('phone_number'), 'user_domain': request.data.pop('user_domain'), 'known_languages': request.data.pop('known_languages') }
request.POST._mutable = False
serializer = UserSerializer(user_obj, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Can any one help on it......
data = request.data.dict()
data['users'] = { 'phone_number': request.data.pop('phone_number'), 'user_domain': request.data.pop('user_domain'), 'known_languages': request.data.pop('known_languages') }
serializer = UserSerializer(user_obj, data=data, partial=True )
works perfect for me
remove this three lines:
request.POST._mutable = True
request.data['users'] = { 'phone_number': request.data.pop('phone_number'), 'user_domain': request.data.pop('user_domain'), 'known_languages': request.data.pop('known_languages') }
request.POST._mutable = False
and just use inside update:
def update(self, instance, validated_data):
request = self.context.get('request')
data = request.data.copy()
users = {
'phone_number': data.get('phone_number'),
'user_domain': data.get('user_domain'),
'known_languages': data.get('known_languages')
}
# your code ...

NOT NULL constraint failed: device_api_devicegroup.owner_id

I am getting not null contraint failed error while posting a group. How should i fix it? I don't want to show the user in the api so i have not used it in the serializer fields. Do i have to compulsorily add it there?
Here is my model, serializer and APIView
class DeviceGroup(models.Model):
token = models.UUIDField(default=uuid.uuid4, unique=True, editable=False)
name = models.CharField(max_length=250, blank=False, null=False)
owner = models.ForeignKey(User, blank=False, null=False)
class DeviceGroupSerializer(serializers.ModelSerializer):
id = serializers.UUIDField(source='token', format='hex', read_only=True)
class Meta:
model = DeviceGroup
fields = ['id','name']
class DevicesGroupsAPIView(APIView):
permission_classes = (permissions.IsAuthenticated,)
serializer_class = DeviceGroupSerializer
def get_object(self, user, token):
try:
return BaseDevice.objects.filter(owner=user).get(token=token)
except ObjectDoesNotExist:
return error.RequestedResourceNotFound().as_response()
def get(self, request, format=None):
"""
Returns a list of groups
"""
reply = {}
try:
groups = DeviceGroup.objects.filter(owner=request.user)
reply['data'] = DeviceGroupSerializer(groups, many=True).data
except:
reply['data'] = []
return Response(reply, status.HTTP_200_OK)
def post(self, request, format=None):
"""
create a new group
"""
print('request.data', request.data)
print('user', request.user)
serializer = DeviceGroupSerializer(data=request.data)
print('serializer', serializer)
if serializer.is_valid():
serializer.save()
return Response(serializers.data, status.HTTP_200_OK)
return Response(serializer.errors, status.HTTP_204_NO_CONTENT)
see this carefully, user is not in request.data:
serializer = DeviceGroupSerializer(data={
'name':request.data['name'],
'owner':request.user.id,
})
also check that the serializer allows the owner to be used
from django.contrib.auth.models import User
class DeviceGroupSerializer(serializers.ModelSerializer):
id = serializers.UUIDField(source='token', format='hex', read_only=True)
owner = serializers.PrimaryKeyRelatedField(queryset=User.objects.all())
class Meta:
model = DeviceGroup
fields = ['id','name', 'owner']

Categories

Resources