I am using django rest framework to create a blog website for fun. I am using neon db for the database. I have a users model in which I have a created_at attribute with datetimetz datatype. I have also set the default value to NOW() and in the serializer i have set the attribute to read_only_fields. But when i'm doing a post request to create a new user, it puts in null in the field and the created_at is filled as null in the database table.
My users model:
class Users(models.Model):
user_id = models.AutoField(primary_key=True,null=False,blank=True)
username = models.CharField(max_length=100)
email = models.CharField(max_length=254)
password_hash = models.CharField(max_length=30, blank=True, null=True)
created_at = models.DateTimeField(null=False,blank=True)
class Meta:
managed = False
db_table = 'users'
my serializer:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = Users
read_only_fields = ('created_at',)
fields = '__all__'
my view :
class UsersList(APIView):
"""
get all users or create a single user
"""
def get(self, request, format=None):
users = Users.objects.all()
serializer = UserSerializer(users,many=True)
return Response(serializer.data,status=status.HTTP_200_OK)
def post(self, request, format=None):
serializer = UserSerializer(data = request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data,status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
i have tried this:
class UserSerializer(serializers.ModelSerializer):
created_at = serializers.SerializerMethodField()
class Meta:
model = Users
read_only_fields = ('created_at',)
fields = '__all__'
def get_created_at(self, instance):
return instance.created_at.strftime("%B %d %Y")
it didn't work plus i don't want to do this. i want DRF to NOT include the created_at field and let the neon db table set the default value for the field.
I am using django rest framework to create a blog website for fun. I am using neon db for the database. I have a users model in which I have a created_at attribute with datetimetz datatype. I have also set the default value to NOW() and in the serializer i have set the attribute to read_only_fields. But when i'm doing a post request to create a new user, it puts in null in the field and the created_at is filled as null in the database table.
My users model:
class Users(models.Model):
user_id = models.AutoField(primary_key=True,null=False,blank=True)
username = models.CharField(max_length=100)
email = models.CharField(max_length=254)
password_hash = models.CharField(max_length=30, blank=True, null=True)
created_at = models.DateTimeField(null=False,blank=True)
class Meta:
managed = False
db_table = 'users'
my serializer:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = Users
read_only_fields = ('created_at',)
fields = '__all__'
my view :
class UsersList(APIView):
"""
get all users or create a single user
"""
def get(self, request, format=None):
users = Users.objects.all()
serializer = UserSerializer(users,many=True)
return Response(serializer.data,status=status.HTTP_200_OK)
def post(self, request, format=None):
serializer = UserSerializer(data = request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data,status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
i have tried this:
class UserSerializer(serializers.ModelSerializer):
created_at = serializers.SerializerMethodField()
class Meta:
model = Users
read_only_fields = ('created_at',)
fields = '__all__'
def get_created_at(self, instance):
return instance.created_at.strftime("%B %d %Y")
it didn't work plus i don't want to do this. i want DRF to NOT include the created_at field and let the neon db table set the default value for the field.
Share Improve this question edited Feb 6 at 17:00 Nick ODell 25.3k7 gold badges45 silver badges87 bronze badges asked Feb 6 at 15:52 mofu mofumofu mofu 31 bronze badge New contributor mofu mofu is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.3 Answers
Reset to default 0The short answer is: the read only field specification works. It just means that the serializer accepts a request as valid if that field is not given. In this case it is set to null value. This also means that the create operation from Django into your database includes created_at=NULL
(or whatever default you set in your model definition), which in turn makes the default that is defined on the database level to not trigger (as you have set a value, even if it is null).
For the long answer, there is one point in your question that irritates me: on the one hand you have in your models.py
the definition of created_at
as non-null, and on the other hand you write that the entry is stored with a null value in the database. As you have managed=False
I suppose you have created the table manually in the database, and as there is a null value in the created_at
column, your definition of the table in the database allows these (contrairy to the model definition in Django). This would be the first thing you need to check.
That said, your model definition in Django should generally reflect your table definition in the database, wich means that you also need to include the default function you defined on database level into your model definition, because otherwise Django will always set the created_at
attribute to s.th. you don't want.
So, your model should look like created_at = models.DateTimeField(default=timezone.now, null=False, blank=True)
as suggested here.
By Default django does not add timestamp to DatetimeFields so you should change your model to the following:
from django.utils import timezone
class Users(models.Model):
user_id = models.AutoField(primary_key=True, null=False, blank=True)
username = models.CharField(max_length=100)
email = models.CharField(max_length=254)
password_hash = models.CharField(max_length=30, blank=True, null=True)
created_at = models.DateTimeField(default=timezone.now, null=False, blank=True)
class Meta:
managed = False
db_table = 'users'
You can try to use auto_now
param:
class Users(models.Model):
...
created_at = models.DateTimeField(auto_now=True, null=False, blank=True)
class Meta:
managed = False
db_table = 'users'
DateField.auto_now
Automatically set the field to now every time the object is saved. Useful for “last-modified” timestamps. Note that the current date is always used; it’s not just a default value that you can override.
The field is only automatically updated when calling Model.save(). The field isn’t updated when making updates to other fields in other ways such as QuerySet.update(), though you can specify a custom value for the field in an update like that.