How to order by a non-model remote field like this?

154 views Asked by At

I have a table like this:

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

As u can see in the model above, user_id is a IntegerField, not a foreign key. Cuz user infos in out system are retrieved from gRPC calls. Now, I wanna to order the queryset by last_login which is a field in user info. I have tried with annotate like this in get_queryset:

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

And below is 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

As u can see, F('user_id') passed to the func is a type of django.db.models.expressions.F instead of a actual user_id.

Maybe annotate can just take some simple expressions like annotate(off_price=F('original_price') - F('discount_price')).

So, how should I implement this remote field ordering?

1

There are 1 answers

2
Alvi15 On

If you don't mind adding a last_login field in SystemPushLog, by making last_login field nullable, you can populate last_login by overriding django @classmethod def create() then you can easily order your model since it has last_login field

I haven't tried this but something like this should work

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)