YYLeo
YYLeo

Reputation: 13

Django REST framework serialize last log

I use Django rest framework in a website, and it works well.

But I just meet a speical problem, just like this:

models.py:

class User(models.Model):
    uid = models.IntegerField(
        primary_key=True,
    )
    name = models.CharField(
        max_length=15,
    )

class LoginLog(models.Model):
    sn = models.AutoField(
        primary_key=True,
    )
    user = models.ForeignKey(
        to=User,
    )
    time = models.IntegerField(
        null=False,
    )
    IP = models.CharField(
        max_length=20,
        verbose_name='Login IP',
    )

serializers.py:

class UserSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = User
        fields = '__all__'

class UserListView(generics.ListAPIView, ):
    queryset = User.objects.all()
    serializer_class = UserSerializer

How can I serialize the last LoginLog in UserSerializer?

Just return json data like this:

{
    "name": "admin",
    "uid": 1,
    "last_login": {
        "time": 1503414665,
        "IP": "127.0.0.1"
    }
}

Upvotes: 1

Views: 579

Answers (2)

mindcruzer
mindcruzer

Reputation: 844

Since you only want the time, and not the entire entity:

class UserSerializer(serializers.HyperlinkedModelSerializer):
    last_login_time = serializers.SerializerMethodField()

    def get_last_login_time(self, obj):
        last_login = obj.loginlog_set.last()
        if last_login is not None:
            return last_login.time
        return None

    class Meta:
        model = User
        fields = ('uid', 'account', 'last_login_time')

Also, white-listing all fields on the model by default can get you into trouble and is not recommended. Be explicit (like above).

Upvotes: 2

wencakisa
wencakisa

Reputation: 5958

A possible solution can be to use SerializerMethodField:

class UserSerializer(serializers.HyperlinkedModelSerializer):
    login_log = serializers.SerializerMethodField()

    class Meta:
        model = User
        fields = '__all__'

    def get_login_log(self, obj):
        last_login_log = obj.__class__.objects.filter(user=obj.user).last()
        login_log_serializer = LoginLogSerializer(last_login_log)

        return login_log_serializer.data
  • obj.__class__ will simply reproduce LoginLog
  • Then you filter those entries, which are related to your user
  • You get the last() one and return it serialized.

It's controversial whether this is straightforward and simple, but it will give the wanted result. It's a bit hacky.

You can have a look at this: Return only last entry of related model in serializer - Django

Upvotes: 1

Related Questions