As you see on the code. The exception does not raise when i add partial=True, It work ok with partial=False
Rest django framework
from rest_framework import serializers
class AField(serializers.Serializer):
afield = serializers.CharField()
xfed = serializers.CharField()
class BField(serializers.Serializer):
bfield = AField(many=True, required=False)
data = {
"bfield":[{},{}]
}
BField(data=data, partial=True).is_valid(raise_exception=True)
Related
I have a Django Log model which has many-to-one with a User
from django.db import models
class Log(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
...
I have a Django form for the Log
from django.forms import ModelForm
class LogForm(ModelForm):
class Meta:
model = Log
exclude = ("user",)
I have a graphene-django mutation to enable Log creation
import graphene
from graphene_django import DjangoObjectType
from graphene_django.forms.mutation import DjangoModelFormMutation
class LogType(DjangoObjectType):
class Meta:
model = Log
fields = "__all__"
class CreateLogMutation(DjangoModelFormMutation):
log = graphene.Field(LogType)
class Meta:
form_class = LogForm
How do I set Log.user to the current user before saving? With Django class-based views you would do as follows:
from django.views.generic import CreateView
class LogCreateView(CreateView):
model = Log
form_class = LogForm
def form_valid(self, form):
form.instance.user = self.request.user
return super().form_valid(form)
How is this achieved with graphene-django?
Override perform_mutate and add the user there. pefrom_mutate is called after Django's Form.is_valid.
class CreateLogMutation(DjangoModelFormMutation):
log = graphene.Field(LogType)
class Meta:
form_class = LogForm
#classmethod
def perform_mutate(cls, form, info):
form.instance.user = info.context.user
return super().perform_mutate(form, info)
I use kotli. I define everything as per requirement, why I am getting
thing type of Issue
UserRegistrationService.kt: (25, 36): No value passed for parameter 'userRegistration'
I got this type of issue at my UserRegistration class No value passed
for parameter department, and userRegistration
I Creat ResponseTemplateVO POJO Class
ResponseVO.kt
package com.userservice.userregistration.VO
import com.userservice.userregistration.entity.UserRegistration
data class ResponseTemplateVO(
var userRegistration: UserRegistration,
var department: Department
)
Department.kt
package com.userservice.userregistration.VO
data class Department(
val departmentId:Long=-1,
val departmentName:String="",
val departmentAddress:String="",
val departmentCode:String=""
)
UserRegistration.kt
package com.userservice.userregistration.entity
data class UserRegistration(
val userId:Long=-1,
val firstName:String="",
val lastName:String="",
val email:String="",
val departmentId:Long=-1,
)
UserRegistrationService.kt
package com.userservice.userregistration.service
import com.userservice.userregistration.VO.Department
import com.userservice.userregistration.VO.ResponseTemplateVO
import com.userservice.userregistration.entity.UserRegistration
import com.userservice.userregistration.repository.UserRegistrationRepository
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import org.springframework.web.client.RestTemplate
#Service
class UserRegistrationService {
#Autowired
private lateinit var userRegistrationRepository: UserRegistrationRepository
#Autowired
private lateinit var restTemplate: RestTemplate
fun saveUserDetails(userRegistration: UserRegistration): UserRegistration {
return userRegistrationRepository.save(userRegistration)
}
fun getUserWithDepartment(userId: Long): ResponseTemplateVO {
val vo= ResponseTemplateVO()
val userRegistration:UserRegistration=userRegistrationRepository.findUserById(userId)
val department: Department? =
restTemplate.getForObject("http://localhost:9001/departments/"+userRegistration.departmentId,
Department::class.java)
vo.userRegistration=userRegistration
if (department != null) {
vo.department=department
}
return vo
}
}
I am getting error at this below method at the line 2
val vo= ResponseTemplateVO()
No value passed for parameter department and userRegistration .This is
the error
fun getUserWithDepartment(userId: Long): ResponseTemplateVO {
val vo= ResponseTemplateVO()
val userRegistration:UserRegistration=userRegistrationRepository.findUserById(userId)
val department: Department? =
restTemplate.getForObject("http://localhost:9001/departments/"+userRegistration.departmentId,
Department::class.java)
vo.userRegistration=userRegistration
if (department != null) {
vo.department=department
}
return vo
}
This declaration:
data class ResponseTemplateVO(
var userRegistration: UserRegistration,
var department: Department
)
packs multiple things:
it declares 2 properties userRegistration and department
it defines the primary constructor of the class with 2 arguments: userRegistration and department
When you write:
val vo = ResponseTemplateVO()
You're calling the constructor of that class, but you don't specify the 2 required arguments. You should instead call it by passing the arguments:
fun getUserWithDepartment(userId: Long): ResponseTemplateVO {
val userRegistration:UserRegistration=userRegistrationRepository.findUserById(userId)
val department: Department? = restTemplate.getForObject("http://localhost:9001/departments/"+userRegistration.departmentId,
Department::class.java)
if (department == null) {
// here you should decide if it should have a default value
// or throw an exception
}
return ResponseTemplateVO(userRegistration, department)
}
Note that you declared the department property as non-null, so you need a non-null department in order to create an instance of your class.
So if department is null you have 3 options:
throw an exception
use a default value instead
change the type of department in ResponseTemplateVO so it accepts nulls (Department? with ?)
Also, if you instantiate your class with all required value like that, and you don't need to modify its properties later, the properties can be declared val. This is usually more idiomatic Kotlin. With immutability, it's easier to reason about the values.
The issue is in the data class.
data class ResponseTemplateVO(
var userRegistration: UserRegistration,
var department: Department
)
Here you have added the following params into the constructor of the data class. Hence you will need to pass the values to the constructor of the class before you can initialise it.
Hence your ResponseTemplateVO data class will become like this
data class ResponseTemplateVO(
var userRegistration: UserRegistration?=null,
var department: Department?=null)
Now since we have already assigned null as the default value. Now you can initialise the data class and it creates the data class with the values set to null and you do not need to pass any value for params to the constructor. Now you can access each of the variables and set the respective data into them.
Let's say I have two serializers, UserSerializer and EmployeeSerializer. Where Employee extends User. I want to override a field that is currently declared within UserSerializer from EmployeeSerializer.
From my understanding, you could achieved this via extra_kwargs, but it doesn't seem to work in my case and still getting required field error when I try to POST data to the server.
class UserSerializer(serializers.ModelSerializer):
username = serializers.CharField(required=True, max_length=20, allow_blank=False, allow_null=False)
class Meta:
model = User
fields = "__all__"
class EmployeeSerializer(UserSerializer):
class Meta:
model = User
fields = "__all__"
extra_kwargs = {
'username': {'required': False}
}
You have extends EmployeeSerializer from UserSerializer and in UserSerializer you have explicitly declared the username field is required True. Thus you can't make it required: False in extra_kwargs dict, in fact it will not work as Django rest framework documentation says,
Please keep in mind that, if the field has already been explicitly declared on the serializer class, then the extra_kwargs option will be ignored.
check this link for elaborate understanding.
I have the below views.py file for my class based view.
from rest_framework import viewsets
from rest_framework.views import APIView
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from django.shortcuts import get_object_or_404
from .permissions import IsOwner, IsNotBlacklistedUser
from rest_framework import filters
from django_filters import rest_framework as filters_django
from core.models import Book
from .serializers import BookSerializer, AllBookSerializer
class BookApiView(APIView):
authentication_classes = (JSONWebTokenAuthentication, )
permission_classes = (IsAuthenticated, IsNotBlacklistedUser)
filter_backends = (filters_django.DjangoFilterBackend,)
filterset_fields = ('title',)
def get(self, request):
books = Book.objects.filter(
user=request.user.id, is_published=True).order_by('-title')
serializer = BookSerializer(books, many=True)
return Response(serializer.data)
def post(get, request):
data = request.data
serializer = BookSerializer(data=data)
if serializer.is_valid():
serializer.save(user=request.user)
return Response(serializer.data, status=201)
return Response(serializer.errors, status=400)
I am unable to see any filter option when i load this view in the django rest framework UI . I am not sure how i should be doing this. Can someone point out what i might have to do extra to get this working . I have also added 'django_filters' to my settings.py file.
Thanks in advance.
You can either use ViewSets.
class BookApiViewSet(CreateModelMixin, ListModelMixin, GenericViewSet):
authentication_classes = (JSONWebTokenAuthentication, )
permission_classes = (IsAuthenticated, IsNotBlacklistedUser)
filter_backends = (filters_django.DjangoFilterBackend,)
filter_fields = ('title',)
or generic APIViews
class BookListCreateAPIView(generics.ListCreateAPIView):
authentication_classes = (JSONWebTokenAuthentication, )
permission_classes = (IsAuthenticated, IsNotBlacklistedUser)
filter_backends = (filters_django.DjangoFilterBackend,)
filter_fields = ('title',)
or you can extend GenericAPIView and write filters manually.
class BookApiView(GenericAPIView):
authentication_classes = (JSONWebTokenAuthentication, )
permission_classes = (IsAuthenticated, IsNotBlacklistedUser)
filter_backends = (filters_django.DjangoFilterBackend,)
filter_fields = ('title',)
queryset = self.filter_queryset(self.get_queryset())
def get(self, request, *args, **kwargs):
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
Note: I didn't test codes you may need to tweak little.
I got the following classes:
#JsonIdentityInfo(
generator = ObjectIdGenerators.IntSequenceGenerator.class,
property = "oid"
)
#JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "clazz")
#JsonSubTypes({
#JsonSubTypes.Type(value = MySubEntity.class, name = "MySubEntity"),
})
public abstract class Entity {
...
}
public class MySubEntity extends Entity {
...
}
Now when I serialize that MySubEntity wrapped in an Optional then JSON does not contain the clazz attribute containing the type ID. Bug? When I serialize to List<MySubEntity> or just to MySubEntity it works fine.
Setup: jackson-databind 2.9.4, jackson-datatype-jdk8 2.9.4, serialization is done in Spring Boot application providing a RESTful web service.
EDIT: Here is the Spring REST method that returns the Optional:
#RequestMapping(method = RequestMethod.GET, value = "/{uuid}", produces = "application/json")
public Optional<MySubEntity> findByUuid(#PathVariable("uuid") String uuid) {
...
}
EDIT:
I made a SSCCE with a simple Spring REST controller and two tests. The first test is using ObjectMapper directly which is successful in deserialization although the clazz is missing. The second test calls the REST controller and fails with an error because clazz is missing:
Error while extracting response for type [class com.example.demo.MySubEntity] and content type [application/json;charset=UTF-8]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Missing type id when trying to resolve subtype of [simple type, class com.example.demo.MySubEntity]: missing type id property 'clazz'; nested exception is com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Missing type id when trying to resolve subtype of [simple type, class com.example.demo.MySubEntity]: missing type id property 'clazz'
This, indeed, looks like a bug. There is one workaround that I can suggest for this case, is to use JsonTypeInfo.As.EXISTING_PROPERTY and add field clazz to your Entity. There only one case with this approach is that the clazz must be set in java code manually. However this is easy to overcome.
Here is the full code for suggested workaround:
#JsonIdentityInfo(
generator = ObjectIdGenerators.IntSequenceGenerator.class,
property = "oid"
)
#JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.EXISTING_PROPERTY, //field must be present in the POJO
property = "clazz")
#JsonSubTypes({
#JsonSubTypes.Type(value = MySubEntity.class, name = "MySubEntity"),
})
public abstract class Entity {
#JsonProperty
private String uuid;
//Here we have to initialize this field manually.
//Here is the simple workaround to initialize in automatically
#JsonProperty
private String clazz = this.getClass().getSimpleName();
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
public String getClazz() {
return clazz;
}
public void setClazz(String clazz) {
this.clazz = clazz;
}
}