欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

如何在Django中添加沒有微秒的 DateTimeField 屬性詳解

 更新時間:2019年01月30日 09:08:15   作者:陽明  
這篇文章主要給大家介紹了關(guān)于如何在Django中添加沒有微秒的 DateTimeField 屬性的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

前言

今天在項目中遇到一個Django的大坑,一個很簡單的分頁問題,造成了數(shù)據(jù)重復(fù)。最后排查發(fā)現(xiàn)是DateTimeField 屬性引起的。

下面描述下問題,下面是我需要用到的一個 Task Model 基本定義:

class Task(models.Model):
 # ...... 省略了其他字段
 title = models.CharField(max_length=256, verbose_name=u'標題')
 created_at = models.DateTimeField(auto_now_add=True, verbose_name=u'創(chuàng)建時間')

問題描述

前端這邊的分頁方式不是常規(guī)的 page、page_size 方式,而是使用標志位的方式進行分頁,我這里采用的就是通過創(chuàng)建時間的時間戳作為分頁標記。比如下面是返回的第一頁的數(shù)據(jù):

{
 "data": {
 "count": 5,
 "has_next": 1,
 "tasks": [
 {
 "title": "這是一個作業(yè)標題1",
 "ts": 1546829224000,
 "id": 1
 },
 {
 "title": "這是一個作業(yè)標題2",
 "ts": 1546829641000,
 "id": 2
 }
 ]
 },
 "result": 1
}

要請求第2頁的數(shù)據(jù)只需要在請求的 API 中傳遞上一頁最后一條數(shù)據(jù)的時間戳即可,這里我們就傳遞 1546829641000,這樣當我后臺接收到這個值過后就直接過濾大于該時間戳的數(shù)據(jù),再取一頁數(shù)據(jù)返回前端即可,邏輯上很簡單。過濾核心代碼如下:

ts = string_utils.get_num(request.GET.get('ts', 0), 0)
alltask = Task.objects.filter(created_at__gt=date_utils.timestamp2datetime(ts))

這段代碼很簡單,主要就是將前臺傳遞過來的時間戳轉(zhuǎn)換成 DateTime 類型的數(shù)據(jù),然后利用created_at__gt來過濾,就是大于這個時間點的就可以。然后問題來了,查詢出來的數(shù)據(jù)始終包含了上一頁最后一條數(shù)據(jù),感覺很奇怪,我這里明明用的是gt而不是gte,怎么會重復(fù)這條數(shù)據(jù)呢。

于是,我們把上一頁最后一條數(shù)據(jù)的 created_at 字段打印出來和傳遞過來的時間戳進行對比下:

>>> task = Task.objects.get(pk=2)
>>> task.created_at
datetime.datetime(2019, 1, 7, 10, 54, 1, 343136)

然后將時間戳轉(zhuǎn)換成 DateTime 類型的數(shù)據(jù):

>>> ts = int(1546829641000/1000)
>>> date_utils.timestamp2datetime(ts)
datetime.datetime(2019, 1, 7, 10, 54, 1)

現(xiàn)在看到區(qū)別沒有,從數(shù)據(jù)庫中查詢出來的 created_at 字段的值包含了一個微秒,就是后面的 343136,而時間戳轉(zhuǎn)換成 DateTime 類型的值是不包含這個微秒值的,所以我們上面查詢的使用created_at__gt來進行過濾很顯然 created_at 的值是大于下面的值的,因為多了一個微秒,所以就造成了數(shù)據(jù)重復(fù)了,終于破案了。

解決方法

那么要怎么解決這個問題呢?當然我們可以直接在數(shù)據(jù)庫中就保存一個時間戳的字段,用這個字段直接來進行查詢過濾,肯定是可以解決這個問題的。

如果就用現(xiàn)在的 created_at 這個 DateTimeField 類型呢?如果保存的數(shù)據(jù)沒有這個微秒是不是也可以解決這個問題啊?

我們可以去查看下源碼為什么 DateTimeField 類型的數(shù)據(jù)會包含微秒,下面是django/db/backends/mysql/base.py文件中的部分代碼說明:

class DatabaseWrapper(BaseDatabaseWrapper):
 vendor = 'mysql'
 # This dictionary maps Field objects to their associated MySQL column
 # types, as strings. Column-type strings can contain format strings; they'll
 # be interpolated against the values of Field.__dict__ before being output.
 # If a column type is set to None, it won't be included in the output.
 _data_types = {
 'AutoField': 'integer AUTO_INCREMENT',
 'BinaryField': 'longblob',
 'BooleanField': 'bool',
 'CharField': 'varchar(%(max_length)s)',
 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
 'DateField': 'date',
 'DateTimeField': 'datetime',
 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
 'DurationField': 'bigint',
 'FileField': 'varchar(%(max_length)s)',
 'FilePathField': 'varchar(%(max_length)s)',
 'FloatField': 'double precision',
 'IntegerField': 'integer',
 'BigIntegerField': 'bigint',
 'IPAddressField': 'char(15)',
 'GenericIPAddressField': 'char(39)',
 'NullBooleanField': 'bool',
 'OneToOneField': 'integer',
 'PositiveIntegerField': 'integer UNSIGNED',
 'PositiveSmallIntegerField': 'smallint UNSIGNED',
 'SlugField': 'varchar(%(max_length)s)',
 'SmallIntegerField': 'smallint',
 'TextField': 'longtext',
 'TimeField': 'time',
 'UUIDField': 'char(32)',
 }

 @cached_property
 def data_types(self):
 if self.features.supports_microsecond_precision:
  return dict(self._data_types, DateTimeField='datetime(6)', TimeField='time(6)')
 else:
  return self._data_types

 # ... further class methods

上面的 data_types 方法中在進行 MySQL 版本檢查,屬性supports_microsecond_precision來自于文件django/db/backends/mysql/features.py:

class DatabaseFeatures(BaseDatabaseFeatures):
 # ... properties and methods

 def supports_microsecond_precision(self):
 # See https://github.com/farcepest/MySQLdb1/issues/24 for the reason
 # about requiring MySQLdb 1.2.5
 return self.connection.mysql_version >= (5, 6, 4) and Database.version_info >= (1, 2, 5)

從上面代碼可以看出如果使用的 MySQL 大于等于 5.6.4 版本,屬性DateTimeField會被映射成為數(shù)據(jù)庫中的datetime(6),所以保存的數(shù)據(jù)就包含了微秒。

在 Django 中暫時沒有發(fā)現(xiàn)可以針對改配置進行設(shè)置的方法,所以我們要想保存的數(shù)據(jù)不包含微秒,我們這里則可以將上面的data_types屬性進行覆蓋即可:

from django.db.backends.mysql.base import DatabaseWrapper

DatabaseWrapper.data_types = DatabaseWrapper._data_types

將上面的代碼放置在合適的地方,比如models.py或者__init__.py或者其他地方,當我們運行 migrations 命令來創(chuàng)建 DateTimeField 列的時候?qū)?yīng)在數(shù)據(jù)庫中的字段就被隱射成為了datetime,而不是datetime(6),即使你用的是 5.6.4 版本以上的數(shù)據(jù)庫。

當然要立即解決當前的問題,只需要更改下數(shù)據(jù)庫中的 created_at 字段的類型即可:

mysql> ALTER TABLE `task` CHANGE COLUMN `created_at` `created_at` datetime NOT NULL;
Query OK, 156 rows affected (0.14 sec)
Records: 156 Duplicates: 0 Warnings: 0

這樣數(shù)據(jù)重復(fù)的 BUG 就解決了。

參考鏈接:https://stackoverflow.com/questions/46539755/how-to-add-datetimefield-in-django-without-microsecond

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

相關(guān)文章

  • 基于python SMTP實現(xiàn)自動發(fā)送郵件教程解析

    基于python SMTP實現(xiàn)自動發(fā)送郵件教程解析

    這篇文章主要介紹了基于python實現(xiàn)自動發(fā)送郵件教程解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-06-06
  • 用Python實現(xiàn)QQ游戲大家來找茬輔助工具

    用Python實現(xiàn)QQ游戲大家來找茬輔助工具

    這是一個用于QQ大家來找茬(美女找茬)的輔助外掛,開發(fā)的原因是看到老爸天天在玩這個游戲,分數(shù)是慘不忍睹的負4000多。本來是想寫個很簡單的東西,但由于過程中老爸的多次嘲諷,逼得我不得不盡力完善,最后形成了一個小小的產(chǎn)品。
    2014-09-09
  • python實現(xiàn)通過pil模塊對圖片格式進行轉(zhuǎn)換的方法

    python實現(xiàn)通過pil模塊對圖片格式進行轉(zhuǎn)換的方法

    這篇文章主要介紹了python實現(xiàn)通過pil模塊對圖片格式進行轉(zhuǎn)換的方法,涉及Python中pil模塊的使用技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-03-03
  • python中比較兩個列表的實例方法

    python中比較兩個列表的實例方法

    在本篇文章里小編給各位分享了關(guān)于python中比較兩個列表的實例方法以及相關(guān)代碼,需要的朋友們參考下。
    2019-07-07
  • 如何將你的應(yīng)用遷移到Python3的三個步驟

    如何將你的應(yīng)用遷移到Python3的三個步驟

    這篇文章主要介紹了如何將你的應(yīng)用遷移到Python3的三個步驟,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • python使用多線程備份數(shù)據(jù)庫的步驟

    python使用多線程備份數(shù)據(jù)庫的步驟

    在日常服務(wù)器運維工作中,備份數(shù)據(jù)庫是必不可少的,剛工作那會看到公司都是用shell腳本循環(huán)備份數(shù)據(jù)庫,到現(xiàn)在自己學(xué)習(xí)python語言后,利用多進程多線程相關(guān)技術(shù)來實現(xiàn)并行備份數(shù)據(jù)庫,充分利用服務(wù)器資源,提高備份速度。
    2021-05-05
  • Python操作Elasticsearch處理timeout超時

    Python操作Elasticsearch處理timeout超時

    這篇文章主要介紹了Python操作Elasticsearch處理timeout超時,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-07-07
  • pytorch實現(xiàn)onehot編碼轉(zhuǎn)為普通label標簽

    pytorch實現(xiàn)onehot編碼轉(zhuǎn)為普通label標簽

    今天小編就為大家分享一篇pytorch實現(xiàn)onehot編碼轉(zhuǎn)為普通label標簽,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-01-01
  • Django?Rest?Framework實現(xiàn)身份認證源碼詳解

    Django?Rest?Framework實現(xiàn)身份認證源碼詳解

    這篇文章主要為大家介紹了Django?Rest?Framework實現(xiàn)身份認證源碼詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-05-05
  • Python設(shè)計模式之命令模式簡單示例

    Python設(shè)計模式之命令模式簡單示例

    這篇文章主要介紹了Python設(shè)計模式之命令模式,簡單介紹了命令模式的概念、原理,并結(jié)合實例形式分析了Python命令模式的定義與使用相關(guān)操作技巧,需要的朋友可以參考下
    2018-01-01

最新評論