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.
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)
Is there any annotation provided by spring to validate the input values from predefined set ?
Requirement validate roles assign to user, and Role value should be either user, admin, moderator.
Can I validate at the time when request comes in controller ?
You could use the Enum type to define the expected constants:
Role {
USER,
ADMIN,
MODERATOR
}
And then, your request would be:
public class User implements Serializable {
#NotNull(message = "role cannot be null")
private Role role;
}
I'm letting system to create queries from the methods names:
public interface CompanyRepository extends JpaRepository<Company, Long> {
Boolean existsByName(String name);
Boolean existsByRegCode(String regCode);
}
There are several different repos for different entities (Company, User, Shop) and they all have field named CountryId.
Now I need to add condition "AND CountryId = :CountryId" to all queries in all repos , where the country parameter gets it's value from some configuration file.
I know that I should build some base class for this and extend from that, but can't figure out what to put into this class.
You can define a superclass for all of your entities and add the countryId field to this superclass and annotate with #Where(clause = "countryId='id'")
#Where(clause = "countryId='id'")
public class Entity {...}
and
public class Company extends Entity {...}
I'm using Spring data rest with Kotlin and if I use data classes the associations via uri stops working with the error no String-argument constructor/factory method to deserialize from String value
Data class
#Entity
data class Comment(
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
var id: Long = 0,
var author: String? = null,
var content: String? = null,
#ManyToOne
var post: Post? = null) {
}
If I use a simple class instead the association works fine.
#Entity
class Comment {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long = 0
var author: String? = null
var content: String? = null
#ManyToOne
var post: Post? = null
}
The association is done via a POST request {"author":"John Doe","content":"Dummy Content", "post":"http://localhost:8080/post/33"}
Any ideia why I have this error when I use a data class and what can I do to use the association creation via uri and keep using data classes?
I did some investigation, and turns out Spring Data Rest uses a custom Jackson module to deserialize JSON into JPA entities: it uses PersistentEntityJackson2Module class and using the inner class UriStringDeserializer to resolve the concrete entities from entity URI references, http://localhost:8080/post/33 in your example.
Problem is, this custom deserialization only kicks in when the "standard deserialization" of Jackson is triggered: The one that uses empty constructor, then using setters to resolve & set the fields. At that moment, UriStringDeserializer converts the string into the concrete entity - Post instance of your example.
When you use a data class, the class neither has an empty constructor nor setters, therefore in BeanDeserializer#deserializeFromObject method of Jackson, it branches into if (_nonStandardCreation) being true, from there the call goes into BeanDeserializerBase#deserializeFromObjectUsingNonDefault , but not handed over to PersistentEntityJackson2Module anymore, and directly failing due to type mismatch between the constructor argument and the json value.
It seems you need to create a feature request for it to be implemented. If you decide to implement yourself, providing a _delegateDeserializer to the BeanDeserializer might be a start (not sure).
However, I don't know how JPA itself plays with data classes in the first place - after all it tracks the entity state changes, but a data class cannot have state changes. So, it might not be possible to use data classes after all - better to keep in mind.
Note: You probably cannot simply extend/override PersistentEntityJackson2Module because it is registered to multiple beans in RepositoryRestMvcConfiguration
I am using spring mvc with hibernate and JPA. I have a Person class which is inherited by another class called Agent. The mapping is implemented as follows:
#Entity
#Table(name = "Person")
#Inheritance(strategy = InheritanceType.JOINED)
public class Person extends Auditable implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "PersonId")
protected Long id;
//other variables
...
}
#Entity
#PrimaryKeyJoinColumn(name = "PersonId")
public class Agent extends Person implements Serializable {
//additional agent specific variables go here
...
}
Saving new data is smooth and I have no problem there. however, when I edit data, everything except the id value is bound to the controller method's model attribute. I have verified that the id has been sent along with other items from the browser using chrome's developer tools. but the id field at the controller is always null and as a result the data is not updated. This is what my controller method looks like:
#RequestMapping(value = "register", method = RequestMethod.POST)
public #ResponseBody CustomAjaxResponse saveAgent(ModelMap model, #ModelAttribute("agent") #Valid Agent agent, BindingResult result) {
...
}
I suspect the problem is probably with my inheritance mapping because I have other classes inheriting from the Person class and I face a similar problem there as well.
Please help!
you need a public setter for id.
In cases like this I commonly use a specific dto for the form, and/or implement a conversion service that retrieves the entity via hibernate based on id and then performs a merge.