更新使用中间件扩展默认用户的配置文件模型(last_activity 字段)DRF

Update Profile model that extends default User with middleware (last_activity field) DRF

我正在尝试更新 Profile 模型,它扩展了默认的 User 模型。但显然有些不对劲,因为 Profile 不显示任何条目。您能否建议如何在扩展另一个中间件的中间件中正确更新模型?

models.py

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    last_activity = models.DateTimeField()  # filled in by middleware

    def __str__(self):
        return str(self.id)

serializers.py

class ProfileSerializer(serializers.ModelSerializer):
    class Meta:
        model = Profile
        fields = '__all__'

view.py

class ProfileList(ListAPIView):
    queryset = Profile.objects.all()
    serializer_class = ProfileSerializer

middleware.py

from django.utils import timezone

class UpdateLastActivityMiddleware(object):
def __init__(self, get_response):
    self.get_response = get_response

def __call__(self, request):
    return self.get_response(request)

def process_view(self, request, view_func, view_args, view_kwargs):
    if request.user.is_authenticated():
        # Update last visit time after request finished processing.
        # I'm trying to create record - in case user had no activity before
        Profile.objects.filter(user__id=request.user.pk).update_or_create(last_activity=timezone.now())  # <-- looks like something is off here, since I'm not sure how to correctly update extended model

settings.py

MIDDLEWARE = [
    ...
    'core.middleware.UpdateLastActivityMiddleware',
]
Profile.objects.filter(user__id=request.user.pk).update_or_create(last_activity=timezone.now())

user.profile.last_activity=timezone.now()
user.save()

原因是因为它是一对一的关系,所以您不需要 update_or_create,因为用户将始终拥有个人资料,反向关系应该开箱即用,您可以直接更新 属性 last_activity

感谢@Borko Kovacev 和大量谷歌搜索,这是我最终得到的解决方案:

middleware.py

class UpdateLastActivityMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        return self.get_response(request)

    def process_view(self, request, view_func, view_args, view_kwargs):
        assert hasattr(request, 'user')

        # need to separately detect user when used middleware with JWT (else Anonymous User)
        try:
            auth_res = authentication.JWTAuthentication().authenticate(request)
        except InvalidToken:
            return JsonResponse({'error': 'Invalid token'}, status=status.HTTP_401_UNAUTHORIZED)

        if auth_res:
            request.user = auth_res[0]
        
        # save last_activity on each authenticated request
        if request.user.is_authenticated:
            request.user.profile.last_activity = timezone.now()  # assigning last_activity
            request.user.save()  # this triggers signal on User model saving
            print(f'MIDDLEWARE saved last_activity for {request.user}')

signals.py

from django.db.models.signals import post_save
from django.dispatch import receiver
from django.contrib.auth.models import User

from .models import Profile


@receiver(post_save, sender=User)  # to populate Profile on user creation (else fails because Profile record does not exist for user)
def create_profile(sender, instance, created, **kwargs):
    if created:
        print('signals create_profile ')
        Profile.objects.create(user=instance)

@receiver(post_save, sender=User)  # to update Profile on user update (triggered by middleware)
def save_profile(sender, instance, **kwargs):
    print('signals save_profile ')
    instance.profile.save()