I'm trying to validate data in order to store it. But the serializer is removing valid fields. Here my code:
models.py
class MyModel(models.Model):
user_id = models.UUIDField('action uid',default=uuid.uuid4,null=False,primary_key=True,blank=False,editable=False, unique=True)
city = models.CharField('City', max_length=50, null=True, blank=True, editable=False)
latitude = models.CharField('Latitude', max_length=50, null=True, blank=True, editable=False)
longitude = models.CharField('Longitude', max_length=50, null=True, blank=True, editable=False)
datetime = models.DateTimeField('datatime', null=False, blank=False, editable=False)
serializer.py
class MyModelSerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
fields = '__all__'
view.py
def save_my_data(self, request):
user_info ={
"user_id": resquest.user.user_uid,
"city": resquest.user.city,
"latitude": "17.6801",
"longitude": "83.2016",
"datetime": timezone.now()
}
serializer = serializers.MyModelSerializer(data=user_info)
serializer.is_valid(raise_exception=True) # Not error thrown.
print( serializer.data ) # returns void
Any thoughts about this? thanks in advance.
You didn't call the .save() method of the serializer
serializer = serializers.MyModelSerializer(data=user_info)
serializer.is_valid(raise_exception=True)
print("This is validated data, ", serializer.validated_data)
serializer.save()
print("This is saved data, ", serializer.data)
Update
Some of the model fields are set as editable=False which causing the issue. DRF thinks that those fields shouldn't be edited, which in turns the fields into read_only.
So,
Method 1
Remove editable=False and migrate
class MyModel(models.Model):
user_id = models.UUIDField(
'action uid',
default=uuid.uuid4,
null=False,
primary_key=True,
blank=False,
editable=False,
unique=True
)
# other fields
Method 2
Explicitly define corresponding fields in the serializer class.
class MyModelSerializer(serializers.ModelSerializer):
user_id = serializers.UUIDField()
# other `editable=False` fields
class Meta:
model = MyModel
fields = '__all__'
Related
I have my DRF app. In my case, one wallet can have many entries such as income or expense. When I call my endpoint (viewset) I get data in this format:
[
{
"id": "d458196e-49f1-42db-8bc2-ee1dba438953",
"owner": 1,
"viewable": [],
"entry": []
}
]
How can I get the content of "entry" variable?.
class Category(models.Model):
name = models.CharField(max_length=20, unique=True)
def __str__(self):
return self.name
class BudgetEntry(models.Model):
STATE= [
('income','income'),
('expenses','expenses'),
]
amount = models.IntegerField()
entry_type = models.CharField(max_length=15, choices=STATE, null=True)
entry_category = models.ForeignKey(Category, null=True, blank=True, on_delete=models.SET_NULL)
class WalletInstance(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, unique=True)
owner = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='owner', on_delete=models.CASCADE)
viewable = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='can_view', blank=True)
entry = models.ManyToManyField(BudgetEntry, related_name='BudgetEntry', blank=True)
Serializers.py:
class BudgetEntrySerializer(serializers.ModelSerializer):
class Meta:
model = BudgetEntry
fields = '__all__'
class WalletInstanceSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.id')
class Meta:
model = WalletInstance
fields = '__all__'
Views.py:
class WalletViewset(viewsets.ModelViewSet):
permission_classes = [IsAuthenticated]
serializer_class = WalletInstanceSerializer
def get_queryset(self):
user_id = self.request.user.id
available = WalletInstance.objects.filter(
Q(owner=user_id)
)
return available
Change your serializer like this:
class WalletInstanceSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.id')
entry = BudgetEntrySerializer(many=True, read_only=True)
class Meta:
model = WalletInstance
fields = '__all__'
This is the model that I want to show on the admin panel. I'm registering the model via admin.py file with admin.site.register(Ad). I tried to re-write the register line twice, and an exception appeared that the model is already registered.
class Ad(AdModel):
plate = models.CharField(max_length=50, unique=True)
description = models.TextField(max_length=500)
ad_type = models.CharField(
max_length=255,
choices=AdTypes.get_choices(),
default=AdTypes.OFFERING,
)
price = models.PositiveIntegerField(
default=0,
help_text='In cents'
)
location = models.CharField(
max_length=255,
choices=AdLocations.get_choices(),
default=AdLocations.VILNIUS,
)
user = models.ForeignKey(User, on_delete=models.PROTECT)
approved_date = models.DateField(null=True, blank=True)
approved_by = models.ForeignKey(
User, on_delete=models.PROTECT, related_name='approved_by', null=True
)
The two base models:
class UUIDBaseModel(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
uuid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
class Meta:
abstract = True
class AdModel(UUIDBaseModel):
expires_at = models.DateTimeField(null=True)
is_draft = models.BooleanField(default=False)
is_active = models.BooleanField(default=False)
class Meta:
abstract = True
This is really strange, maybe that could be the problem because of the naming 'Ad'? I have a serializer for this model and everything works just fine, but the admin panel doesn't want to display it.
views.py
class AdCreateViewSet(ModelViewSet, CreateModelMixin):
serializer_class = AdCreateSerializer
permission_classes = (AllowAny,)
filter_backends = [DjangoFilterBackend]
search_fields = ('plate', 'description', 'user__email')
queryset = Ad.objects.select_related('user')
def perform_create(self, serializer):
user = User.objects.first()
serializer.save(user=user) # self.request.user)
serializers.py
class AdCreateSerializer(CustomAdSerializer):
class Meta:
model = Ad
exclude = ['expires_at']
read_only_fields = ('user',)
I am using Django-rest-auth to authenticate my users, that works well. how my model is set up is that I have the custom user model for authentication and I also have a profile model that gets created with a signal whenever a user is created.
I want that when the users are fetched in its URL, the profile for that user is also displayed, and I have passed through the serializer.
THE PROBLEM: I am getting null instead of the actual data
my models.py (I didnt include some models like the user managers, skill, e.t.c as i felt they werent relevant)
class User(AbstractBaseUser, PermissionsMixin):
username = None
email = models.EmailField(max_length=254, unique=True)
fullname = models.CharField(max_length=250)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
last_login = models.DateTimeField(null=True, blank=True)
date_joined = models.DateTimeField(auto_now_add=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['fullname']
objects = UserManager()
class Profile(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='profiles')
date_of_birth = models.DateField(blank=True, verbose_name="DOB", null=True)
bio = models.TextField(max_length=500, blank=True, null=True)
profile_photo = models.CharField(blank=True, max_length=300, null=True)
skills = models.ManyToManyField(Skill, related_name='skills')
sex = models.CharField(max_length=1, choices=SEX, blank=True, null=True)
type_of_body = models.CharField(max_length=8, choices=BODYTYPE, blank=True, null=True)
feet = models.PositiveIntegerField(blank=True, null=True)
inches = models.PositiveIntegerField(blank=True, null=True)
lives_in = models.CharField(max_length=50, blank=True, null=True)
updated_on = models.DateTimeField(auto_now_add=True)
the serializers.py code
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = "__all__"
read_only_fields = ('pk',)
class CustomUserDetailsSerializer(serializers.ModelSerializer):
profiles = ProfileSerializer(read_only=True)
class Meta:
model = User
fields = ('pk', 'email', 'fullname', 'profiles')
read_only_fields = ('email', 'fullname', 'profiles')
view.py
class ListUsersView(APIView):
permission_classes = [AllowAny]
def get(self, request):
user = User.objects.all()
serializer = CustomUserDetailsSerializer(user, many=True)
return Response(serializer.data)
urls.py
url(r'^list-users/$', ListUsersView.as_view(), name='list-users'),
the JSON response I get
[
{
"pk": 1,
"email": "opeyemiodedeyi#gmail.com",
"fullname": "opeyemi odedeyi",
"profiles": {
"date_of_birth": null,
"bio": null,
"profile_photo": null,
"sex": null,
"type_of_body": null,
"feet": null,
"inches": null,
"lives_in": null
}
}
]
how do I get the profiles to show in the response?
I guess the problem is in your CustomUserDetailsSerializer. you have one-to-many relationship with User and Profile, but you are not explicitly telling it in your profiles attribute of the serializer. You have to pass many=True argument to the ProfileSerializer:
class CustomUserDetailsSerializer(serializers.ModelSerializer):
profiles = ProfileSerializer(many=True, read_only=True)
class Meta:
model = User
fields = ('pk', 'email', 'fullname', 'profiles')
read_only_fields = ('email', 'fullname', 'profiles')
But I am curious why you are using one-to-many relationship for that. You could use OneToOneField which explicitly tells that one user can only have one profile. But I am not familiar with your situation, so that is only my advice.
I am trying to implement simple api in Django Rest Framework.
I have following models in models.py:
class Entry(BaseModel):
company_name = models.CharField(max_length=256, null=True, blank=True)
first_name = models.CharField(null=True, default=None, max_length=32)
last_name = models.CharField(null=True, default=None, max_length=32)
code = models.CharField(null=True, default=None, max_length=12)
class Meta:
db_table = 'entry'
class Admin(admin.ModelAdmin):
list_display = ('company_name', 'code')
list_display_links = ('company_name', )
ordering = ('-created',)
class EntryContactData(BaseModel):
entry = models.ForeignKey(Entry, related_name='contact')
email = models.CharField(max_length=256, null=True, blank=True)
website = models.CharField(max_length=64, null=True, blank=True)
phone = models.CharField(max_length=64, null=True, blank=True)
My API serializers.py:
from django.contrib.auth.models import User, Group
from rest_framework import serializers
from core.models import Entry, EntryContactData
class EntryContactSerializer(serializers.ModelSerializer):
class Meta:
model = EntryContactData
fields = ('uuid', 'email', 'website', 'phone')
class EntrySerializer(serializers.ModelSerializer):
contact = EntryContactSerializer(many=False, read_only=True)
class Meta:
model = Entry
fields = ('uuid', 'company_name', 'first_name', 'last_name', 'contact')
And my API views:
from core.models import Entry
from .serializers import EntrySerializer
class EntryViewSet(viewsets.ViewSet):
"""
A simple ViewSet for listing or retrieving users.
"""
queryset = Entry.objects.all()
def retrieve(self, request, pk=None):
queryset = Entry.objects.all()
entry = get_object_or_404(queryset, code=pk)
serializer = EntrySerializer(entry, context={'request': request})
return Response(serializer.data)
When I want to retrieve single entry its contact field is empty:
{
"uuid": "e6818508-a172-44e1-b927-3c087d2f9773",
"company_name": "COMPANY NAME",
"first_name": "FIRSTNAME",
"last_name": "LASTTNAME",
"contact": {}
}
So it doesn't contain any of fields defined in EntryContactSerializer
What am I doing wrong? How can I force it to return all fields included in serializer? Thank you guys.
Try setting many=True in EntrySerializer, and provide a source attribute to the serializer,
class EntrySerializer(serializers.ModelSerializer):
contact = EntryContactSerializer(source='contact', many=True, read_only=True)
class Meta:
model = Entry
fields = ('uuid', 'company_name', 'first_name', 'last_name', 'contact')
I'm facing a problem using python2.7 with django rest-framework. When I serialize my JSON data, a field is omitted by the serializer and I don't understand why. Here is some details.
The missing field is "country". When I'm doing POST or PUT requests on /campaigns/:id
class CampaignSerializer(serializers.HyperlinkedModelSerializer):
created_by = UserFullSerializer(read_only=True)
country = CountrySerializer(read_only=True)
class Meta:
model = Campaign
fields = ('id', 'created_by', 'name', 'media', 'status', 'begin', 'end', 'country')
class CampaignFullSerializer(serializers.HyperlinkedModelSerializer):
client = ClientSerializer(read_only=True)
collection = CollectionSerializer(read_only=True)
created_by = UserFullSerializer(read_only=True)
updated_by = UserFullSerializer(read_only=True)
channels = ChannelSerializer(read_only=True, many=True)
country = CountrySerializer(read_only=True)
class Meta:
model = Campaign
fields = ('id',
'client',
'name',
'media',
'status',
'begin',
'end',
'created_at',
'created_by',
'updated_at',
'updated_by',
'collection',
'channels',
'country')
class CountrySerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Country
fields = ('id', 'name', 'code')
class Country(models.Model):
name = models.CharField(max_length=255)
code = models.CharField(max_length=255)
class Campaign(models.Model):
name = models.CharField(max_length=255)
media = models.IntegerField(choices=constant.MEDIA_CHOICES, default=0)
status = models.IntegerField(choices=constant.STATUS_CHOICES, default=2)
created_at = models.DateTimeField(auto_now_add=True)
created_by = models.ForeignKey(User, blank=True, null=True, related_name="created_by")
updated_at = models.DateTimeField(auto_now_add=True, blank=True, null=True)
updated_by = models.ForeignKey(User, blank=True, null=True, related_name="updated_by")
client = models.ForeignKey(client.Client)
begin = models.DateField(blank=True, null=True)
end = models.DateField(blank=True, null=True)
collection = models.ForeignKey(collection.Collection, blank=True, null=True)
country = models.ForeignKey(country.Country, blank=True, null=True)
mediaplan = models.ForeignKey(mediaplan.Mediaplan, blank=True, null=True, default=None)
channels = models.ManyToManyField(channel.Channel)
When I'm doing POST on /campaign/id with the following JSON, everything works except the country field.
{
...
"channels": [],
"country": {
"id": 74,
"name": "France",
"code": "FR"
}
On the controller side when I print the request.data I got all the fields. I'm not overriding the create method of the controller.
{
...
u'country': {u'code': u'AL', u'id': 3, u'name': u'Albania'}
}
My controller looks like:
class CampaignViewSet(viewsets.ModelViewSet):
queryset = Campaign.objects.all()
serializer_class = CampaignSerializer
def create(self, request):
logger.info(request.data)
return super(CampaignViewSet, self).create(request, *args, **kwargs)
I tried to override the create method of my CountrySerializer and when I print the content of validated_data, the country field is missing in the OrderedDict..
class CountrySerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Country
fields = ('id', 'name', 'code')
def create(self, validated_data):
logger.info(validated_data)
I'm really lost, I can't find my mistake, maybe you will. Thanks for your time.
Your CountrySerializer is read only as a nested serializer by default (per http://www.django-rest-framework.org/api-guide/relations/#nested-relationships) so you have to override the create/update method of the Campaign serializer for POST/PUT. You've tried to override it on the Country serializer instead.