I have created slicing in views but how to do that using rest framework in django.
username = email
username = username.split("#")
real_username = username[0]
I have done this in views, here is my serializers:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = "all"
class DetailSerializers(serializers.ModelSerializer):
class Meta:
model = Data
fields = "all"
You can override to_internal_value method in your serializer class and write your custom logic there.
You can look at it in docs: https://www.django-rest-framework.org/api-guide/serializers/#advanced-serializer-usage
Related
I feel like this is a super basic question but am having trouble finding the answer in the DRF docs.
Let's say I have a models.py set up like so:
#models.py
class Person(models.Model):
name = models.CharField(max_length=20)
address = models.CharField(max_length=20)
class House(models.Model):
name = models.CharField(max_length=20)
owner = models.ForeignKey(Person)
And I have a ModelSerializer set up like so:
#serializers.py
class House(serializers.ModelSerializer):
class Meta:
model = House
fields = '__all__'
What I want to do is to be able to POST new House objects but instead of having to supply the pk of the Person object, I want to be able to supply the name of the Person object.
E.g.
post = {'name': 'Blue House', 'owner': 'Timothy'}
The actual models I'm using have several ForeignKey fields so I want to know the most canonical way of doing this.
One solution may be to use a SlugRelatedField
#serializers.py
class House(serializers.ModelSerializer):
owner = serializers.SlugRelatedField(
slug_field="name", queryset=Person.objects.all(),
)
class Meta:
model = House
fields = '__all__'
This will also change the representation of your serializer though, so it will display the Person's name when you render it. If you need to render the Person's primary key then you could either override the House serializers to_representation() method, or you could implement a small custom serializer field by inheriting SlugRelatedField and overriding to_representation() on that instead.
Change your serializer as below by overriding the create() method
class House(serializers.ModelSerializer):
owner = serializers.CharField()
class Meta:
model = House
fields = '__all__'
def create(self, validated_data):
owner = validated_data['owner']
person_instance = Person.objects.get(owner=owner)
return House.objects.create(owner=person_instance, **validated_data)
I'm using django-rest-framework. I have a serializer with nested data and I want to hide a specific field (password):
class MyUser(models.Model):
# django's auth model
user = models.OneToOneField(User)
class MyUserSerializer(serializers.ModelSerializer):
username = serializers.CharField(source="user.username")
password = serializers.CharField(source="user.password")
# Other fields related to MyUser model
class Meta:
model = MyUser
fields = ( ..., "password")
write_only_fields = ("password",)
The first problem is that if I remove password from fields it will error saying that I have password defined but it's not found in the fields list.
write_only_fields does not having any effect on password; it's always returned.
Is there a way to keep the password for write only and remove it from the result?
I solved it by removing write_only_fields and modified the field itself to write_only:
password = serializer.CharField(source="user.password", write_only=True).
I have no idea why write_only_fields and extra_kwargs did not work.
It didn't work because the write_only_fields attribute of Meta class only overrides the implicit fields (the ones that are only listed in the Meta class fields attributes, and not defined in the ModelSerializer scope) write_only attribute to be True. If you declare a ModelSerializer field explicitly you must define all the attributes that are not default for it to work.
The right code should be something like:
class MyUser(models.Model):
# django's auth model
user = models.OneToOneField(User)
class MyUserSerializer(serializers.ModelSerializer):
username = serializers.CharField(source="user.username")
password = serializers.CharField(source="user.password", write_only=True)
# Other fields related to MyUser model
class Meta:
model = MyUser
fields = ( ..., "password")
write_only_fields = ("password",)
You can also override the function that builds the nested fields. Good choice for when you want to display the default auth_user's name in a nested ListView.
from rest_framework.utils.field_mapping import get_nested_relation_kwargs
def build_nested_field(self, field_name, relation_info, nested_depth):
"""
Create nested fields for forward and reverse relationships.
"""
class NestedSerializer(serializers.ModelSerializer):
class Meta:
model = relation_info.related_model
depth = nested_depth - 1
fields = ['username'] # Originally set to '__all__'
field_class = NestedSerializer
field_kwargs = get_nested_relation_kwargs(relation_info)
return field_class, field_kwargs
I have written basic model serializers in Django where the api mimics the data model. I now have a requirement to store User Preference in database. The api contains an array.
My User Models :
class User(models.Model):
email_id = models.EmailField(max_length=80, blank=True, primary_key=True)
class UserPreference(models.Model)
email_id = models.ForeignKey('User')
preference = models.CharField(maxlength=20)
An ideal json post request would look something like this
{
email:"abhishek#gmail.com"
preference : [ 'books', 'food', 'lifestyle', 'travel']
}
I wish to save this json schema to the UserPreference model. This requires multiple inserts for preference. What will be a good serializer design for it ?
I tried
class UserPreferenceSerializer(serializers.ModelSerializer):
class Meta:
model = UserPreference
fields = ('email_id', 'preference')
you could use StringRelatedField of Django Rest Framework.
Make below changes and you will get the response in the way you want.
models.py (put related_name there)
class UserPreference(models.Model):
email_id = models.ForeignKey(User, related_name='preference')
preference = models.CharField(maxlength=20)
serializers.py
class UserSerializer(serializers.ModelSerializer):
preference = serializers.StringRelatedField(many=True)
class Meta:
model = User
fields = ('email_id', 'preference')
You could make your model like this:
class UserPreference(models.Model)
email_id = models.ForeignKey('User')
preference = models.ManyToManyField('Preference') #create model for preferences
Then add custom create method to your serializer:
def create(self, validated_data):
user = self.context.get('user') #you can pass context={'user': self.request.user} in your view to the serializer
up = UserPreference.objects.create(email_id=user)
up.save()
preference = validated_data.get('preference', [])
up.preference.add(*preference)
up.save()
return up
Consider the following serializer
class MyModelSerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
fields = ('id', 'account')
depth = 1
The field account refers to a ForeignKey in MyModel and I want to expose some of the Account fields with this serializer but not all of them.
How do I specify that only account.name and account.email should be serialized?
You can do this by creating your own serializer to use as the nested serializer.
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields = ('name', 'email', )
You are better off with creating specialized serializers instead of relying on Django REST Framework to create them for you. By default, serializers that are automatically created contain all fields defined on the model.
class MyModelSerializer(serializers.ModelSerializer):
account = AccountSerializer()
class Meta:
model = MyModel
fields = ('id', 'account', )
You can find out more about nested serializers in the Django REST Framework documentation.
I've got a simple newsletter app with a subscription model with fields email and city.
In this model I set unique_together('email', 'city') to avoid having subscription duplicates.
class Subscription(models.Model):
email = models.EmailField(_('Email'), max_length=75)
create_date = models.DateField(_("Creation Date"))
city = models.ForeignKey(City)
class Meta:
unique_together = ('email', 'city')
I created a forms.ModelForm from this model:
class SubscriptionForm(forms.ModelForm):
class Meta:
model = Subscription
This is ok when I create a subscription, but when I want to delete a subscription, using the same form, the form does not validate when setting an existing email/subject pair because of the unique_together in the model. Is there any way to bypass this validation rule or should I write a specific form to unsubscribe?
Thank you
You can probably override the unique_together in your SubscriptionForm but this will remove the validation from your form (and will fail when you will save your model).
Or you can create a new UnSubscriptionForm that will override this unique_together setting only for unsubscription.