Django Error: Field 'id' expected a number but got 'Action' - python

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

Related

How to create 2 objects from separate models with a single serializer and also retrieve them from the database with a single serializer in Django RF?

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.

Django order by primary key does not work

I have a model as below:
class Photos(models.Model):
id = models.IntegerField(primary_key=True, default=1)
name = models.CharField(max_length=500)
size = models.IntegerField()
path = models.CharField(max_length=500)
date = models.DateField(default=datetime.now)
def __str__(self):
return self.date.strftime('%Y-%m-%d')
class Meta:
verbose_name_plural = "Photos"
I want to retrieve the last primary key from the database (postgresql) as below:
try:
last_inserted = Photos.objects.order_by('-id')[0]
print(last_inserted)
except IndexError:
print("No data in the database")
but instead of a primary key I always get a date from the date column which is really strange! printing the last_inserted gives me '2018-09-04'.
As a test I change the 'id' column to lang (does not exists in table) gives below error message:
Cannot resolve keyword 'lang' into field. Choices are: date, id, name, path, size
in the above message why date is coming first then id and so on ..!
please help!
print(last_inserted) will show you result of model's __str__ method. To see id you can change model:
class Photos(models.Model):
id = models.IntegerField(primary_key=True, default=1)
name = models.CharField(max_length=500)
size = models.IntegerField()
path = models.CharField(max_length=500)
date = models.DateField(default=datetime.now)
def __str__(self):
return str(self.id)
class Meta:
verbose_name_plural = "Photos"
Or just change query to select only id field using values_list:
last_inserted = Photos.objects.order_by('-id').values_list('id', flat=True)[0]
print(last_inserted)
As for
in the above message why date is coming first then id and so on ..!
I suppose it because of alphabetical order.
You can also try it like this. A bit shorter
Photos.objects.order_by('-id').first().id
There is also a last()

DRF one to many serialization -- AttributeError from missing field

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")

GenericTabularInline isn't returning what it should in my Django Admin

I have the following models.py file:
class Product(Model):
...
class ExtraService(Model):
...
class Order(Model):
...
class OrderItem(Model):
order = models.ForeignKey(verbose_name=_('Order Item'), to=Order)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
item_relation = GenericForeignKey('content_type', 'object_id')
quantity = models.PositiveIntegerField(verbose_name=_('Quantity'), default=0)
And I'm working my admin.py this way:
class OrderItemInlineAdmin(GenericTabularInline):
model = OrderItem
min_num = 0
extra = 0
fields = ('item_relation', 'quantity',)
ct_field = 'content_type'
ct_fk_field = 'object_id'
class OrderAdmin(admin.ModelAdmin):
list_display = ('user_form',)
inlines = (OrderItemInlineAdmin,)
admin.site.register(Order, OrderAdmin)
I can't get my admin to show the OrderItem object inline (which can have a key to either a Product or an ExtraService) with my Order object, followed by its quantity field. Instead, it says the item_relation field is unknown:
FieldError at /admin/product/order/13/
Unknown field(s) (item_relation) specified for OrderItem
How do I bypass this?
PS: I've also tried using my own ModelForm but it still doesn't recognize the item_relation field.
PS1: If I don't define a fields variable in OrderItemInlineAdmin, I end up with something like this, which is incorrect because I have existing OrderItem objects and this assumes I don't (no object selected and no quantity?):

Searching by related fields in django admin

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'.

Categories