DRF Exception value: Cannot assign - it must be a instance - python

I know there are a bunch of questions addressing this issue, but I haven't solved it out yet. I'm using DRF for the first time and I'm working with nested serializers. My Restaurant serializer points to a Category serializer via a slug related field as it shows below
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = (
'name',
'description'
)
class RestaurantSerializer(serializers.HyperlinkedModelSerializer):
category = serializers.SlugRelatedField(
many=True,
read_only=False,
queryset=Category.objects.all(),
slug_field='name'
)
class Meta:
model = Restaurant
fields = (
'id',
'name',
'description',
'website',
'twitter',
'facebook',
'instagram',
'category'
)
I send all the necessary data to my endpoint to create a new Restaurant via jquery but I keep getting "Cannot assign "[< Category: Italian food >]": "Restaurant.category" must be a "Category" instance."
I understand I need to assign a Category object to Restaurant's category, although I don't know how to access my queryset to extract the object that matters.
Any advices on this?
Edit: This is the data I'm sending from jquery to my endpoint
{"name":"Restaurant","email":"restaurant#gmail.com","password":"1234","category":["Italian food"],"description":"Description test"}
Edit # 2 See the model definitions below
class Restaurant(models.Model):
name = models.CharField(max_length=80, null=False)
description = models.TextField(max_length=300, null=False)
email = models.EmailField(max_length=80, null=True)
password = models.CharField(max_length=60, null=False)
website = models.URLField(max_length=80, null=True)
twitter = models.CharField(max_length=60, null=True, blank=True)
facebook = models.CharField(max_length=60, null=True, blank=True)
instagram = models.CharField(max_length=60, null=True, blank=True)
category = models.ForeignKey('Category')
def __unicode__(self):
return self.name
class Category(models.Model):
name = models.CharField(max_length=80, null=False)
description = models.TextField(max_length=100, null=False)
def __unicode__(self):
return self.name

You have a ForeignKey from Restaurant to Category. That means there is only one Category for each Restaurant. But you are sending a list of category slugs, and you have many=True in the definition of the SlugRelatedField.
Your data should just be {..."category": "Italian food"...}, and you should remove the many=True.

Related

How can I dispay the data in django admin panel

I am creating an eCommerce website but I want to know how can I display a product_name or customer_name in the admin panel.
The concept is that if a customer places an order that it will go to the admin panel. So the other details are displaying properly except product_name or customet_name.
As shown in the below image:
models.py
class Order(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
quantity = models.IntegerField(default=1)
address = models.CharField(max_length=50, default='', blank=True)
phone = models.CharField(max_length=50, default='', blank=True)
price = models.IntegerField()
date = models.DateField(default=datetime.datetime.today)
status = models.BooleanField(default=False)
admin.py
class AdminOrders(admin.ModelAdmin):
list_display = ['product', 'customer', 'quantity', 'address', 'phone', 'price', 'date', 'status']
You need to define the __str__ method in the models Product and Customer
Example:
def __str__(self):
return self.name
If you call a function it have to return string if you want to display as word.
I know 2 ways to do this
First its repr Method
def __repr__(self):
return self.(Model You wanna Display)
or str Witch is akcually same
def __str__(self):
return self.(Model You wanna Display)
Have tried double underscore in order to access the foreign item field (product__name) and (customer__name).
class Product(models.Model):
name= models.CharField(max_length=50, default='', blank=True)
....
class Customer(models.Model):
name= models.CharField(max_length=50, default='', blank=True)
....
class AdminOrders(admin.ModelAdmin):
list_display = ['product__name', 'customer__name', 'quantity', 'address', 'phone', 'price', 'date', 'status']

ValueError: Field 'id' expected a number but got string in Django Rest Framework

In DRF I am facing an issue, whenever I do a POST request on the endpoint, on the field "name" which is a text field I get an exception "Field 'id' expected a number but got 'TITLE'", but when I change the value of "name" to an integer the request is successful I don't understand it becauses name is TextField in model and why its mixing Id and Name field with each other. I have deleted the migration files from the Project and DB and re-run the Migrations, but still facing this issue.
Following is my code:
models.py
class Project(models.Model):
admin = models.ForeignKey(User, on_delete=models.CASCADE, related_name='project_crated_by')
name = models.TextField(max_length=225, blank=False, null=False)
project_members = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='members', null=True, blank=True)
created_on = models.DateField(default=timezone.now)
tags = ArrayField(models.CharField(max_length=225, default=''), blank=True)
def __str__(self):
return self.name
objects = models.Manager()
views.py
class ProjectView(viewsets.ViewSet):
def create(self, request):
project_name_exist = Project.verify_project_name(request.data['admin'], request.data['name'])
if project_name_exist:
return Response({'message': 'You already have a project with this name',
'status': status.HTTP_200_OK})
serialized_project = ProjectSerializer(data=request.data)
if serialized_project.is_valid():
serialized_project.save()
return Response({'message': 'Project Created Successfully', 'status': status.HTTP_201_CREATED})
else:
return Response({'error': serialized_project.errors, 'status': status.HTTP_400_BAD_REQUEST})
serializer.py
class ProjectSerializer(serializers.ModelSerializer):
class Meta:
model = Project
fields = '__all__'
A more generic and non-DIY solution is to use UniqueTogetherValidator on your serializer and let Django sort it out.
from rest_framework.validators import UniqueTogetherValidator
class ProjectSerializer(serializers.ModelSerializer):
class Meta:
model = Project
fields = '__all__'
validators = [
UniqueTogetherValidator(
queryset=Project.objects.all(),
fields=['admin', 'name'],
message='You already have a project with this name'
)
]
And/or add it to the model for enforcing it on the database.
class Project(models.Model):
admin = models.ForeignKey(User, on_delete=models.CASCADE, related_name='project_crated_by')
name = models.TextField(max_length=225, blank=False, null=False)
project_members = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='members', null=True, blank=True)
created_on = models.DateField(default=timezone.now)
tags = ArrayField(models.CharField(max_length=225, default=''), blank=True)
def __str__(self):
return self.name
objects = models.Manager()
class Meta:
unique_together = ("admin", "name")

DjangoFilterBackend: Filtering on a primary key results in "Select a valid choice. That choice is not one of the available choices."

I have two models (Product & Category) which every product has a linked category.
I have installed DjangoFilterBackend which the hope of filtering on the category field to return a list of products in that category.
However, whenever I send the query in Postman. I receive the error Select a valid choice. That choice is not one of the available choices..
I have tried filtering on another field in my product model (name for an example) and that works fine. So i'm not sure if i'm missing something for category to work.
Product/View.py:
class ProductView(ListAPIView):
serializer_class = ProductSerializer
queryset = Product.objects.all()
filter_backends = [DjangoFilterBackend]
filterset_fields = ('category', 'name')
Products/Models.py:
class Product(models.Model):
name = models.CharField(max_length=250, unique=True, blank=False)
photo = models.ImageField(upload_to=product_photo_path)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
quantity = models.IntegerField()
description = models.TextField(blank=False)
price = models.DecimalField(max_digits=6, decimal_places=2)
in_stock = models.BooleanField(default=False)
trending = models.BooleanField(default=False)
def __str__(self):
return self.name
Products/serializers.py
class ProductSerializer(serializers.ModelSerializer):
category = serializers.CharField(source='category.name', read_only=True)
class Meta:
model = Product
fields = ('category', 'name', 'photo', 'quantity', 'description', 'price', 'in_stock', 'trending')
The query I am using is a GET request to:
http://127.0.0.1:8000/api/products?category=xxxx - I am sending no payload. The response I am receiving is a `400 Bad Request` and the exact error is:
{
"category": [
"Select a valid choice. That choice is not one of the available choices."
]
}
Ah-ha!
I changed the model to:
class Product(models.Model):
name = models.CharField(max_length=250, unique=True, blank=False)
photo = models.ImageField(upload_to=product_photo_path)
**category = models.ForeignKey(Category, to_field='name', on_delete=models.CASCADE)**
quantity = models.IntegerField()
description = models.TextField(blank=False)
price = models.DecimalField(max_digits=6, decimal_places=2)
in_stock = models.BooleanField(default=False)
trending = models.BooleanField(default=False)
And now it works!
Well, I am not sure, but try to filter on field category_id, this field is created automatically for FK fields
Just in case somebody will ever need the answer, to be able to use the name of a foreign field to filter instead of the primary key use a double underscore i.e category__name in this case. Note that name in this case is the field of the foreign model that you want to filter with and you can replace it with your field accordingly.

Django Rest Framework requieres as not null look up field

I have two models:
class Album(models.Model):
code = models.CharField(max_length=10, primary_key=True, default=_create_access_code, verbose_name=_("Id"))
name = models.CharField(max_length=200, verbose_name=_("Name"))
description = models.TextField(null=True, blank=True, verbose_name=_("Description"))
company = models.ForeignKey(Company, on_delete=models.PROTECT, related_name='albums', verbose_name=_("Company"))
access_code = models.CharField(max_length=10, default=_create_access_code, verbose_name=_("Internal Use"))
class Meta:
verbose_name = _("Album")
verbose_name_plural = _("Albums")
def __str__(self):
return "[{}] {} ({})".format(self.pk, self.name, self.company.id)
class Photo(models.Model):
name = models.CharField(max_length=100, null=True, blank=True, verbose_name=_("Name"))
album = models.ForeignKey(Album, on_delete=models.CASCADE, related_name='photos', verbose_name=_("Album"))
photo = models.ImageField(verbose_name=_("Photo"))
class Meta:
verbose_name = _("Photo")
verbose_name_plural =_("Photos")
def __str__(self):
return "[{}] {}".format(self.pk, self.name)
I am trying to make a post to the ModelViewSet for model Albums, but I get an error indicating that field photos is required. Even the OPTIONS method indicates it es required.
How can I instruct DRF for not considering look up fields as required? Is it some serializer setting?
You can add required=False to fields in the serializer.
photos = PhotoSerializer(many=True, required=False)
Something like this. Can you post you serializers?

Django Rest creating Nested-Objects (ManyToMany)

I looked for an answer to this question specifically for Django Rest, but I haven't found one anywhere, although I think a lot of people have this issue. I'm trying to create an object with multiple nested relationships but something is keeping this from happening. Here are my models for reference:
class UserProfile(models.Model):
user = models.OneToOneField(User, unique=True, null=True)
tmp_password = models.CharField(max_length=32)
photo = models.ImageField(upload_to='media/', blank=True, null=True)
likes = models.IntegerField(blank=True, null=True)
dislikes = models.IntegerField(blank=True, null=True)
def __unicode__(self):
return unicode(self.user.username)
class Item(models.Model):
"""Item Object Class"""
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=125, blank=True)
price = models.FloatField(default=0, blank=True)
rating = models.IntegerField(default=0, blank=True)
description = models.TextField(max_length=300, blank=True)
photo = models.ImageField(upload_to="media/", blank=True)
barcode = models.CharField(max_length=20, blank=True)
photo_url = models.URLField(max_length=200, blank=True)
item_url = models.URLField(max_length=200, blank=True)
def __unicode__(self):
return unicode(self.name)
class Favorite(models.Model):
user = models.OneToOneField(User, null=True)
items = models.ManyToManyField(Item)
def __unicode__(self):
return unicode(self.user.username)
def admin_names(self):
return '\n'.join([a.name for a in self.items.all()])
And here are my serializers:
class ItemSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Item
fields = ('id', 'name', 'price', 'description', 'rating', 'photo', 'barcode', 'photo_url','item_url' )
class FavoriteSerializer(serializers.ModelSerializer):
class Meta:
model = Favorite
exclude = ('id', 'user')
class UserProfileSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = UserProfile
fields = ('likes', 'dislikes', 'photo', 'tmp_password')
class UserSerializer(serializers.HyperlinkedModelSerializer):
userprofile = UserProfileSerializer()
favorite = FavoriteSerializer()
class Meta:
model = User
fields = (
'id', 'username', 'url',
'email', 'is_staff', 'password',
'userprofile', 'favorite'
)
def create(self, validated_data):
profile_data = validated_data.pop('userprofile')
favorites_data = validated_data.pop('favorite')
user = User.objects.create_user(**validated_data)
user_profile = UserProfile.objects.create(user=user, **profile_data)
favorite = Favorite(user=user)
favorite.save()
print favorite.items
for item in favorites_data:
favorite.items.add(item)
print favorite.items
return user
What I am having trouble with is the create() method on UserSerializer. What's happening is I can't .add() the data from favorites_data to the favorite object. I get an error saying invalid literal for int() with base 10: 'items'. I guess this makes sense, but if I try this instead of using the for loop:
favorite.items.add(**favorites_data)
I just get an error saying add() got an unexpected keyword argument 'items'. Finally, If I try this:
favorite.items.add(favorites_data)
I just get this error: unhashable type: 'OrderedDict'
What am I doing wrong in this approach? Obviously, favorites_data exist, but I'm not inserting it properly. Thanks for any help!
I think favorite.items.add expects you to pass in a single instance of an Item, so you should replace this:
for item in favorites_data:
favorite.items.add(item)
With this:
for key in favorites_data:
for item in favorites_data[key]:
favorite.items.add(item)

Categories

Resources