Error:
AttributeError at /stats/matches
Got AttributeError when attempting to get a value for field players on serializer MatchSerializer.
The serializer field might be named incorrectly and not match any attribute or key on the Match instance.
Original exception text was: 'Match' object has no attribute 'players'.
Models:
Every Match has 10 players.
class Match(models.Model):
tournament = models.ForeignKey(Tournament, blank=True)
mid = models.CharField(primary_key=True, max_length=255)
mlength = models.CharField(max_length=255)
win_rad = models.BooleanField(default=True)
class Player(models.Model):
match = models.ForeignKey(Match, on_delete=models.CASCADE)
playerid = models.CharField(max_length=255, default='novalue')
# There is also a Meta class that defines unique_together but its omitted for clarity.
Serializers:
class PlayerSerializer(serializers.ModelSerializer):
class Meta:
model = Player
fields = "__all__"
class MatchSerializer(serializers.ModelSerializer):
players = PlayerSerializer(many=True)
class Meta:
model = Match
fields = ("mid","players")
The MatchSerializer search for a players attribute in Match's instance, but it couldn't find and you get the following error:
AttributeError at /stats/matches
Got AttributeError when attempting to get a value for field players on
serializer MatchSerializer. The serializer field might be named
incorrectly and not match any attribute or key on the Match instance.
Original exception text was: 'Match' object has no attribute 'players'.
In DRF serializer, a parameter called source will tell explicitly where to look for the data. So, change your MatchSerializer as follow:
class MatchSerializer(serializers.ModelSerializer):
players = PlayerSerializer(many=True, source='player_set')
class Meta:
model = Match
fields = ("mid", "players")
Hope it helps.
The problem here is that Match model has not an attribute called players, remember that you are trying to get backwards relationship objects, so you need to use players_set as field as django docs says.
You could solve this in Two Ways
1. Adding a source parameter to the PlayerSerializer
class MatchSerializer(serializers.ModelSerializer):
players = PlayerSerializer(many=True, source='player_set')
class Meta:
model = Match
fields = ("mid", "players")
2. Change the lookup-field
class MatchSerializer(serializers.ModelSerializer):
player_set = PlayerSerializer(many=True)
class Meta:
model = Match
fields = ("mid","player_set")
Related
I have 3 models: Maker, Item and MakerItem that creates the relation between the items and their makers:
class Maker(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4)
name = models.CharField(max_length=100)
class Item(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4)
name = models.CharField(max_length=100)
class MakerItem(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4)
item_id = models.ForeignKey(Item, on_delete=models.CASCADE)
maker_id = models.ForeignKey(Maker, on_delete=models.CASCADE)
the items can have a random amount of makers.
I want to create both the Item and the MakerItem objects at the same time with a single set of data,
for example if a Maker with id = "abcd" already exists, and I go to /item and send a POST request with the following data:
{
"name": "item1",
"makers": [
{
"maker_id": "abcd"
}
]
}
I want the serializer to create the Item object and the MakerItem object.
I have achieved this, with the following setup:
views.py
class ItemListCreate(ListCreateAPIView):
queryset = Item.objects.all()
serializer_class = ItemSerializer
serializers.py
class ItemSerializer(serializers.ModelSerializer):
class MakerItemSerializer(serializers.ModelSerializer):
class Meta:
model = MakerItem
exclude = ['id', 'item_id']
makers = MakerItemSerializer(many=True)
class Meta:
model = Item
fields = ['id', 'name', 'makers']
def create(self, validated_data):
maker_item_data = validated_data.pop('makers')
item_instance = Item.objects.create(**validated_data)
for each in maker_item_data:
MakerItem.objects.create(
item_id=check_instance,
maker_id=each['maker_id']
)
return item_instance
but when Django tries to return the created object, it always gives me the error:
AttributeError at /item/
Got AttributeError when attempting to get a value for field `makers` on serializer `ItemSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `Item` instance.
Original exception text was: 'Item' object has no attribute 'makers'.
What am I doing wrong?
Thanks
EDIT: To clarify, the objects get created and populate the database correctly, but when the browsable API that DRF provides tries to display the created object, it gives me the error above.
Change:
class ItemSerializer(serializers.ModelSerializer):
class MakerItemSerializer(serializers.ModelSerializer):
class Meta:
model = MakerItem
exclude = ['id', 'item_id']
makers = MakerItemSerializer(many=True)
To:
class ItemSerializer(serializers.ModelSerializer):
class MakerItemSerializer(serializers.ModelSerializer):
class Meta:
model = MakerItem
exclude = ['id', 'item_id']
makers = MakerItemSerializer(many=True, source="makeritem_set")
Hope this works!
For clarity, you're attempting to serialise the reverse relationship between MakerItem and Item for this serialiser.
This means that the attribute on your object is automatically set by Django as fieldname_set but you can override this behaviour by setting the related_name kwarg on the field and then makemigrations and migrate it.
In your case you would need to do:
maker_id = models.ForeignKey(Maker, on_delete=models.CASCADE, related_name="maker_items")
And then update the field in the Meta to match the new field name, this way you don't have to manually specify source. Because actually the attribute "makers" is misleading, due to the fact its actually the MakerItem, not the Maker itself.
See https://docs.djangoproject.com/en/3.2/ref/models/relations/ for further details about this behaviour.
Error: Field 'id' expected a number but got 'Action'.
I am getting this error when trying to submit a form. It works fine if i use the admnin page to add a post so the errror must be in the forms.
error only occurs when i click on one of the checkboxes
models.py:
class Genres(models.Model):
name = models.CharField(max_length=100)
class Meta:
verbose_name_plural = "Genres"
ordering = ('name',)
class Post(models.Model):
genres = models.ManyToManyField(Genres, null=True, blank=True)
forms.py:
genre_choices = Genres.objects.all().values_list('name', 'name')
genre_choices_list = []
for item in genre_choices:
genre_choices_list.append(item)
class NewPost(forms.ModelForm):
genres = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple(attrs={'class': 'form_input_select_multi'}),
choices=genre_choices_list, required=False)
You're passing names while should have pass ids. Try something like that:
genre_choices = Genres.objects.all().values_list('id', 'name')
Look at line above: now it returns id & name tuple instead of name & name. So, MultipleChoiceField takes id as a value not name
I'm trying to query a specific column from my table. I've tried doing it with this
team_lenDeserialized = RolesInTeam.objects.values_list('user_id', flat=True).filter(academic_year_id=9).filter(deleted=0)
team_lenDict = RolesInTeamSerializer(team_lenDeserialized, many=True)
team_len = orderedDictToJSON(team_lenDict.data)
After that I run it through a function that converts it to JSON
def orderedDictToJSON(orderedDict):
return json.loads(json.dumps(orderedDict))
then I go and manipulate it further. However if I try to serialize and convert the team_lenDeserialized I get an error that states
AttributeError: Got AttributeError when attempting to get a value for field `user_id` on
serializer RolesInTeamSerializer`.
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 'user_id'.
This is my model for that table
class RolesInTeam(models.Model):
user_id = models.IntegerField()
team_id = models.IntegerField()
role_id = models.IntegerField()
deleted = models.IntegerField()
academic_year_id = models.IntegerField()
class Meta:
managed = False
db_table = 'roles_in_team'
and my serializer
class RolesInTeamSerializer(serializers.ModelSerializer):
class Meta:
model = RolesInTeam
fields = ['id', 'user_id', 'team_id', 'role_id', 'deleted', 'academic_year_id']
I have no clue what's happening or why it's not working.
You can only serialize models instances with a ModelSerializer, and values_list() returns a queryset of tuples, so when you try to use the serializer over the queryset, you get the error.
If you make a regular query (team_lenDeserialized = RolesInTeam.objects.filter(academic_year_id=9).filter(deleted=0)), you would be able to serialize team_lenDeserialized.
I got following models:
class OrderItem(models.Model):
ordered_amount = models.IntegerField(validators=[MinValueValidator(0)])
amount = models.IntegerField(default=0)
order = models.ForeignKey(
Order, on_delete=models.CASCADE, related_name="order_items"
)
class Order(models.Model):
reference = models.CharField(max_length=50)
purchase_order = models.CharField(max_length=15, blank=True, null=True)
I'm now writing a serializer for listing orders. In this OrderSerializer I need to access amount and ordered_amount in the OrderItem class. How do I do this?
This is What I have now:
class AdminOrderListSerializer(serializers.ModelSerializer):
amount = serializers.IntegerField()
ordered_amount = serializers.IntegerField()
class Meta:
model = Order
fields = [
"purchase_order",
"reference",
"amount",
"ordered_amount",
]
# noinspection PyMethodMayBeStatic
def validate_amount(self, order):
if order.order_items.amount:
return order.order_items.amount
return
# noinspection PyMethodMayBeStatic
def validate_ordered_amount(self, order):
if order.order_items.ordered_amount:
return order.order_items.ordered_amount
return
This gives me following error:
AttributeError: Got AttributeError when attempting to get a value for field amount on serializer AdminOrderItemListSerializer.
The serializer field might be named incorrectly and not match any attribute or key on the Order instance.
Original exception text was: 'Order' object has no attribute 'amount'.
There are many ways to that, one of them is SerializerMethodField:
from django.db.models import Sum
class AdminOrderListSerializer(serializers.ModelSerializer):
amount = serializers.SerializerMethodField()
ordered_amount = serializers.SerializerMethodField()
def get_amount(self,obj):
return obj.order_items.aggregate(sum=Sum('amount'))['sum']
def get_ordered_amount(self,obj):
return obj.order_items.aggregate(sum=Sum('order_amount'))['sum']
Optimized solution
Another way of achieving this is to annotate the data to queryset, and access them in serializer. For that, you need to change in view:
class SomeView(ListAPIView):
queryset = Order.objects.annotate(amount=Sum('order_items__amount'),order_amount=Sum('order_items__order_amount'))
This is a optimized solution because it reduces database hits(it only hits once).
I've been looking at the docs for search_fields in django admin in the attempt to allow searching of related fields.
So, here are some of my models.
# models.py
class Team(models.Model):
name = models.CharField(max_length=255)
class AgeGroup(models.Model):
group = models.CharField(max_length=255)
class Runner(models.Model):
"""
Model for the runner holding a course record.
"""
name = models.CharField(max_length=100)
agegroup = models.ForeignKey(AgeGroup)
team = models.ForeignKey(Team, blank=True, null=True)
class Result(models.Model):
"""
Model for the results of records.
"""
runner = models.ForeignKey(Runner)
year = models.IntegerField(_("Year"))
time = models.CharField(_("Time"), max_length=8)
class YearRecord(models.Model):
"""
Model for storing the course records of a year.
"""
result = models.ForeignKey(Result)
year = models.IntegerField()
What I'd like is for the YearRecord admin to be able to search for the team which a runner belongs to. However as soon as I attempt to add the Runner FK relationship to the search fields I get an error on searches; TypeError: Related Field got invalid lookup: icontains
So, here is the admin setup where I'd like to be able to search through the relationships. I'm sure this matches the docs, but am I misunderstanding something here? Can this be resolved & the result__runner be extended to the team field of the Runner model?
# admin.py
class YearRecordAdmin(admin.ModelAdmin):
model = YearRecord
list_display = ('result', 'get_agegroup', 'get_team', 'year')
search_fields = ['result__runner', 'year']
def get_team(self, obj):
return obj.result.runner.team
get_team.short_description = _("Team")
def get_agegroup(self, obj):
return obj.result.runner.agegroup
get_agegroup.short_description = _("Age group")
The documentation reads:
These fields should be some kind of text field, such as CharField or TextField.
so you should use 'result__runner__team__name'.