Django中的日期處理注意事項和自定義時間格式轉換

咱們在用Django建立models時,經常會涉及時間日期字段的處理,Django裏日期相關Field有DateTimeField、DateField和TimeField三種類型,看似簡單,但其中有一些容易出錯的地方須要注意;另外,若是不習慣Django的默認時間格式,也能夠自定義的修改。html

DateTimeField、DateField和TimeField,其值分別對應着Python裏的datetime.datetime、datetime.date和datetime.time三個實例,這三個Field裏都有兩個參數:auto_now和auto_now_add,默認值均爲False數據庫

auto_now參數說明:django

每次保存對象時自動將字段值設置爲當前時間,可以在保存該字段時,將其值設置爲當前時間,而且每次修改model,都會自動更新。所以這個參數在須要存儲「最後修改時間」的場景下,十分方便,經常使用相似「last-modified」或者"update_time"字段。ide

須要注意的是,該字段不能被手動修改覆蓋;當設置爲true時,只有每次調用Model.save()時,纔會強制更新爲當前時間點;當用其餘方式更新其餘字段時並不會更新:好比用QuerySet.update()方法,即便爲該字段指定一個自定義的值,該字段也不會有所更改。比較直觀的表現形式是,若是使用django自帶的admin管理器,那麼該字段在admin中是隻讀的,而且沒法進行修改。示例代碼以下:ui

class Datacenter(models.Model):
    id = models.UUIDField('機房ID', default=uuid.uuid4, primary_key=True)
    zone = models.ForeignKey(Zone, verbose_name='所在區域', on_delete=models.PROTECT)
    dc_name = models.CharField('機房', max_length=128, unique=True)
    networks = models.CharField('IP地址段', max_length=128, blank=True, unique=True)
    update_time = models.DateTimeField('更新時間', auto_now=True)

    def __str__(self):
        return self.dc_name

    class Meta:
        verbose_name = '機房配置'
        verbose_name_plural = '機房配置'

Datacenter的ModelAdmin代碼:3d

class DatacenterAdmin(admin.ModelAdmin):
    list_display = ['id', 'dc_name', 'zone', 'networks', 'update_time']
    search_fields = ['dc_name', 'zone', 'networks']
    list_filter = ['dc_name', 'zone']
    ordering = ['networks', 'zone']
admin.site.register(models.Datacenter, DatacenterAdmin)

Admin界面效果圖:code

admin界面顯示

點擊編輯頁面,會發現找不到‘更新時間’的編輯處,由於此字段是隻讀,且不容許手動修改,效果圖以下:
admin界面顯示
當頁面「save」以後,再觀察如今的‘更新時間’發現時間已經被修改:
時間已被修改
auto_now_add參數說明:orm

設置爲True時,會在model對象第一次被建立時,將字段的值設置爲建立時的時間,之後修改對象時,字段的值不會再更新。該屬性一般被用在存儲「建立時間」的場景下。與auto_now相似,auto_now_add也具備強制性,一旦被設置爲True,就沒法在程序中手動爲字段賦值,在admin中字段也會成爲只讀的。htm

繼續沿用剛纔的代碼示例,'update_time'的'auto_now'改完'auto_now_add',其餘代碼不變:對象

class Datacenter(models.Model):
    id = models.UUIDField('機房ID', default=uuid.uuid4, primary_key=True)
    zone = models.ForeignKey(Zone, verbose_name='所在區域', on_delete=models.PROTECT)
    dc_name = models.CharField('機房', max_length=128, unique=True)
    networks = models.CharField('IP地址段', max_length=128, blank=True, unique=True)
    update_time = models.DateTimeField('更新時間', auto_now_add=True)

編輯更新北京聯通機房的IP地址段以後保存:

再次編輯
更改以後‘更新時間’並未發生改變(見下圖),由於‘auto_now_add’在對象建立完成後即再也不更新:

時間再也不變化

如何實現可編輯

auto_now和auto_now_add被設置爲True後,這樣作會致使字段成爲editable=False和blank=True的狀態。editable=False將致使字段不會被呈如今admin中,blank=Ture表示容許在表單中不輸入值。此時,若是在admin的fields或fieldset中強行加入該日期時間字段,那麼程序會報錯,admin沒法打開;若是在admin中修改對象時,想要看到日期和時間,能夠將日期時間字段添加到admin類的readonly_fields中:

readonly_fields = ('save_date', 'mod_date',)

那麼問題來了。實際場景中,每每既但願在對象的建立時間默認被設置爲當前值,又但願能在往後修改它。怎麼實現這種需求呢?

django中全部的model字段都擁有一個default參數,用來給字段設置默認值。能夠用default=timezone.now來替換auto_now=True或auto_now_add=True。timezone.now對應着django.utils.timezone.now(),代碼示例:

from django.utils import timezone

class Datacenter(models.Model):
    id = models.UUIDField('機房ID', default=uuid.uuid4, primary_key=True)
    zone = models.ForeignKey(Zone, verbose_name='所在區域', on_delete=models.PROTECT)
    dc_name = models.CharField('機房', max_length=128, unique=True)
    networks = models.CharField('IP地址段', max_length=128, blank=True, unique=True)
    update_time = models.DateTimeField('更新時間', default=timezone.now())

    def __str__(self):
        return self.dc_name

    class Meta:
        verbose_name = '機房配置'
        verbose_name_plural = '機房配置'

這裏'update_time'字段默認值改成timezone.now()後,再次編輯已經能看到相應‘更新時間’字段,而且可修改:
更新時間已可修改
咱們把時間天數加1天后,保存退出再觀察‘更新時間’已經變爲自定義時間:
保存後時間變爲自定義時間

自定義日期格式
剛建立的Django應用,可能你看到的日期顯示格式跟下圖相似(跟LANGUAGE_CODE和TIME_ZONE有關):

![可能的默認日期格式](https://s4.51cto.com/images/blog/201803/23/164dc709843a56536c09c9142775a553.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)

若是不習慣這種格式,本身定義顯示格式的配置以下,更改Django的setting.py文件:

USE_L10N = False
DATE_FORMAT = 'Y-m-d'
DATETIME_FORMAT = 'Y-m-d H:i:s'

注意事項:若是USE_L10N設置爲了True,那麼語言環境規定的格式具備更高的優先級並將被應用,即DATE_FORMAT不生效。
這裏可用的格式化字符串的其餘寫法參見Django官方文檔:

<https://docs.djangoproject.com/en/2.0/ref/templates/builtins/#date>;

Available format strings,部分截圖:
format stringsDjango中的日期處理注意事項和自定義時間格式轉換

另外在Django頁面渲染的時候,html頁面從數據庫中讀出DateTimeField字段時,顯示的時間格式和數據庫中存放的格式不一致,另一個解決辦法:能夠在頁面格式化時間,添加{{ Datacenter.updatetime|date:"Y-m-d H:i:s" }}相似的過濾器。以後刷新頁面,便可正常顯示。

相關文檔:

https://docs.djangoproject.com/en/2.0/ref/settings/

https://docs.djangoproject.com/en/2.0/ref/templates/builtins/#std:templatefilter-date

相關文章
相關標籤/搜索