Django 视图返回过时的数据,在服务器重新启动后修复

roo*_*oob 2 database django postgresql orm

我有一个带有 postgresql 数据库的 Django 网络服务器。

我有一个视图(Django REST 框架),它表现出奇怪的行为。

该视图列出表中最新记录的日期。记录始终每分钟多次添加到该表中。我没有对此视图实施任何缓存。

今天我观察到以下几点:

  • 生产服务器上的视图返回过时的数据(2 天前的最新数据)
  • 本地开发服务器上的视图(连接到同一远程数据库)返回了新数据
  • 在生产服务器上运行的视图./manage.py shell返回了新数据
  • 我从两天前起就没有重新启动过生产服务器
  • 今天重启生产服务器后,视图中的数据又是新鲜的
  • 30 分钟后,数据现在已过时 30 分钟

可能是什么原因造成的?为什么我必须刷新与数据库的连接才能获取新数据?

相关代码:

# models.py
class MyModel(models.Model):
    name = models.CharField(max_length=255)

    def get_data(self,
            start_date=timezone.now()-timedelta(hours=24),
            end_date=timezone.now()):
        latest_data = self.data.filter(date__gte=start_date, date__lte=end_date).latest('date')
        return {
            'latest': latest_data.date
        }


class MyOtherModel(models.Model):
    date = models.DateTimeField()
    foreign_key = models.ForeignKey(MyModel, related_name='data')


# views.py
class MyView(generics.ListAPIView):
    serializer_class = MySerializer
    def get_queryset(self):
        queryset = MyModel.objects.all()


# serializers.py
class MySerializer(serializers.ModelSerializer):
    data = serializers.DictField(source="get_data")

    class Meta:
        model = MyModel
        fields = ('data',)
Run Code Online (Sandbox Code Playgroud)

当 Gunicorn 工作人员在视图序列化器中调用该方法时,该方法get_data返回陈旧数据。截至工作人员启动之日,数据已过时。

当从新的工作进程或新的 shell 实例调用时,该get_data方法不会返回过时的数据。

roo*_*oob 5

发现问题了。我正在获取某个时间范围的数据,并且该时间范围是在该方法的默认参数中设置的。

Python 中的默认参数在方法声明时计算一次。

我需要改变:

def get_data(self,
        start_date=timezone.now()-timedelta(hours=24),
        end_date=timezone.now()):
    latest_data = self.data.filter(date__gte=start_date, date__lte=end_date).latest('date')
    return {
        'latest': latest_data.date
    }
Run Code Online (Sandbox Code Playgroud)

到:

def get_data(self, start_date=None, end_date=None):
    if start_date is None:
        start_date = timezone.now()-timedelta(hours=24)
    if end_date is None:
        end_date = timezone.now()

    latest_data = self.data.filter(date__gte=start_date, date__lte=end_date).latest('date')
    return {
        'latest': latest_data.date
    }
Run Code Online (Sandbox Code Playgroud)