0

Currently I have a site, and I want the user to be able to view their liked articles. I want this to be included in the user api view that is already set up. I have tried the tracks = serializers.StringRelatedField(many=True)that is in the drf docs yet this didn't work. I have also tried the following:

    from rest_framework import serializers

from articles.models import Article, CustomUser,FavoriteArticles


class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = ('title', 'content')
class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = CustomUser
        fields = '__all__'

class FavoriteArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = FavoriteArticles
        fields = '__all__'

class UserProfileSerializer(serializers.ModelSerializer):
    fav_title = FavoriteArticleSerializer(read_only=False)
    class Meta:
        model = CustomUser
        fields = 'username, git, email, fav_article, fav_title, homepage'

and my models:

from django.db import models
# users/models.py
from django.contrib.auth.models import AbstractUser
from django.db.models.signals import post_save
from django.dispatch import receiver
import uuid



class ProgrammingLanguage(models.Model):
    programming_language = models.CharField(max_length=120, null=False, primary_key=True, default="React")

    def __str__(self):
        return self.programming_language

class Article(models.Model):
    title = models.CharField(max_length=25, primary_key=True)
    content = models.TextField()
    usedfor = models.TextField()
    url=models.CharField(max_length=200, null=True)
    article_programming_language = models.ForeignKey(ProgrammingLanguage, on_delete=models.CASCADE, related_name="article_programming_language", default="react")
    score = models.IntegerField(max_length=5, null=0)

    def __str__(self):
        return self.title

class CustomUser(AbstractUser):
    username = models.CharField(max_length=50, unique=True, primary_key=True)
    git = models.CharField(max_length=200, null=True)
    homepage = models.CharField(max_length=250, null=True)
    user_programming_language = models.ForeignKey(ProgrammingLanguage, on_delete=models.CASCADE, related_name="most_used_programming_language", default="react")
    def __str__(self):
        return str(self.username)


class FavoriteArticles(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    fav_title = models.ForeignKey(Article, on_delete=models.CASCADE, related_name='fav_title')
    reasons_liked = models.CharField(max_length=120, null=True)
    user = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name="user", default="tom" )
    def __unicode__(self):
        return '%s: %s' % (self.fav_title, self.reasons_liked)
lakerskill
  • 1,019
  • 1
  • 11
  • 24

1 Answers1

1

I think you misunderstood what related_name means. It specifies how you would access a model from its reverse relationship. So I'd recommend you remove it from fields in your FavoriteArticles model and use the default Django already provides (in this case favoritearticles_set):

class FavoriteArticles(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    fav_title = models.ForeignKey(Article, on_delete=models.CASCADE)
    reasons_liked = models.CharField(max_length=120, null=True)
    user = models.ForeignKey(CustomUser, on_delete=models.CASCADE, default="tom")

    def __unicode__(self):
        return '%s: %s' % (self.fav_title, self.reasons_liked)

This way, you can access favorite articles of a user via my_user.favoritearticles_set.all(). Then, you can change your UserSerializer to include a liked_articles field which is populated from the favoritearticles_set reverse relationship to a user's FavoriteArticles using a source attribute:

class UserSerializer(serializers.ModelSerializer):
    liked_articles = FavoriteArticleSerializer(source='favoritearticles_set', many=True, read_only=True)

    class Meta:
        model = CustomUser
        # explicitly include other fields as required
        fields = ('username', 'git', 'user_programming_language', 'liked_articles')

Note that we've made this a read_only field, so it will only get populated if you perform a GET request.

slider
  • 12,810
  • 1
  • 26
  • 42
  • 1
    You're answer worked liked a charm. Thanks. Can you just explain what this is? source='favoritearticles_set' – lakerskill Oct 14 '18 at 23:29
  • @lakerskill `source` specifies which model field should be used for this serializer field. In this specific case, we're saying that we want to use the reverse relation field `favoritearticles_set` of the user model. This is a field that Django gives us by default because we defined a foreign key field to `CustomUser` in the `FavoriteArticles` model. – slider Oct 14 '18 at 23:37