DateTimeField throwing datetime is not serializeable - django

I have added a new Datetime field in my model.
class MyModel:
valid_upto = models.DateTimeField(auto_now=True, blank=True, null=True)
and my serializer code is
class MyModelSerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
fields = '__all__'
When i am updating one instance i am getting TypeError: Object of type datetime is not JSON serializable
the value that can come in valid_upto is None or a datetime value which i am getting from timezone.now()

probably you are wrong with field attribute. More here:
https://docs.djangoproject.com/en/4.1/ref/models/fields/#django.db.models.DateField.auto_now
class MyModel:
valid_upto = models.DateTimeField(auto_now=True, auto_now_add=True)
By default this field is not editable. And serializer should check it.
But if you want, you remove this field manually:
class MyModelSerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
exclude = ('valid_upto', )

Related

Django Resf Framework: auto fill a field of a Model when POST?

Is there a way of filling some particular fields in a model using a field value of another model object?
For example, I thought of the following scenario:
1 - there are some models
from django.db import models
class Supplier(models.Model):
supplier = models.Charfield(max_length=50, unique=True)
class Object(models.Model):
object = models.Charfield(max_length=50)
supplier = models.ForeignKey(Supplier, on_delete=models.CASCADE, to_field="supplier")
class Transaction(models.Model):
object_id = models.ForeignKey(Object, on_delete=models.CASCADE)
supplier = models.Charfield(max_length=50)
2 - Those models are serialized
from . import models
from rest_framework.serializers import ModelSerializer
class SupplierSerializer(ModelSerializer):
class Meta:
model = models.Supplier
fields = '__all__'
class ObjectSerializer(ModelSerializer):
class Meta:
model = models.Object
fields = '__all__'
class TransactionSerializer(ModelSerializer):
class Meta:
model = models.Transaction
exclude = ('supplier',)
3 - And there is a view
from . import models, serializers
from rest_framework.viewsets import ModelViewSet
class TransactionApiViewset(ModelViewSet):
queryset = models.Transaction.objects.all()
serializer_class = serializers.TransactionSerializer
When submiting a post with 'object_id' field to Transaction Api, I'd like that the 'supplier' field in Transaction Model autofills with the 'supplier' field value of Object object related to 'object_id'.
I'd appreciate any help.
I think you could use property(or cached_property) method for supplier instead of saving as a field:
class Transaction(models.Model):
object = models.ForeignKey(Object, on_delete=models.CASCADE)
#property
def supplier(self):
return self.object.supplier.supplier
If you need to keep supplier saved in Transaction table, then just keep the model definition as you posted, and add a validate method in serializer:
class TransactionSerializer(ModelSerializer):
def validate(self, data):
object = Object.objects.get(id=data["object_id"])
data["supplier"] = object.supplier.supplier
return data
That would automatically update Transaction with new object related supplier's supplier field.

nested serializer showing null data

nested serializer showing null data
from rest_framework import serializers
from .models import PlayerTable, ChildTable
class ChildTableSerializer(serializers.ModelSerializer):
# x= ChildTable.objects.all().values
class Meta:
model = ChildTable
fields = ('season','goals','fk')
# fields =('fk',)
class PlayerTableSerializer(serializers.ModelSerializer):
player_details = ChildTableSerializer(many=True, read_only=True)
class Meta:
model = PlayerTable
fields = ('player_details',)
please help data getting by serializer is null
what is the field 'player-details'? It's not a field on your PlayerTable model. You need to use the name of the related field. In your case since you have a ForeignKey relationship ChildTable --> PlayerTable and you haven't specified the related_name, it's childtable_set. So if you do this it should work:
class PlayerTableSerializer(serializers.ModelSerializer):
childtable_set = ChildTableSerializer(many=True, read_only=True)
class Meta:
model = PlayerTable
fields = ('childtable_set',)
Alternatively, change your models naming to be more aligned with Django conventions:
class PlayerDetail(models.Model):
player = models.ForeignKey(Player, db_column="fk", related_name="player_details", null=True, blank=True, on_delete=models.CASCADE)
...
class Meta:
managed = False
db_table = "child_table"
class Player(models.Model):
name = models.CharField(db_column="player_name", ...)
class Meta:
db_table = "player_table"
then your serializer would work because the relation is player_details. This also has the advantage that when you do details.player you get the player object (now, you have to do details.fk but that actually doesn't return the foreign key value, it returns the Player object). Also your models have more pythonic names (Player not PlayerTable). Your code will be much more readable.

Validations of Model Serializers

I have to modify the feature of ModelSerializer, my expectations are as,
I have two fields in my Model. Both are charFields.
class MyModel(models.Model):
name = models.CharField(blank=False,
null=False,
max_length=20)
value = models.CharField(blank=True,
null=True,
max_length=20)
My serializer is as,
class MyModelSerializer(ModelSerializer):
class Meta:
model = MyModel
fields = '__all__'
I am have to create the object of MyModel using this serializer.
Now issue is that if I am passing the 'bool' values in my fields, its showing error message that 'Not a valid string.' (As expected by Modelserializer)
{ "name":True, "value":False }
My requirements are to handle the 'bool' value and converted that 'bool' into 'str'. what should be the trick to resolve this.
use the to_internal_value function, for example this works:
class MyModelSerializer(ModelSerializer):
class Meta:
model = MyModel
fields = '__all__'
def to_internal_value(self, data):
for field in ('name', 'value'):
if field in data and isinstance(data[field], bool):
data[field] = str(data[field])
return super().to_internal_value(data)

Serializer ForeignKey results in "Expected a dictionary ..."

My Model:
class Font(ValidateVersionOnSaveMixin, models.Model):
id = models.UUIDField(primary_key=True, editable=True)
name = models.CharField(max_length=100, blank=False, null=False)
class Glyph(ValidateVersionOnSaveMixin, models.Model):
id = models.UUIDField(primary_key=True, editable=True)
unit = models.CharField(max_length=100, blank=False, null=False, unique=True)
font = models.ForeignKey(Font, on_delete=models.CASCADE)
I want to post the following JSON to add a Glyph to an already existing Font (having the fontId as ID) object.
{
fontId: "4a14a055-3c8a-43ba-aab3-221b4244ac73"
id: "40da7a83-a204-4319-9a04-b0a544bf4440"
unit: "aaa"
}
As there is a mismatch between the ForeignKey Field font and the JSON propertyfontId I am adding source='font' in my Serializer:
class FontSerializer(serializers.ModelSerializer):
class Meta:
model = Font
fields = ('id', 'name')
class GlyphSerializer(serializers.ModelSerializer):
fontId = FontSerializer(source='font')
class Meta:
model = Glyph
fields = ('id', 'unit', 'fontId' )
But the result is an BAD REQUEST Error:
{"fontId":{"non_field_errors":["Invalid data. Expected a dictionary, but got str."]}}
Update
The following Serializer gave me the result I was looking for.
class GlyphSerializer(serializers.ModelSerializer):
fontId = serializers.PrimaryKeyRelatedField(
queryset=Font.objects.all(),
required=True,
source='font',
write_only=False
)
class Meta:
model = Glyph
fields = ('id', 'unit', 'version', 'fontId')
You can user model_to_dict method as bellow:
from django.forms.models import model_to_dict
model_to_dict(obj)
You have defined fontId as being a serialized object (FontSerializer). But that serializer in turn is defined as having both an id and a name. Where as your json dictionary is posting only an id. You would have to change that to a dictionary that contains both an id and a name
{
fontId: {id: "4a14a055-3c8a-43ba-aab3-221b4244ac73",name: "some name" },
id: "40da7a83-a204-4319-9a04-b0a544bf4440"
unit: "aaa"
}
The reason you are getting this error is that during deserialization process, DRF calls .is_valid(raise_exception=True) before you can call serializer.save(validated_data). And non_field_errors lists any general validation errors during this process. In your GlyphSerializer, your FontSerializer is a nested serializer, which correlates to a Python dictionary. So it will raise an error like you encountered for any non-dictionary data types.
You could create a subclass of GlyphSerializer called GlyphCreateSerializer
class FontSerializer(serializers.ModelSerializer):
class Meta:
model = Font
fields = ('id', 'name')
class GlyphSerializer(serializers.ModelSerializer):
fontId = FontSerializer(source='font')
class Meta:
model = Glyph
fields = ('id', 'unit', 'fontId' )
class GlyphCreateSerializer(GlyphSerializer):
fontId = serializers.CharField()
And you can use GlyphCreateSerializer for the POST request on your Viewset.

many=True TypeError object is not iterable

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.