You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 20:35:11