首頁 > 軟體

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

2020-06-16 16:49:38

我們在用Django建立models時,常常會涉及時間日期欄位的處理,Django裡日期相關Field有DateTimeField、DateField和TimeField三種型別,看似簡單,但其中有一些容易出錯的地方需要注意;另外,如果不習慣Django的預設時間格式,也可以自定義的修改。

DateTimeField、DateField和TimeField,其值分別對應著Python裡的datetime.datetime、datetime.date和datetime.time三個範例,這三個Field裡都有兩個引數:auto_now和auto_now_add,預設值均為False。

auto_now引數說明:

每次儲存物件時自動將欄位值設定為當前時間,能夠在儲存該欄位時,將其值設定為當前時間,並且每次修改model,都會自動更新。因此這個引數在需要儲存“最後修改時間”的場景下,十分方便,常用類似“last-modified”或者"update_time"欄位。

需要注意的是,該欄位不能被手動修改覆蓋;當設定為true時,只有每次呼叫Model.save()時,才會強制更新為當前時間點;當用其他方式更新其他欄位時並不會更新:比如用QuerySet.update()方法,即使為該欄位指定一個自定義的值,該欄位也不會有所更改。比較直觀的表現形式是,如果使用django自帶的admin管理器,那麼該欄位在admin中是唯讀的,並且無法進行修改。範例程式碼如下:

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程式碼:

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介面效果圖:

點選編輯頁面,會發現找不到‘更新時間’的編輯處,因為此欄位是唯讀,且不允許手動修改,效果圖如下:

當頁面“save”之後,再觀察現在的‘更新時間’發現時間已經被修改:

時間已被修改
auto_now_add引數說明:

設定為True時,會在model物件第一次被建立時,將欄位的值設定為建立時的時間,以後修改物件時,欄位的值不會再更新。該屬性通常被用在儲存“建立時間”的場景下。與auto_now類似,auto_now_add也具有強制性,一旦被設定為True,就無法在程式中手動為欄位賦值,在admin中欄位也會成為唯讀的。

繼續沿用剛才的程式碼範例,'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有關):

![可能的預設日期格式]

如果不習慣這種格式,自己定義顯示格式的設定如下,更改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/>;

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/

Flask+uWSGI+Nginx+Ubuntu部署教學 http://www.linuxidc.com/Linux/2016-06/132690.htm
Ubuntu 16.04下安裝部署 Nginx+uWSGI+Django1.9.7  http://www.linuxidc.com/Linux/2016-07/133484.htm
Ubuntu 16.10 下部署Django+uWSGI+Nginx伺服器  http://www.linuxidc.com/Linux/2017-05/143661.htm
Nginx+uWSGI+Django在Ubuntu下的部署  http://www.linuxidc.com/Linux/2016-07/133490.htm
uWSGI+Nginx+Django安裝和設定  http://www.linuxidc.com/Linux/2017-03/141822.htm
Ubuntu下通過Nginx部署Django  http://www.linuxidc.com/Linux/2017-09/147165.htm
Django運算表示式與Q物件/F物件  https://www.linuxidc.com/Linux/2018-05/152509.htm
Django 錯誤之 No module named ‘MySQLdb’ https://www.linuxidc.com/Linux/2018-04/151991.htm
Ubuntu 16.04 LTS Django虛擬開發環境設定 http://www.linuxidc.com/Linux/2017-09/147174.htm

Linux公社的RSS地址:https://www.linuxidc.com/rssFeed.aspx

本文永久更新連結地址https://www.linuxidc.com/Linux/2018-08/153373.htm


IT145.com E-mail:sddin#qq.com