Почему мой Django фильтр с использованием дат не возвращает ожидаемых результатов? - PullRequest
1 голос
/ 07 февраля 2020

Я использую Django 2.2.6.

У меня есть такая модель:

class NetflowRecord(models.Model):
    #############
    # Help Text #
    #############

    min_mac_length_error_message = "Must be at least 12 characters long"
    data_help_text = "Bytes"
    direction_help_text = "True if record reflects downloaded bytes.<br>False if data reflects uploaded bytes."

    ##########
    # Fields #
    ##########

    timestamp = models.DateTimeField(auto_now_add=True, blank=False, null=False, editable=False)
    mac = models.CharField(max_length=17, unique=False, blank=False, null=False, validators=[MinLengthValidator(12, min_mac_length_error_message), validate_mac], editable=False)
    data = models.BigIntegerField(default=0, blank=False, null=False, help_text=data_help_text, validators=[MinValueValidator(0)], editable=False)
    direction = models.BooleanField(blank=False, null=False, help_text=direction_help_text, editable=False)
    site = models.ForeignKey(Site, on_delete=models.CASCADE, blank=False, null=False, related_name="netflow_records")

    ##########
    # Extras #
    ##########

    class Meta:
        verbose_name = "Netflow Record"
        verbose_name_plural = "Netflow Records"
        ordering = ['mac', 'timestamp']

    def __str__(self):
        formatted_date = self.timestamp.astimezone().strftime("%b %d, %Y - %I:%M:%S %p")

        if self.direction:
            return f"Download record for {self.mac} on {formatted_date}"
        else:
            return f"Upload record for {self.mac} on {formatted_date}"

Кажется, довольно основа c. У меня есть куча записей в базе данных в таблице, созданной этой моделью. Используя интерактивную оболочку, если я делаю это:

>>> from django.utils import timezone
>>> from my_app.models import NetflowRecord
>>>
>>> for record in NetflowRecord.objects.filter()[:3]:
...     print(record.timestamp)
... 
2020-02-06 19:20:41.758768+00:00
2020-02-06 20:20:46.491537+00:00
2020-02-06 19:07:57.482944+00:00
>>> for record in NetflowRecord.objects.filter(timestamp__year=2020)[:3]:
...     print(record.timestamp)
... 
2020-02-06 19:20:41.758768+00:00
2020-02-06 20:20:46.491537+00:00
2020-02-06 19:07:57.482944+00:00
>>> for record in NetflowRecord.objects.filter(timestamp__month=2)[:3]:
...     print(record.timestamp)
... 
# Returned None
>>> for record in NetflowRecord.objects.filter(timestamp__day=6)[:3]:
...     print(record.timestamp)
... 
# Returned None
>>> today = timezone.now().date()
>>> for record in NetflowRecord.objects.filter(timestamp__date=today)[:3]:
...     print(record.timestamp)
...
# Returned None

Почему мой фильтр не работает, когда я использовал __day, __month или __date? Документация Django говорит, что все они должны работать, и если я начну новый проект, используя ту же версию Django, я не смогу воспроизвести проблему - все они работают.

Я что-то напортачил где-нибудь?

Редактировать: я смог скопировать его, используя этот минимальный код: https://github.com/terminator14/django_filter_problem.git

Просто клонировать его, установить зависимости с pip install -r requirements.txt, редактировать db.cnf указать на вашу MySQL базу данных, запустить ./manage.py migrate; ./manage.py shell и сделать что-то вроде:

>>> from django.utils import timezone
>>> from test_app.models import NetflowRecord
>>>
>>> for i in range(3):
...     NetflowRecord.objects.create(timestamp=timezone.now())
...
>>> NetflowRecord.objects.filter(timestamp__day=timezone.now().day)

Редактировать 2: Установка последней версии Django 2, доступной в PIP (2.2.10) didn ' решить проблему. Установка последней версии Django 3, доступной по протоколу PIP (3.0.3), устраняет проблему. Это ошибка? Или Django изменил способ работы?

1 Ответ

0 голосов
/ 07 февраля 2020

Для любого запроса Django, вы можете точно узнать, какие команды MySQL он выполнит, добавив .query.

Это позволит мне сделать это:

str(NetflowRecord.objects.filter(timestamp__day=6).query)

, который показал мне длинную команду MySQL. Важной частью было следующее:

... WHERE EXTRACT(DAY FROM CONVERT_TZ(`test_app_netflowrecord`.`timestamp`, 'UTC', 'America/Edmonton')) = 6;

Выполняя несколько MySQL запросов вручную, оказалось, что если я запущу:

SELECT CONVERT_TZ('2004-01-01 12:00:00','GMT','MET');

, как показано здесь , это должен был дать мне дату, но это давало мне ноль. Как объяснено здесь , это потому, что MySQL не имеет определений для загруженных часовых поясов.

После запуска команды по этой ссылке (mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql), теперь приведенный выше пример кода с GMT to MET работает, и мои запросы тоже работают.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...