Django DateTimeField仅记录日期未记录时间问题求助
问题:DateTimeField仅存储日期,时间信息丢失
我创建了一个包含两个DateTimeField的WorkTime模型,但数据库中仅存储了日期信息,时间部分完全丢失。我尝试过使用auto_now和auto_now_add参数,但问题仍未解决。以下是我的模型、视图及settings.py代码,希望得到可行的解决方法:
模型代码
from django.db import models from django.db.models.signals import pre_save from django.dispatch import receiver from django.utils import timezone from accounts.models import CustomUser class WorkTime(models.Model): worker = models.ForeignKey(CustomUser, null=True, on_delete=models.CASCADE) clock_in = models.DateTimeField(null=True) clock_out = models.DateTimeField(null=True) def save(self, *args, **kwargs): if self.id: # Object is being updated self.clock_out = timezone.now() super(WorkTime, self).save(*args, **kwargs) @receiver(pre_save, sender=WorkTime) def set_clock_in(sender, instance, **kwargs): if not instance.id: # Object is being created instance.clock_in = timezone.now()
视图代码
from django.shortcuts import render from django.views.generic import DetailView, CreateView, UpdateView from django.utils import timezone from django.urls import reverse_lazy from .models import WorkTime from django.contrib.auth.mixins import LoginRequiredMixin class WorkTimeCreateView(LoginRequiredMixin, CreateView): model = WorkTime fields = [] # Remove 'worker' from fields as it will be auto-detected template_name = 'timeclock/worktime_form.html' def form_valid(self, form): # Automatically set the worker to the currently logged-in user form.instance.worker = self.request.user # Set the clock_in time form.instance.clock_in = timezone.now() return super().form_valid(form) class WorkTimeUpdateView(LoginRequiredMixin, UpdateView): model = WorkTime fields = ['worker'] template_name = 'worktime_update' # Use a custom template for update view def form_valid(self, form): # Automatically set the clock_out time form.instance.clock_out = timezone.now() return super().form_valid(form) def get_success_url(self): return reverse_lazy('worktime_detail', args=[self.object.id])
settings.py代码
""" Django settings for config project. Generated by 'django-admin startproject' using Django 3.2.20. For more information on this file, see https://docs.djangoproject.com/en/3.2/topics/settings/ For the full list of settings and their values, see https://docs.djangoproject.com/en/3.2/ref/settings/ """ from pathlib import Path # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = 'django-insecure-my_sq_rtxn8pc6=7hl&ta1fo4c03^7g6hq#=9g+tytk3_mk_&a' # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True ALLOWED_HOSTS = [] # Application definition INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', #Custom apps 'accounts', 'timeclock', 'articles', ] MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] ROOT_URLCONF = 'config.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [str(BASE_DIR.joinpath('templates'))], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] WSGI_APPLICATION = 'config.wsgi.application' # Database # https://docs.djangoproject.com/en/3.2/ref/settings/#databases DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'db.sqlite3', } } # Password validation # https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ { 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', }, { 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', }, { 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', }, { 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', }, ] AUTH_USER_MODEL = 'accounts.CustomUser' # Internationalization # https://docs.djangoproject.com/en/3.2/topics/i18n/ LANGUAGE_CODE = 'en-us' TIME_ZONE = 'UTC' USE_I18N = True USE_L10N = True USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/3.2/howto/static-files/ STATIC_URL = '/static/' # Default primary key field type # https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
解决方法
1. 排查时间丢失的核心原因
你的代码同时用了**模型save方法、pre_save信号、视图form_valid**三处逻辑来设置时间,这会导致逻辑冲突,反而让auto_now/auto_now_add失效。SQLite本身支持完整的datetime存储,问题出在重复赋值覆盖了时间信息。
2. 简化模型逻辑,用原生参数实现需求
直接使用Django提供的auto_now_add和auto_now参数,去掉所有冗余的时间设置逻辑:
from django.db import models from accounts.models import CustomUser class WorkTime(models.Model): worker = models.ForeignKey(CustomUser, null=True, on_delete=models.CASCADE) # 创建时自动设置打卡时间 clock_in = models.DateTimeField(auto_now_add=True, null=True) # 每次保存时自动更新签退时间 clock_out = models.DateTimeField(auto_now=True, null=True)
3. 清理视图中的冗余代码
视图不再需要手动设置时间,只保留用户关联逻辑即可:
# 创建视图修改后 class WorkTimeCreateView(LoginRequiredMixin, CreateView): model = WorkTime fields = [] template_name = 'timeclock/worktime_form.html' def form_valid(self, form): form.instance.worker = self.request.user return super().form_valid(form) # 更新视图修改后 class WorkTimeUpdateView(LoginRequiredMixin, UpdateView): model = WorkTime fields = ['worker'] template_name = 'worktime_update' def get_success_url(self): return reverse_lazy('worktime_detail', args=[self.object.id])
4. 确认显示格式(避免假丢失)
如果数据库已经存储了完整时间,但显示时只看到日期,是因为默认格式化只展示日期:
- 模板中强制显示时间:
{{ object.clock_in|date:"Y-m-d H:i:s" }} - Admin后台自定义显示格式:
from django.contrib import admin from .models import WorkTime class WorkTimeAdmin(admin.ModelAdmin): list_display = ('worker', 'format_clock_in', 'format_clock_out') def format_clock_in(self, obj): return obj.clock_in.strftime("%Y-%m-%d %H:%M:%S") def format_clock_out(self, obj): return obj.clock_out.strftime("%Y-%m-%d %H:%M:%S") if obj.clock_out else None admin.site.register(WorkTime, WorkTimeAdmin)
5. 执行数据库迁移
修改模型后,需要更新数据库结构:
python manage.py makemigrations python manage.py migrate
内容的提问来源于stack exchange,提问作者Finn
相关产品推荐
相关产品推荐

