Как сделать заказ по удаленному полю без модели, подобному этому?

#django #django-rest-framework #annotate #django-annotate

#django #django-rest-framework #аннотировать #django-аннотировать

Вопрос:

У меня есть такая таблица:

 class SystemPushLog(models.Model):
    ...
    user_id = models.IntegerField(null=True)
  

Как вы можете видеть в приведенной выше модели, user_id это a IntegerField , а не внешний ключ. Потому что информация о пользователях в системе извлекается из вызовов gRPC. Теперь я хочу упорядочить набор last_login запросов, который является полем в информации о пользователе.
Я пробовал с annotate подобным в get_queryset :

     def get_queryset(self):
        queryset = super().get_queryset().annotate(
            last_login=self.__class__.get_user_last_login(F('user_id'))
        )
  

И ниже get_user_last_login :

     @staticmethod
    def get_user_last_login(user_id):
        print('user_id', user_id)  # <<< user_id F(user_id)
        print('type of user_id', type(user_id))  # <<< type of user_id <class 'django.db.models.expressions.F'>

        # retrieving user info from rpc call.
        user = do_user_actions({'id': user_id})
        return user.last_login
  

Как вы можете видеть, F('user_id') переданный функции, является типом django.db.models.expressions.F вместо фактического user_id .

Может annotate быть, можно просто взять несколько простых выражений, таких как annotate(off_price=F('original_price') - F('discount_price')) .

Итак, как я должен реализовать этот удаленный порядок полей?

Ответ №1:

Если вы не возражаете против добавления поля last_login в SystemPushLog, сделав поле last_login обнуляемым, вы можете заполнить last_login, переопределив django @classmethod def create() , тогда вы можете легко заказать свою модель, поскольку в ней есть поле last_login

Я не пробовал этого, но что-то вроде этого должно сработать

 def create(self, *args, **kwargs):
    if 'user_id' in kwargs and isinstance(kwargs['type'], int):
        # retrieving user info from rpc call.
        user = do_user_actions({'id': user_id})
        kwargs['last_login'] = user.last_login
    return super(SystemPushLog, self).create(*args, **kwargs)
  

Комментарии:

1. Но last_login это поле, которое будет меняться при повторном входе пользователя в систему, поэтому я должен получить его динамически. В противном случае я бы сделал так, как вы сказали.

2. @Gorgine Это правда, но даже если вы сможете каким-то образом передать F(‘id’), user.last_login вернет не выражения в QuerySet.annotate() . может быть, вы можете заполнять данные каждый раз, когда запрашиваете get_queryset(self) ?