更新使用中间件扩展默认用户的配置文件模型(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()
我正在尝试更新 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()