如何计算 Django 中 model_set 的不同?

How to count the distinct of model_set in Django?

我已经研究过这个 ,但我认为它有所不同。 让我进一步解释一下。我有一个名为 DetailTrackSerializer 的序列化程序来序列化我的 Track 模型,并且我在 DetailTrackSerializer 中嵌套了一个 TaggedSerializer

class DetailTrackSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField(read_only=True)
    title = serializers.CharField(max_length=120)
    link = serializers.URLField(max_length=120)
    tagged_set = TaggedSerializer(many=True)
    artist = ArtistSerializer()
    class Meta:
        model = Track
        fields = ('id', 'artist', 'title', 'link', 'tagged_set',)

class TaggedSerializer(serializers.ModelSerializer):
    tag = TagSerializer()
    class Meta:
        model = Tagged
        fields = ('tag',)

class TagSerializer(serializers.ModelSerializer):
    class Meta:
        model = Tag
        fields = ('name',)

目前,这个 DetailTrackSerializer 正在返回一个像这样的 json

{
    "tracks": [
        {
            "id": 168,
            "artist": {
                "id": 163,
                "name": "Gob"
            },
            "title": "Face the Ashes",
            "link": "",
            "tagged_set": [
                {
                    "tag": {
                        "id": 1356,
                        "name": "punk rock"
                    }
                },
                {
                    "tag": {
                        "id": 1356,
                        "name": "punk rock"
                    }
                },
                {
                    "tag": {
                        "id": 1356,
                        "name": "punk rock"
                    }
                },
                ...

等等,如果这个曲目中有 100 个 "punk rock" 标签,它将出现 100 次,并且可能还有另一个标签也不仅仅是 "punk rock"。我需要的是这样的东西

{
    "tracks": [
        {
            "id": 168,
            "artist": {
                "id": 163,
                "name": "Gob"
            },
            "title": "Face the Ashes",
            "link": "",
            "tagged_set": [
                {
                    "tag": {
                        "id": 1356,
                        "name": "punk rock"
                    },
                    "frequency": 100,
                },
                {
                    "tag": {
                        "id": 546,
                        "name": "pop"
                    },
                    "frequency": 236,
                },
                ...

每个标签只出现一次,并且有频率。 注意:我也在使用 Django Rest Framework

编辑:models.py

class Tagged(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
    track = models.ForeignKey(Track, on_delete=models.CASCADE)
    tag = models.ForeignKey(Tag, on_delete=models.CASCADE)
class Tag(models.Model):
    name = models.CharField(max_length=255, unique=True)
class Track(models.Model):
    artist = models.ForeignKey(Artist, on_delete=models.CASCADE)
    title = models.CharField(max_length=255)
    link = models.URLField(max_length=255, blank=True)
    tags = models.ManyToManyField(Tag, through='Tagged', blank=True)

Edwin Harly,Track、Tag 和 Tagged 模型之间有一些数据重叠。如果您接受,我建议您删除标记模型。如果要保存哪个用户创建标签,请在标签模型中添加用户字段。

class Tag(models.Model):
name = models.CharField(max_length=255, unique=True)
user = models.ForeignKey(User, on_delete=models.CASCADE, default=1)

class Track(models.Model):
    artist = models.ForeignKey(Artist, on_delete=models.CASCADE)
    title = models.CharField(max_length=255)
    link = models.URLField(max_length=255, blank=True)
    tags = models.ManyToManyField(Tag, through='Tagged', blank=True)

然后,您可以像这样使用序列化程序:

class DetailTrackSerializer(serializers.ModelSerializer):

    id = serializers.IntegerField(read_only=True)
    title = serializers.CharField(max_length=120)
    link = serializers.URLField(max_length=120)
    tags = TagSerializer(many=True)
    artist = ArtistSerializer()

    class Meta:
        model = Track
        fields = ('id', 'artist', 'title', 'link', 'tags',)



class TagSerializer(serializers.ModelSerializer):
    class Meta:
        model = Tag
        fields = ('name',)

从你的Tagged我了解到Data Redundancy的可能性很大,这就是你的tagged_set多次出现的原因。

我想说的是,这不是 Representation Problem 与你的序列化程序 ,而不是 它是 Implementation Problem 与你的模型.

所以,unique_together 属性将解决问题,因为

class Tagged(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
    track = models.ForeignKey(Track, on_delete=models.CASCADE)
    tag = models.ForeignKey(Tag, on_delete=models.CASCADE)

    <b>class Meta:
        unique_together = ('track', 'tag')</b>

更改模型后,请执行makemigrationsmigration

注意:在执行 migration 时,您可能会遇到 django.db.utils.IntegrityError: UNIQUE constraint failed 异常。因此,删除 Tagged 模型

中的所有条目

阅读 Django 关于 querysets 的文档后,这是我想出的解决方案

class DetailTrackSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField(read_only=True)
    title = serializers.CharField(max_length=120)
    link = serializers.URLField(max_length=120)
    tags_frequency = serializers.SerializerMethodField()
    artist = ArtistSerializer()

    def get_tags_frequency(self, track):
        tags = track.tags.all()
        return tags.values('id', 'name').annotate(Count('id'))

    class Meta:
        model = Track
        fields = ('id', 'artist', 'title', 'link', 'tags_frequency',)

这将给我 json 这样的表示

{
    "tracks": [
        {
            "id": 168,
            "artist": {
                "id": 163,
                "name": "Gob"
            },
            "title": "Face the Ashes",
            "link": "",
            "tags_frequency": [
                {
                    "name": "punk rock",
                    "id": 1356,
                    "id__count": 100
                },
                {
                    "name": "punk",
                    "id": 1357,
                    "id__count": 60
                }
            ]
        },
        {
            "id": 169,
            "artist": {
                "id": 164,
                "name": "Jeff And Sheri Easter"
            },
            "title": "The Moon And I (Ordinary Day Album Version)",
            "link": "",
            "tags_frequency": []
        },