Django Rest Framework relation Attribute error - python

I'm fighting to find my way into DRF and can't get related data into my endpoint.
models.py
class ChapterMark(models.Model):
title = models.CharField(max_length=100, null=True)
episode = models.ForeignKey(Episode, on_delete=models.CASCADE)
start_time = models.CharField(max_length=20)
class Episode(models.Model):
title = models.CharField(max_length=100, blank=False)
show = models.ForeignKey(Show, on_delete=models.PROTECT)
serializers.py
class ChapterMarkSerializer(serializers.ModelSerializer):
class Meta:
model = ChapterMark
exclude = ('')
class EpisodeSerializer(serializers.ModelSerializer):
chapters = ChapterMarkSerializer(source='id')
class Meta:
model = Episode
depth = 1
The error I'm getting is
Got AttributeError when attempting to get a value for field
start_time on serializer ChapterMarkSerializer. The serializer
field might be named incorrectly and not match any attribute or key on
the int instance. Original exception text was: 'int' object has no
attribute 'start_time'.
My guess is that the relation via source='id' just doesn't work but everything I found so far is pointing back to doing it that way.
There's a many to one relationship between chapters and episodes (so each episode has many chapters). I'm sure I'm just missing an important part.

To get reverse relation object use chaptermark_set as source of chapters field, also dont forget to add many=True since episode can have miltiple chapters:
class EpisodeSerializer(serializers.ModelSerializer):
chapters = ChapterMarkSerializer(source='chaptermark_set', many=True)
class Meta:
model = Episode
depth = 1

Related

Django / DRF - Got AttributeError when attempting to get a value for field `users_answers_set` on serializer `TestTakerSerializer`

everyone. I want to make a test in DRF. But DRF gave me this error:
models.py:
class TestTaker(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
test = models.ForeignKey(Test, on_delete=models.CASCADE)
class UsersAnswers(models.Model):
test_taker = models.ForeignKey(TestTaker, on_delete=models.CASCADE)
question = models.ForeignKey(Question, on_delete=models.CASCADE)
answer = models.ForeignKey(Answer, on_delete=models.CASCADE)
serializers.py
class UsersAnswersSerializer(serializers.ModelSerializer):
class Meta:
model = UsersAnswers
fields = "__all__"
class TestTakerSerializer(serializers.ModelSerializer):
users_answers_set = UsersAnswersSerializer(many=True)
class Meta:
model = TestTaker
fields = "__all__"
And the error is:
Got AttributeError when attempting to get a value for field `users_answers_set` on serializer `TestTakerSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `TestTaker` instance.
Original exception text was: 'TestTaker' object has no attribute 'users_answers_set'.
I tried to add "source" parameter to users_answers_set, but nothing changed.
Thank you.
try usersanswers_set instead of users_answers_set.
or
you can define custom related_name in your model:
class UsersAnswers(models.Model):
test_taker = models.ForeignKey(TestTaker, related_name="users_answers_set" , on_delete=models.CASCADE)

DRF: Reverse foreign key assignment using an array of primary keys

As stated in this question
With Django REST Framework, a standard ModelSerializer will allow ForeignKey model relationships to be assigned or changed by POSTing an ID as an Integer.
I am attempting to update a reverse relationship of the following format:
class Lesson(models.Model):
name = models.TextField()
class Quiz(models.Model):
lesson = models.ForeignKey(Lesson, related_name='quizzes', null=True)
class LessonSerializer(serializers.ModelSerializer):
quizzes = serializers.PrimaryKeyRelatedField(queryset=Quiz.objects.all(), many=True, write_only=True)
class Meta:
model = Lesson
fields = ('quizzes')
When posting an update containing an array of quiz primary keys using LessonSerializer I get TypeError: 'Quiz' instance expected, got '1'.
Is it possible to assign or change a reverse relationship by POSTing an array of primary keys?
You don't need special field in a serializer, DRF serializers is smart enough to figure out related field from a fields value.
class LessonSerializer(serializers.ModelSerializer):
class Meta:
model = Lesson
fields = ('quizzes', 'name')
And you should pass list of ids, if there is only one value it should be a list anyway.
To solve this you need to create a Quiz instance first before you assign it to Lesson. Below's a small change to your code.
class Lesson(models.Model):
name = models.TextField()
class Quiz(models.Model):
lesson = models.ForeignKey(Lesson, related_name='quizzes', null=True)
class LessonSerializer(serializers.ModelSerializer):
quizzes = serializers.PrimaryKeyRelatedField(queryset=Quiz.objects.all(), many=True, write_only=True)
class Meta:
model = Lesson
fields = ('quizzes')
class QuizSerializer(serializers.ModelSerializer):
class Meta:
model = Quiz
fields = ('name')
Create POST request with with quiz then run your post again

Django - Follow a backward ForeignKey and then a ForeignKey (query)

I use Django 1.9 and Python 2.7.
My app has four models. Each "trip" is made of several "steps" chosen by the visitor, which relate to "places", which may have several related "Picture".
class Trip(models.Model):
title = models.CharField(max_length=140, blank=True)
class Step(models.Model):
theplace = models.ForeignKey(ThePlace)
trip = models.ForeignKey(Trip)
class ThePlace(models.Model):
name = models.CharField(max_length=200)
class Picture(models.Model):
file = models.ImageField(upload_to="pictures")
slug = models.SlugField(max_length=100, blank=True)
theplace = models.ForeignKey(ThePlace, null=True, blank=True)
I would like to retrieve all "Picture" objects which are related to a specific Trip, using an existing "selectedtrip" queryset:
selectedtrip = Trip.objects.filter(author=request.user)[0]
pictures = selectedtrip.step_set.all().theplace.picture_set.all()
Django displays the following error:
"AttributeError: 'QuerySet' object has no attribute 'theplace'"
Any idea why ?
Because all() returns a queryset, which is a collection of items; theplace is an attribute on an individual Step, not on the collection.
The way to do this type of query is to start from the class you want to retrieve, and follow the relationships within the query using the double-underscore syntax. So:
Picture.objects.filter(theplace__step__trip=selectedtrip)

Creating many to many relation with AUTH_USER_MODEL in django via intermediary model

I am trying to create the following models. There is a ManyToMany relation from Entry to AUTH_USER_MODEL via the EntryLike intermediate model.
class BaseType(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
creation_time = models.DateTimeField(auto_now_add=True)
last_update_time = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
class Title(BaseType):
text = models.CharField(max_length=100)
description = models.TextField()
class EntryLike(BaseType):
entry = models.ForeignKey(Entry)
user = models.ForeignKey(settings.AUTH_USER_MODEL)
class Entry(BaseType):
title = models.ForeignKey(Title, on_delete=models.PROTECT)
text = models.TextField()
user = models.ForeignKey(settings.AUTH_USER_MODEL)
liked_by_users = models.ManyToManyField(settings.AUTH_USER_MODEL, through='EntryLike', through_fields=('entry', 'user'))
Running migrations on the above model scheme throws the error: AttributeError:'str' object has no attribute 'meta'.
Any help in resolving this error would be highly appreciated. Am new to Django & Python, but not to Web Development.
The issue is that settings.AUTH_USER_MODEL is almost certainly not a model instance. It's probably a string that constrains the choices another model can make - settings would be a strange place to leave a model definition.
To do a MTM between the user model and your field above you need need to do:
from django.contrib.auth.models import User
class Entry(BaseType):
title = models.ForeignKey(Title, on_delete=models.PROTECT)
text = models.TextField()
user = models.ForeignKey(User)
def __str__(self):
return self.title
I've added the str function so that it gives a more sensible return when you're manipulating it in admin/shell.
I'd also question whether you need the second set of fields (removed here), as you can use select related between the Entry and EntryLike join table, without any duplication of the fields - you can probably go that way, it's just a bit unnecessary.
Lastly, I'd note that the way I'm using it above just uses the default User object that comes with Django - you may wish to customise it. or extend the base class as you've done here with your own models' base class.
(All of this is predicated on AUTH_USER_MODEL not being a model instance - if it is, can you post the model definition from settings.py? )

select_related Issue

Here are my models:
class Brand(models.Model):
name = models.CharField(max_length=30)
order = models.SmallIntegerField()
class FeatureGroup(models.Model):
name = models.CharField(max_length=30)
class Feature(models.Model):
name = models.CharField(max_length=30, blank=True)
order = models.SmallIntegerField()
group = models.ForeignKey(FeatureGroup)
class FeatureDetail(models.Model):
description = models.TextField()
feature = models.ForeignKey(Feature)
class Phone(models.Model):
name = models.CharField(max_length=30)
brand = models.ForeignKey(Brand)
features = models.ManyToManyField(FeatureDetail)
I an trying to get features and feature details of the current phone and loop over data pairs but unable to do so.
I tried this and it only works for getting the brand:
p = get_object_or_404(Phone.objects.select_related('brand', 'feature__featuredetail'), id=id)
And when doing:
print p.featuredetail_set.all()
I get and this error:
Django Version: 1.4.3
Exception Type: AttributeError
Exception Value:
'Phone' object has no attribute 'featuredetail_set'
What's wrong?
You can't use a class name as a parameter to select_related. The parameter must be a string of your model field.
In your case, it should be 'features__feature'
Another problem is that select_related cannot follow many-to-many relationship. That's why prefetch_related comes.
Therefore, your queryset would be:
Phone.objects.select_related('brand').prefetch_related('features__feature')
Note that prefetch_related creates an additional query and does the joining in Python.
Your relation is called features, not featuredetail_set.
Note this has nothing to do with select_related, which does nothing in this case (it only works on forward ForeignKeys, anyway).

Categories

Resources