Is there a way to bypass Django Rest Framework validators in nested serialization without overwriting the validators on the original serializers?
Example :
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('username')
class TaskSerializer(serializers.ModelSerializer):
owner = UserSerializer()
class Meta:
model = models.Task
If I try to update or create a Task I'll get a unicity error, because DRF use the unique constraint on the username field of the User model.
The solution I have found is to overwrite the validators on the UserSerializer:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('username')
extra_kwargs = {
'username': {
'validators': []
}
Is there a way to bypass this validation without overwriting the validators directly in the UserSerializer?
By overwriting this validator I have to rewrite every constraints that I defined on my model.
A solution like below would have been nice, since it would have allow to bypass the validators only in the TaskSerializer without overwriting the initial UserSerializer.
class TaskSerializer(serializers.ModelSerializer):
owner = UserSerializer(validators=[])
class Meta:
model = models.Task
Related
How do I enable RestfulController to auto-map or even manually map the dynamic fields to domain classes implementing MongoEntity? I have a domain class as below:
class Company implements MongoEntity<Company> {
String id = UUID.randomUUID().toString()
String name
String email
String phone
}
And I have a RestfulController setup for CRUD operations as below
class CompanyController extends RestfulController<Company> {
#Transactional
def save(Company company) {
if(company.hasErrors()) {
respond company.errors
}
else {
company.insert(flush:true)
respond company, status: CREATED
}
}
}
When I POST a request with some additional JSON fields, how do I get them auto-mapped to gorm_dynamic_attributes ? Currently the company object does not return any information on the dynamic attributes. Another problem I am facing is that request.JSON is also null so I cannot manually map either. Any suggestions would be highly appreciated.
I'm pretty sure, that the problem is not in data binding of your controller, but rather in persisting of the domain class instance.
I would change the domain class like so:
import grails.gorm.annotation.Entity
#Entity
class Company {
String id
String name
String email
String phone
def beforeValidate() {
if( !id ) setId UUID.randomUUID().toString()
}
static mapping = {
id generator:'assigned'
}
}
to use the assigned generator. You could put your id generation either in the controller / service code, or leave it inside the domain class' beforeValidate. In the later case pay special attention to when the id shall be generated, as beforeValidate() is called pretty often. Also note, that inside beforeValidate() a setter must be called.
I tested the similar domain class of mine with save() and insert() and in both cases that works like charm.
The django-rest-auth returns a token after successful authentication using rest_auth.serializers.TokenSerializer. How can I override this serializer or add my own so that I can get the user info like username, instead of token key after successful authentication?
I solved the problem by defining a custom serializer.
from django.contrib.auth.models import User
from rest_framework import serializers
from rest_auth.models import TokenModel
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('username', 'email')
class TokenSerializer(serializers.ModelSerializer):
user = UserSerializer()
class Meta:
model = TokenModel
fields = ('key', 'user')
You can also use the depth option to easily generate nested representations, but in that case, you will receive the password field as well, which is not expected and intended.
Declaring session model attribute as:
#SessionAttributes ("customer")
Controller code is basically to modify the customer object :
#RequestMapping(value="/testlink", method=RequestMethod.GET)
public String testLinkHandler(ModelMap modelMap){
customerDao.getCustomer(111);
modelMap.put("customers", customerDao.getCustomers());
Customer cust = customerDao.getCustomer(115);
if (cust == null){
cust = new Customer();
}
modelMap.put("customer", cust);
return "testlink";
}
#RequestMapping(value="/testlink", method=RequestMethod.POST)
public String testLinkHandler(#ModelAttribute Customer customer){
customerDao.save(customer);
return "redirect:/testlink";
}
With above code in POST method Customer object is loaded from session & posted new customer name with proper id and hence Editing the Customer works perfectly and updates DB with modified customer Name.
But the moment I change the model variable name and the #SessionAttribute name from "customer" to say "customerModel" or "customer_model" or "model" it doesn't work anymore and above code inserts a new record in DB.
So the question is, Is there a naming convention that needs to be followed here?
public String testLinkHandler(#ModelAttribute Customer customer){ ... }
This method expects an object named customer to be available for binding. When using #ModelAttribute without attributes Spring MVC tries to deduce the name of the model attribute from the method argument name.
Now if you decide to rename your model attribute you either have to
Rename the method argument accordingly
Supply the name to the #ModelAttribute.
As I wouldn't suggest option 1, that leaves option 2.
public String testLinkHandler(#ModelAttribute("your-model-name-here") Customer customer){ ... }
With #SessionAttribute, Spring obtains an instance of model attribute from the session.
Hence model attribute field name should match with the session attribute name,in this case customer
If you require changing of the attribute name then you can use :
#SessionAttributes (types = {Customer.class})
Now, whenever you put your modelClass of the type Customer in spring Model then it would automatically be set in the session.
I’m dealing with a set of Model classes which share some common attributes via inheritance:
class MyBaseModel(models.Model):
class Meta:
abstract = True
unique_together = (('system', 'code',),)
id = models.UUIDField(default=uuid.uuid4, primary_key=True, unique=True, ...
system = models.ForeignKey(System, ...
code = models.CharField(...
...
class ModelA(MyBaseModel):
...
class ModelB(MyBaseModel):
...
Please note the presence of a unique_together constraint in Meta class.
A similar hierarchy would be convenient for the corresponding serializers;
I'm not sure whether I need to explicitly specify a UniqueTogetherValidator,
and currently investigating on this.
But in case, I wonder how to express it in the base serializer class, as it
requires a queryset which is not known in advance:
from rest_framework import serializers
from rest_framework.validators import UniqueTogetherValidator
class MyBaseModelSerializer(serializers.ModelSerializer):
class Meta:
exclude = ['date_created', 'created_by', ...
validators = [
UniqueTogetherValidator(
queryset=???.objects.all(),
fields=('system', 'code')
)
]
class ModelASerializer(MyBaseModelSerializer):
class Meta(MyBaseModelSerializer.Meta):
model = ModelA
...
class ModelBSerializer(MyBaseModelSerializer):
class Meta(MyBaseModelSerializer.Meta):
model = ModelB
...
How can I avoid repeating it for every single derived class, as in the following
example ?
from rest_framework import serializers
from rest_framework.validators import UniqueTogetherValidator
class MyBaseModelSerializer(serializers.ModelSerializer):
class Meta:
exclude = ['date_created', 'created_by', ...
class ModelASerializer(MyBaseModelSerializer):
class Meta(MyBaseModelSerializer.Meta):
model = ModelA
validators = [
UniqueTogetherValidator(
queryset=ModelA.objects.all(),
fields=('system', 'code')
)
]
...
class ModelBSerializer(MyBaseModelSerializer):
class Meta(MyBaseModelSerializer.Meta):
model = ModelB
validators = [
UniqueTogetherValidator(
queryset=ModelB.objects.all(),
fields=('system', 'code')
)
]
...
Model Serializer adds the UniqueTogetherValidator from model's unique_together constraints. You don't have give seperately.
need override
unique_together = (('system', 'code',),)
in non abstract model
I am using Spring Security plugin in my grails app. I have extended Springs User class in my own generated Physician class. Now when I run app I am not getting physician table in database instead User class only has all properties defined in Physician Domain. I need to have separate table for Physician.
When I try to find all Users in User table with User.findAll() my output is,
[com.HospitalManagement.User : 1, com.HospitalManagement.User : 2, com.HospitalManagement.User : 3, com.HospitalManagement.User : 4, com.HospitalManagement.User : 5, com.HospitalManagement.User : 6, com.HospitalManagement.User : 7, com.HospitalManagement.User : 8, com.HospitalManagement.User : 9]
but I was expecting username and other physician properties values.
What could the problem be?
Domain Class is:
package com.HospitalManagement
class Physician extends User{
static constraints = {
}
String specilty;
String MobileNo;
String Physician_Address;
String clinicals;
}
By default, GORM uses a table-per-hierarchy model for domain classes with inheritance. All fields in the parent class and all fields in each subclass will be stored in a single table.
If you want to turn off this functionality, you can use the tablePerHierarchy mapping parameter. Setting this parameter to false will put the parent class fields in a common parent table, and put the fields for each subclass in their own table. This can make your queries slightly less efficient because the queries will will have joins, but if the inheritance tree is small, the difference should be negligible. Here's what it would look like with your domain class:
package com.HospitalManagement
class Physician extends User {
static constraints = {
}
String specilty;
String MobileNo;
String Physician_Address;
String clinicals;
static mapping = {
tablePerHierarchy false
}
}
See The grails documentation for more information:
Inheritance Strategies
Inheritance in GORM
If you want each subclass to have it's own table which contains all fields from the parent class and all fields from the subclass, then you can define the parent class as 'abstract' and that should prevent grails from making a separate table for it. Grails should only create tables for concrete domain classes, not abstract domain classes. [Source]
Your user class would look then look something like this:
abstract class User {
String username
String password
//etc...
}
This will build the tables correctly, though I'm not sure what effect it might have on Spring Security. If you see any Spring Security errors after making the User class abstract, I'd fall back to disabling table-per-hierarchy and dealing with the joins.
It sounds like you're trying to display the attributes of an object. Perhaps you just want to override toString() for your Physician class:
package com.HospitalManagement
class Physician extends User{
static constraints = {
}
String specilty;
String MobileNo;
String Physician_Address;
String clinicals;
String toString() {
"specilty: $specilty, MobileNo: $MobileNo, Physician_Address: $Physician_Address, clinicals: $clinicals"
}
}
or something like that, depending on how you want the output to be formatted.