1

I’m working through a book that introduces the Django and Django Rest frameworks. The tutorial creates a rest API with games, categories, players and scores, with a suitable relational model between them. I’ve stumbled upon an issue when inserting a game category I get the following error:

AttributeError at /game-categories/
'GameCategory' object has no attribute 'games'
Request Method: POST
Request URL:    http://127.0.0.1:8000/game-categories/
Django Version: 1.10.5
Exception Type: AttributeError
Exception Value:    
'GameCategory' object has no attribute 'games'
Exception Location: C:\Users\user\AppData\Local\Programs\Python\Python36-32\lib\site-packages\rest_framework\fields.py in get_attribute, line 103
Python Executable:  C:\Users\user\AppData\Local\Programs\Python\Python36-32\python.exe
Python Version: 3.6.0
Python Path:    
['C:\\Python\\Django01\\gamesapi',
 'C:\\Users\\user\\AppData\\Local\\Programs\\Python\\Python36-32\\python36.zip',
 'C:\\Users\\user\\AppData\\Local\\Programs\\Python\\Python36-32\\DLLs',
 'C:\\Users\\user\\AppData\\Local\\Programs\\Python\\Python36-32\\lib',
 'C:\\Users\\user\\AppData\\Local\\Programs\\Python\\Python36-32',
 'C:\\Users\\user\\AppData\\Local\\Programs\\Python\\Python36-32\\lib\\site-packages']
Server time:    Wed, 8 Mar 2017 09:40:42 +0000

My Game and GameCategory models are as follows:

class GameCategory(models.Model):
    name = models.CharField(max_length=200)

    class Meta:
        ordering = ('name',)

    def __str__(self):
        return self.name

class Game(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    name = models.CharField(max_length=200, blank=True, default='')
    game_category = models.ForeignKey(GameCategory, related_name='games', on_delete=models.CASCADE)
    release_date = models.DateTimeField()
    game_category = models.CharField(max_length=200, blank=True, default='')
    played = models.BooleanField(default=False)

    class Meta:
        ordering = ('name',)
    def __str__(self):
        return self.name

and the snippet of my urls.py:

urlpatterns = [
    url(r'^game-categories/$', views.GameCategoryList.as_view(),name=views.GameCategoryList.name),
    url(r'^game-categories/(?P<pk>[0-9]+)$', views.GameCategoryDetail.as_view(), name=views.GameCategoryDetail.name),

views.py:

from games.models import GameCategory
from games.models import Game
from games.models import Player
from games.models import PlayerScore    
from games.serializers import GameCategorySerializer
from games.serializers import GameSerializer
from games.serializers import PlayerSerializer
from games.serializers import PlayerScoreSerializer
from rest_framework import generics
from rest_framework.response import Response
from rest_framework.reverse import reverse

class GameCategoryList(generics.ListCreateAPIView):
    queryset=GameCategory.objects.all()
    serializer_class=GameCategorySerializer
    name='gamecategory-list'

class GameCategoryDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset=GameCategory.objects.all()
    serializer_class = GameCategorySerializer
    name = 'gamecategory-detail'

class GameList(generics.ListCreateAPIView):
    queryset=Game.objects.all()
    serializer_class = GameSerializer
    name = 'game-detail'

class GameDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset=Game.objects.all()
    serializer_class=GameSerializer
    name='game-detail'

serializers.py

from rest_framework import serializers
from games.models import GameCategory
from games.models import Game
from games.models import Player
from games.models import PlayerScore
import games.views

class GameCategorySerializer(serializers.HyperlinkedModelSerializer):
    games = serializers.HyperlinkedRelatedField(
        many=True,
        read_only=True,
        view_name='game-detail'
    )

    class Meta:
        model = GameCategory
        fields = ('url','pk','name','games')

class GameSerializer(serializers.HyperlinkedModelSerializer):
    #We want to display the game categorys name instead of the id
    game_category = serializers.SlugRelatedField(queryset=GameCategory.objects.all(), slug_field='name')

    class Meta:
        model = Game
        fields = (
            'url',
            'game_category',
            'name',
            'release_date',
            'played'
        )

I’m still very new to Python, let alone Django, so I am struggling to source the error here from the debug information given.

Can anyone help me understand where the problem is and why?

Y2H
  • 2,419
  • 1
  • 19
  • 37
LDJ
  • 6,896
  • 9
  • 52
  • 87

1 Answers1

1

How about removing HyperlinkedModelSerializer from GameCategorySerializer?

class GameCategorySerializer(serializers.ModelSerializer):
    # rest here unchanged

Check here for more.

[UPDATE]: You have a duplication inside the Game model!

game_category = models.ForeignKey(GameCategory, related_name='games', on_delete=models.CASCADE)

and

game_category = models.CharField(max_length=200, blank=True, default='')

You should rename the second game_category field to something else. Thus, the error you'are getting. GameCategorySerializer tries to handle this field (which does not have a related_name attribute) instead of the first (ForeignKey) one.

nik_m
  • 11,825
  • 4
  • 43
  • 57
  • Thanks, but unfortunately it made no difference. Exact same error. – LDJ Mar 08 '17 at 11:52
  • I think I found it... Updated my answer! – nik_m Mar 08 '17 at 11:55
  • You're right. It was indeed a duplicate. How did you deduce that from the error though? I have another error now (no such column: games_game.game_category_id) but would prefer to know how to debug these myself. Any ideas? Thanks – LDJ Mar 08 '17 at 14:18
  • 1
    I didn't resolve it from the error. I just copy pasted your code into my IDE and instantly highlighted it! You should use an IDE too. It makes dev, so much easier! Concering the other error, it seems like the database does not have the column `game_category_id` under the table `games_game` (classic DB error). So, what is the solution? Poke me, if you need it! – nik_m Mar 08 '17 at 14:22
  • Awesome. Thanks. Deleted my migrations folder (and DB), reran the migrations and its working now. Any recommendations on a (free) IDE for Python? Lightweight if possible. Cheers – LDJ Mar 08 '17 at 14:27
  • You shouldn't delete your migration folder. Next time run `./manage.py makemigration` and then `./migrate migrate` and everything should handled by Django properly. Here is a [list](http://stackoverflow.com/questions/175044/django-development-ide) of available IDEs. I'm using [PyCharm](https://www.jetbrains.com/pycharm/). – nik_m Mar 08 '17 at 14:29