Django REST Framework中read_only_fields不生效,创建用户时created_at字段被存入Null
看起来你的问题核心在于模型层没有给created_at字段配置正确的默认值逻辑,再加上managed=False的设置让Django无法同步数据库的默认约束,最终导致创建用户时,Django没有为这个字段填充值,数据库也没能触发你设置的NOW()默认规则,最后存入了NULL。下面给你一步步的解决办法:
第一步:修正模型的created_at字段定义
你需要在Django模型层面为created_at设置默认值,这样调用serializer.save()时,Django会自动为这个字段填充当前时间,同时和数据库的默认规则匹配。
修改你的Users模型:
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) # 这里添加default=timezone.now,用Django的时区工具保证时间正确性 created_at = models.DateTimeField(null=False, blank=True, default=timezone.now) class Meta: managed = False db_table = 'users'
另外,因为你设置了managed=False,Django不会自动同步数据库表结构,所以需要确保你的Neon DB中users表的created_at字段确实带有DEFAULT NOW()的约束。如果还没设置,手动执行这条SQL语句:
ALTER TABLE users ALTER COLUMN created_at SET DEFAULT NOW();
第二步:确认Serializer和View的配置
你的Serializer和View的配置其实是没问题的:
- Serializer中
read_only_fields = ('created_at',)确保这个字段不会从请求数据中取值 - View的
post方法里serializer.save()会自动使用模型的默认值填充created_at
不需要做额外修改,保持现有逻辑即可。
为什么之前的SerializerMethodField方案没生效?
你尝试用SerializerMethodField来处理created_at,但这个方法的作用是在序列化输出(比如返回给前端数据)时自定义字段值,完全不会影响对象创建时的字段填充逻辑,所以自然解决不了你遇到的问题。
备选方案:完全依赖数据库默认值
如果你更倾向于完全依赖数据库的NOW()默认值,不想在Django模型层设置默认,可以在Serializer的create方法中手动移除created_at字段,让数据库自动填充:
class UserSerializer(serializers.ModelSerializer): class Meta: model = Users read_only_fields = ('created_at',) fields = '__all__' def create(self, validated_data): # 移除validated_data中的created_at,让数据库使用默认值 validated_data.pop('created_at', None) return super().create(validated_data)
不过这种方式不如在模型层设置默认值可靠,因为Django能更清晰地感知字段的默认行为,避免后续出现逻辑冲突。
备注:内容来源于stack exchange,提问作者mofu mofu

