My Model is
class ChatRoom(models.Model):
name = models.CharField(max_length=55, verbose_name='Имя чата', unique=True)
users = models.ManyToManyField(
CustomUser,
verbose_name='Пользователи',
related_name='user_chatrooms',
null=True
)
My Serializer for this model
class ChatRoomSerializer(serializers.ModelSerializer):
users = UserInfoSerializer(many=True, read_only=False)
class Meta:
model = ChatRoom
fields = [
'name',
'users'
]
View looks
#api_view(['POST'])
#permission_classes([IsAuthenticated])
def api_create_chat(request):
if request.method == 'POST':
serializer = ChatRoomSerializer(data=request.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)
I do request (here is body)
<QueryDict: {'name': ['benny'], 'users': ['11,1']}>
In this case I recieve Error
{'users': [ErrorDetail(string='This field is required.', code='required')]}
And I can't understand what is wrong here.
When I change parameter to read_only=True in UserInfoSerializer it works, but it doesn't add user to new Chat object.
{
"name": "benny",
"users": []
}
UPD
I tried to add create() method, but it didn't help
def create(self, validated_data):
users = validated_data.pop('users')
users = [int(id) for id in users.split(',')]
chat_instance = ChatRoom.objects.create(name=validated_data.pop('name'))
for id in users:
chat_instance.users.add(CustomUser.objects.get(pk=id))
return chat_instance
UPD 2
UserInfoSerializer
class UserInfoSerializer(serializers.ModelSerializer):
class Meta:
model = CustomUser
fields = ['id',]
Problem solved by modifying serializer in view.py. It isn't good decision, but it works.
#api_view(['POST'])
#permission_classes([IsAuthenticated])
def api_create_chat(request):
if request.method == 'POST':
serializer = ChatRoomSerializer(data=request.data)
data = {}
if serializer.is_valid():
serializer.save()
users_id = [int(id) for id in request.data['users'].split(',')]
chat = ChatRoom.objects.get(pk=serializer.data['id'])
for id in users_id:
user = CustomUser.objects.get(pk=id)
chat.users.add(user)
serializer.data['users'].append({'user': user.id, 'username': user.username})
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Related
I need to move validation from views.py to serializators.py.
How can I do it?
Validation must check:
user can't follow himself
user can't follow author that his already follow
I have a ViewSet with #action:
my view.py:
#action(
detail=True,
methods=['post', 'delete'],
permission_classes=(permissions.IsAuthenticated,)
)
def subscribe(self, request, id=None):
"""Following"""
author_id = id
if request.method == 'POST':
author = get_object_or_404(CustomUser, id=author_id)
if author == request.user:
raise serializers.ValidationError(
{'errors': 'You can't follow yourself.'}
)
if self.request.user.follower.filter(author=author).exists():
raise serializers.ValidationError(
{'errors': 'You already follow this author.'}
)
author = get_object_or_404(CustomUser, id=author_id)
Follow.objects.create(
user=request.user, author=author
)
serializer = FollowSerializer(author, context={'request': request})
return Response(serializer.data, status=status.HTTP_201_CREATED)
if request.method == 'DELETE':
user_id = request.user.id
subscribe = get_object_or_404(
Follow, user__id=user_id, author__id=author_id
)
subscribe.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
and I have a FollowSerializer in serializers.py
my serializers.py
class FollowSerializer(serializers.ModelSerializer):
class Meta:
model = CustomUser
fields = ('email', 'id', 'username', 'first_name',
'last_name', 'is_subscribed', 'recipes', 'recipes_count')
I try to add a validate method like def validate(self, data): but it doesn't work.
After user-registration, user wants to post data into Client model ( OnetoOne relationship with User model ). So, I want to access the requested user object inside the serializer-class to create a new row in Client model associated with the requested user.
models.py
class Client(models.Model):
user= models.OneToOneField(User, on_delete=models.CASCADE, null=False, blank=False)
sex = models.CharField(max_length = 6, blank=False, null=False)
location = models.CharField(max_length = 30, null = False, blank = False)
views.py
class ClientRegister(GenericAPIView):
def post(self, request):
user = request.user
serializer = ClientSerializer(data= request.data)
if serializer.is_valid():
serializer.save()
return Response(status= status.HTTP_201_CREATED)
else:
return Response(data= 'Invalid Form', status= status.HTTP_400_BAD_REQUEST)
serializers.py
class ClientSerializer(serializers.ModelSerializer):
class Meta:
model = Client
fields = ['sex', 'location']
def create(self, validated_data):
sex = validated_data.get('sex')
location = validated_data.get('location')
user = #------ Want requested user object here ------#
if user.is_client:
client = Client(user=user, sex=sex, location=location)
client.save()
return client
I have manually added user oject into the data in serializer = CientSerializer(data=request.data).
But, It didn't work. Please, tell me how to pass it from views.py or how to access it in serializers.py.
Pass user when you do serializer.save in post method of views like
def post(self, request):
u = request.user
serializer = ClientSerializer(data= request.data)
if serializer.is_valid():
serializer.save(user=u)
return Response(status= status.HTTP_201_CREATED)
else:
return Response(data= 'Invalid Form', status= status.HTTP_400_BAD_REQUEST)
Or you can read about passing context from views to serializers and in this context you can pass your required data like -
serializer = ClientSerializer(context = {'request':request}, data=request.data)
then you can have your request object in your serializers and you can get request.user or directly pass it in the context.
Try to pass the user with sex and location in views
class ClientRegister(GenericAPIView):
def post(self, request):
data = request.data
user = request.user
#add user in key
data['user']=user
serializer = ClientSerializer(data=data)
if serializer.is_valid():
serializer.save()
return Response(status= status.HTTP_201_CREATED)
else:
return Response(data= 'Invalid Form', status= status.HTTP_400_BAD_REQUEST)
serializer:
class ClientSerializer(serializers.ModelSerializer):
class Meta:
model = Client
fields = '__all__'
views.py
class ClientRegister(GenericAPIView):
def post(self, request):
user = request.user
serializer = ClientSerializer(context={'user':user}, data= request.data)
if serializer.is_valid():
serializer.save()
return Response(status= status.HTTP_201_CREATED)
else:
return Response(data= 'Invalid Form', status= status.HTTP_400_BAD_REQUEST)
serializers.py
class ClientSerializer(serializers.ModelSerializer):
class Meta:
model = Client
fields = ['sex', 'location']
def create(self, validated_data):
sex = validated_data.get('sex')
location = validated_data.get('location')
user = self.context.get('user')
if user.is_client:
client = Client(user=user, sex=sex, location=location)
client.save()
return client
I made APIs to create update case But the problem is with task if I pass only one pk like(task=1) while updating or creating through postman then it works fine and case will be created with referencing that task but a task is a manytomany field I need to assign multiple task pk to a case like task = [1,2] Then it is giving error like
"Incorrect type. Expected pk value, received str."
]
class Case(models.Model):
name = models.CharField(max_length=200)
task = models.ManyToManyField('task.Task',blank=True, null=True)
assigned_to = models.ForeignKey("account.User",null=True, blank=True, on_delete=models.SET_NULL)
class CaseSerializer(serializers.ModelSerializer):
class Meta:
model = Case
fields = ('id', 'name', 'task', 'assigned_to')
class CaseCreateView(APIView):
permission_classes = (IsAuthenticated,)
#access_permission('case_create')
def post(self, request, format=None):
serializer = CaseSerializer(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)
class CaseUpdateView(APIView):
permission_classes = (IsAuthenticated,)
model = Case
#access_permission('case_edit')
def put(self, request,pk, format=None):
case = get_object(self,pk)
serializer = CaseSerializer(case,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)
i'm new in DRF too and most of time i just using Generic but i will try maybe helping you. add read_only_fields=(task, ) in your serializer and then we will adding tasks to Case instance manually.by this way in create method we don't need to 'task' and serializer will be valid.
serializer.py:
class CaseSerializer(serializers.ModelSerializer):
class Meta:
model = Case
fields = ('id', 'name', 'task', 'assigned_to')
read_only_fields = ('task', )
class CaseUpdateView(APIView):
permission_classes = (IsAuthenticated,)
model = Case
#access_permission('case_edit')
def put(self, request,pk, format=None):
case = get_object(self,pk)
serializer = CaseSerializer(case,data=request.data)
if serializer.is_valid():
serializer.save()
task_id_list = request.data['tasks_id'] # depending on request
for task_id in task_id_list: # this way we can add to M2M field manually
task = Task.object.get(id=task_id)
case.task.add(task)
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
This is my UserProfile model,
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='profile', on_delete=models.CASCADE, )
badge = models.ImageField(upload_to='media/badges/', null=True)
reputation = models.IntegerField(default=0)
status = models.CharField(max_length=255, null=True, blank=True)
thumbnail = models.ImageField(upload_to='media/user/', blank=True, null=True)
And this is the Serializer class,
class UserProfileSerializer(serializers.ModelSerializer):
thumbnail = serializers.ImageField(max_length=None, use_url=True)
class Meta:
model = models.UserProfile
fields = ('badge', 'reputation', 'status', 'thumbnail',)
My API to update an image looks like this,
class CreateUpdateUserThumbnail(views.APIView):
def post(self, request, **kwargs):
try:
user = User.objects.get(id=kwargs.get('user_id'))
except User.DoesNotExist:
return Response({"Error": "User does not exist"}, status=status.HTTP_404_NOT_FOUND)
request.data['user_id'] = user.id
serializer = UserProfileSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
This is the error that I get when I try to upload an image using POSTMAN.
return Database.Cursor.execute(self, query, params)
django.db.utils.IntegrityError: NOT NULL constraint failed: bouncer_userprofile.user_id
How do I associate a user_id with the serializer data?
the request.data is immutable so you should to create the copy first:
data = request.data.copy()
data['user_id'] = user.id
serializer = UserProfileSerializer(data=data)
You need to pass user_profile instance on UserProfileSerializer instantiation
serializer = UserProfileSerializer(instance=user.profile, data=request.data)
Your view will look like this
class CreateUpdateUserThumbnail(views.APIView):
def post(self, request, **kwargs):
try:
user = User.objects.get(id=kwargs.get('user_id'))
except User.DoesNotExist:
return Response({"Error": "User does not exist"}, status=status.HTTP_404_NOT_FOUND)
serializer = UserProfileSerializer(instance=user.profile, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
I've been struggling with this problem.
I am not sure what I'm missing.
Please let me know if you have any suggestions..!!
models.py:
co_manager = models.ManyToManyField(BookRunner, blank=True, null=True, related_name="deal_co_manager")
views.py:
class DealAdminViewSet(viewsets.ModelViewSet):
queryset = Deal.objects.all()
serializer_class = CreateDealSerializer
def create(self, request, format=None):
data = ...all things data here.
serializer = CreateDealSerializer(data=deal)
print serializer
co_manager_array = []
if serializer.is_valid():
serializer.save()
return Response(status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
serializer.py:
class CreateDealSerializer(serializers.Serializer):
co_manager = serializers.PrimaryKeyRelatedField(allow_null=True, many=True, queryset=BookRunner.objects.all(), required=False)
I would suggest editing your views, more like this,
class DealAdminViewSet(viewsets.ModelViewSet):
queryset = Deal.objects.all()
serializer_class = CreateDealSerializer
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(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)
Without showing your models, the help anyone could offer is pretty much limited. Please let me know, if anything comes up.
Also, your serializers,
class CreateDealSerializer(serializers.Serializer):
co_manager = serializers.PrimaryKeyRelatedField(allow_null=True, many=True, queryset=BookRunner.objects.all())
The error is triggering because, in your models the field co_manager is not defined as null=True. If you want to save the above field as null, then change in your models.py,
co_manager = models.ForeignKey(Target_table_name, null=True, blank=True)
The error won't be raised, when null value is stored.
Just send an empty list if serializer is set with
many = True,
allow_null=True
from serliazer:
many_field = serializers.PrimaryKeyRelatedField(queryset=qs, read_only=False, many=True, allow_null=True)
class Meta:
model = ModelName
fields = (
'many_field ',
...)
extra_kwargs = {
'many_field': {'required': False},
}
and in the requests data:
data = {'NOT_many_field': None,
'many_field': []}