I have a nested serializer which creates the objects like they are supposed to but also return an error.
Models:
class Trip(models.Model):
startTime = models.DateTimeField()
endTime = models.DateTimeField()
def __str__(self):
return str(self.startTime) + " - " + str(self.endTime)
class TripFaceDetection(models.Model):
trip = models.ForeignKey(Trip, on_delete=models.CASCADE, blank=True)
firstFace = models.DateTimeField()
lastFace = models.DateTimeField()
faceCount = models.IntegerField()
Serializers:
class TripSerializer(serializers.ModelSerializer):
faces = TripFaceDetectionSerializer()
class Meta:
model = Trip
fields = ('id', 'startTime', 'endTime', 'faces')
def create(self, validated_data):
face_data = validated_data.pop('faces')
trip = Trip.objects.create(**validated_data)
TripFaceDetection.objects.create(trip=trip, **face_data)
return trip
The objects are created but I also get the error:
backend_1 | AttributeError: Got AttributeError when attempting to get a value for field faces on serializer TripSerializer.
backend_1 | The serializer field might be named incorrectly and not match any attribute or key on the Trip instance.
I understand I don't have the field within the Trip model, but I expect that since I define the field in the serializer and create it in the create method that it shouldn't return this error.
How can I get rid of this error while using faces for both reading/writing as well as leaving my model structure as-is?
Related
I'm Overriding create method of serializer in order to manipulate validated_data and create object in a model, Although it works, in the end I get below error, i am not able to figure out why after lot of research.
AttributeError: Got AttributeError when attempting to get a value for field `shift_time` on serializer `PunchRawDataAndroidSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `PunchRawData` instance.
Original exception text was: 'PunchRawData' object has no attribute 'shift_time'.
class PunchRawDataAndroidSerializer(serializers.ModelSerializer):
employee_id = serializers.CharField()
shift_id = serializers.CharField()
work_location_id = serializers.CharField()
shift_time = serializers.TimeField()
class Meta:
model = PunchRawData
fields = ['employee_id', 'shift_id','work_location_id', 'punch_type', 'actual_clock_datetime',
'emp_photo', 'created_at', 'updated_at','shift_time']
def create(self, validated_data):
validated_data.pop('shift_time')
request_data = self.context.get('request')
user = request_data.user
validated_data['user'] = user
data = validated_data
return PunchRawData.objects.create(**data)
class PunchRawDataAndroidViewSet(viewsets.ModelViewSet):
serializer_class = PunchRawDataAndroidSerializer
parser_classes = (MultiPartParser, FileUploadParser)
edit:
class PunchRawData(models.Model):
PUNCH_TYPES = [("in", "Punch IN"), ("out", "Punch Out")]
employee = models.ForeignKey(Employee, related_name="punch_employee", on_delete=models.CASCADE)
shift = models.ForeignKey(WorkShift, on_delete=models.CASCADE)
work_location = models.ForeignKey(HRMLocation, blank=True, on_delete=models.CASCADE,
null=True, related_name="punch_work_location")
punch_type = models.CharField(max_length=255, null=True, blank=True, choices=PUNCH_TYPES)
user = models.ForeignKey("useraccounts.User", on_delete=models.CASCADE)
actual_clock_datetime = models.DateTimeField(null=True, blank=True)
emp_photo = models.ImageField(upload_to="selfies/%Y/%m/%d/%I/%M/%S/")
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
strl = "{emp_id} [{shift_id}]".format(emp_id=self.employee.emp_id,
shift_id=self.shift.shift_id)
return strl
class Meta:
verbose_name = "Punch Raw Data"
verbose_name_plural = "Punch Raw Data"
I get shift_time from frontend and it is not from model, hence i'm poping it out from validated_data in create method. is error related to modelviewset?
Your model doesn't have the shift_time attribute. So if you try to save it, you will end with
PunchRawData() got an unexpected keyword argument 'shift_time'
At the other hand you are getting AttributeError, because serializers.to_representation() tries to get a non-existing attribute when showing your freshly saved object.
If this should be a read-only attribute, you may do the following:
shift_time = serializers.TimeField(read_only=True)
and than remove the
validated_data.pop('shift_time')
from PunchRawDataAndroidSerializer.create(). You don't need this any more, because it is never submitted from your client.
If you need the opposite – your client should provide you that field, but you don't want it saved in your model, than the only thing, you should do, is:
shift_time = serializers.TimeField(write_only=True)
And if you need it to be bidirectional, than you should add it to your model.
Hope this helps.
Adding to #wankata's answer we can override __init__ method to have write_only field for only create method.
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.context['view'].action == 'create':
self.fields['shift_time'].write_only = True
Generic viewsets of django-rest-framework return the serialized representation of the model in response, so it's try to serialize the model including the shift_time key.
To avoid this problem you can specify the shift_time field as write_only. documentation
modify the Meta class on your model
class Meta:
model = PunchRawData
fields = ['employee_id', 'shift_id','work_location_id', 'punch_type', 'actual_clock_datetime',
'emp_photo', 'created_at', 'updated_at','shift_time']
extra_kwargs = {'shift_time': {'write_only': True}}
I am Django rest framework to return the list of objects who do not have a foreign key in another table. what queryset should I write to get those objects.
models.py
class Event(models.Model):
id = models.IntegerField(primary_key=True)
title = models.CharField(max_length=100,default='')
description = models.TextField(blank=True,default='', max_length=1000)
link = models.URLField(null=True)
image = models.ImageField(null=True, blank=True)
organizer = models.CharField(max_length=100, default='')
timings = models.DateTimeField(default=None)
cost = models.IntegerField(default=1,null=True,blank=True)
def __str__(self):
return self.title
class Featured(models.Model):
event = models.ForeignKey(Event, null=True ,on_delete=models.PROTECT, related_name="event")
def __str__(self):
return self.event.title
class Meta:
verbose_name_plural = 'Featured'
views.py
class Upcoming2EventsViewSet(mixins.RetrieveModelMixin,mixins.ListModelMixin,viewsets.GenericViewSet):
serializer_class = Upcoming2Events
def get_queryset(self):
featured_events = Featured.objects.all().values_list('id')
return Event.objects.filter(id__in=featured_events)
# return Event.objects.exclude(id__in=featured_events.event.id)
# # return Event.objects.exclude(id__in = [featured_events.id])
serializers.py
class Upcoming2Events(serializers.ModelSerializer):
id = serializers.CharField(source='event.id')
title = serializers.CharField(source='event.title')
timings = serializers.DateTimeField(source='event.timings')
organizer = serializers.CharField(source='event.organizer')
class Meta:
model = Featured
fields = ['id','title','organizer','timings']
Error
Got AttributeError when attempting to get a value for field `id` on serializer `Upcoming2Events`.
The serializer field might be named incorrectly and not match any attribute or key on the `Event` instance.
Original exception text was: 'RelatedManager' object has no attribute 'id'.
Can you tell me what queryset should I write to get the only objects which are not present in the table Featured?
Also, what should I do to get only the upcoming 2 events from the Event table which are not present in the Featured table?
Note I am not supposed to use any flag value, can you provide some other solutions?
Based on the Informations you wrote here, i would suggest using a flag to determine a featured event. A second Model is useful if you want to provide more Informations on this specific for a featured event
like this:
class Event(models.Model):
id = models.IntegerField(primary_key=True)
title = models.CharField(max_length=100,default='')
description = models.TextField(blank=True,default='', max_length=1000)
link = models.URLField(null=True)
image = models.ImageField(null=True, blank=True)
organizer = models.CharField(max_length=100, default='')
timings = models.DateTimeField(default=None)
cost = models.IntegerField(default=1,null=True,blank=True)
featured = models.BooleanField(default=False)
so you can directly use querysets to get what you want:
Event.objects.exclude(featured=True)
Event.objects.exclude(featured=True).order_by('-timings')[:2]
I would use ModelViewsets directly, hence you will use your model here.
views and serializers would look like this:
views.py
class Upcoming2EventsViewSet(viewesets.ReadyOnlyModelViewSet):
serializer_class = EventSerializer
queryset = Event.objects.exclude(featured=True).order_by('-timings')[:2]
serializers.py
class EventSerializer(serializers.ModelSerilizer):
class Meta:
model = Event
fields = ['id', 'title', 'organizer', 'timings']
As improvement i would provide filters instead of setting up different ViewSets for just filtering querysets.
I'm trying to retrieve only some of the fields in the "Appointments" associated to a rental property "Unit". From the UnitSerializer, I call a SerializerMethodField() to do a reverse lookup for the "appointment" field. This works out well. However, the queryset returns all the fields (id, time, unit, staff, prospect) in each object, when I only need a few (id, time).
I tried .values() on the queryset like so:
queryset = instance.appointment_set.values('id', 'appointment_time')
But I get "Got KeyError when attempting to get a value for field unit on serializer AppointmentSerializer.\nThe serializer field might be named incorrectly and not match any attribute or key on the dict instance.\nOriginal exception text was: unit."
Note sure if you need all the code, but here's the essential.
Models
class Appointment(models.Model):
appointment_time = models.DateTimeField()
unit = models.ForeignKey(Unit, on_delete=models.CASCADE)
staff = models.ForeignKey(Staff, on_delete=models.CASCADE)
prospect = models.ForeignKey(Prospect, on_delete=models.CASCADE)
Serializers
class AppointmentSerializer(serializers.ModelSerializer):
class Meta:
model = Appointment
fields = ['id','appointment_time']
class UnitSerializer(serializers.ModelSerializer):
appointment = SerializerMethodField()
class Meta:
model = Unit
fields = ['id', 'address', 'appointment']
def get_appointment(self, instance):
cutoff = _datetime.date.today() + timedelta(hours=72)
queryset = instance.appointment_set.exclude(appointment_time__gt=cutoff)
return AppointmentSerializer(queryset, many=True).data
There is a better way to handle reverse relationship in serializer:
class UnitSerializer(ModelSerializer):
appointment = AppointmentSerializer(many=True, source='appointment_set')
class Meta:
model = Unit
fields = ['id', 'address', 'appointment']
I'm using a Polymorphic model for setting up notifications:
My models:
class Notification(PolymorphicModel):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
created_by = models.ForeignKey(ElsUser, on_delete=models.CASCADE, default=None, related_name="creatednotifications")
created_on = models.DateTimeField(default=timezone.now)
created_for = models.ForeignKey(ElsUser, on_delete=models.CASCADE, default=None, related_name="receivednotifications")
read = models.DateTimeField(default=None, null=True, blank=True)
message = models.CharField(default=None, blank=True, null=True, max_length=800)
#property
def total(self):
return self.objects.filter(created_for=self.request.user).count()
#property
def unread(self):
return self.objects.filter(created_for=self.request.user,read=None).count()
#property
def read(self):
return self.objects.filter(created_for=self.request.user).exclude(read=None).count()
class WorkflowNotification(Notification):
# permission_transition = models.ForeignKey(WorkflowStatePermissionTransition, on_delete=models.CASCADE)
action = models.ForeignKey(UserAction, on_delete=models.CASCADE)
Currently i have just one model WorkFlowNotification inheriting from the Polymorphic model,but many would be there in the future.
Im trying to get the count(total) of notifications for the logged in user in the API ..total is given as property field to help in the same
my serializer:
class NotificationSerializer(serializers.ModelSerializer):
total = serializers.ReadOnlyField()
read = serializers.ReadOnlyField()
unread = serializers.ReadOnlyField()
class Meta:
model = Notification
fields = ['id', 'total','read', 'unread']
In the view:
class NotificationsMeta(generics.ListAPIView):
serializer_class = NotificationSerializer
queryset = Notification.objects.all()
When i try to run the server it shows:
Got AttributeError when attempting to get a value for field `total` on serializer `NotificationSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `WorkflowNotification` instance.
Original exception text was: Manager isn't accessible via WorkflowNotification instances.
Since you need the 'meta data' only, what is the use of making a model serializer? Or any serializer, for that matter? Serializers will give you serialized instances of the objects of your model. So if you have multiple objects, you will get multiple serialized objects in response.
Just make your view a normal APIView. Since there is no necessity of serializing anything.
class NotificationsMeta(APIView):
def get(self, request, format=None):
qs = Notification.objects.filter(created_for=self.request.user)
response = {
'total': qs.count(),
'read': qs.filter(read=None).count(),
'unread': qs.exclude(read=None).count()
}
return Response(response)
Now remove those property functions from your model.
I didn't test your queries, just copied them from your model. You will need to check if they are working properly. Hope this helps.
I am not sure about how calling a model property who is responsible for querying in model can give appropriate data from serializer. Unfortunately i do have knowledge gap about that. I am thinking about an alternative solution. I hope following should work.
class NotificationSerializer(serializers.ModelSerializer):
total = serializers.serializers.SerializerMethodField()
read = serializers.ReadOnlyField()
unread = serializers.ReadOnlyField()
class Meta:
model = Notification
fields = ['read', 'unread']
def get_total(self, obj):
user = self.context['request'].user
return Notification.objects.filter(created_for=user).count()
If this work then you can able to do similar kind of thing for read and unread too.
In order to get notification for current_user we need to overwrite get_queryset from view.
class NotificationsMeta(generics.ListAPIView):
serializer_class = NotificationSerializer
def get_queryset(self):
return Notification.objects.filter(created_for=self.request.user)
I want to fetch the foreign key values in PUT and GET but while using the many=True I am getting error TypeError object is not iterable.
Here are following the my snippets.
I have two models called MasterStatus and MasterType. In MasterType I have foreign key values of MasterStatus.
models.py
class MasterType(models.Model):
id = models.BigIntegerField(primary_key=True)
type_name = models.CharField(max_length=255, blank=True, null=True)
fk_status = models.ForeignKey(MasterStatus)
def __unicode__(self):
return u'%s' % (self.type_name)
class Meta:
managed = False
db_table = 'master_type'
In serializer I am using the many=True to get the nested values of foreignkey. Here I have used PrimaryKeyRelatedField serializer.
serializer.py
class MasterTypeSerializer(serializers.HyperlinkedModelSerializer):
fk_status = serializers.PrimaryKeyRelatedField(queryset=MasterStatus.objects.all(),many=True)
class Meta:
model = MasterType
fields = ('id', 'type_name', 'fk_status', 'last_modified_date', 'last_modified_by')
depth = 2
ForeignKey links to a single MasterStatus instance, therefore it is not many.
Your serializers should look something like this:
class MasterTypeSerializer(serializers.HyperlinkedModelSerializer):
fk_status = serializers.PrimaryKeyRelatedField(
queryset=MasterStatus.objects.all())
class Meta:
model = MasterRepaymentType
class MasterStatusSerializer(serializers.HyperlinkedModelSerializer):
fk_type = serializers.PrimaryKeyRelatedField(
queryset= MasterRepaymentType.objects.all(), many=True)
class Meta:
model = MasterStatus
Note that many is used on the fk_type field as a MasterStatus has many MasterRepaymentType.
Hope this helps.