Django list_select_related gives me this error - python

#store/admin.py
#admin.register(models.Product)
class ProductView(admin.ModelAdmin):
list_display = ['title', 'unit_price', 'inventory_status', 'collection_title',]
list_editable = ['unit_price']
list_per_page = 10
list_select_related = ['collection']
#store/models.py
class Collection(models.Model):
title = models.CharField(max_length=255)
featured_product = models.ForeignKey(
'Product', on_delete=models.SET_NULL, null=True, related_name='+')
class Meta:
ordering = ['title']
'''
def __str__(self) -> str:
return self.title
'''
class Product(models.Model):
title = models.CharField(max_length=255)
slug = models.SlugField()
description = models.TextField()
unit_price = models.DecimalField(max_digits=6, decimal_places=2)
inventory = models.IntegerField()
last_update = models.DateTimeField(auto_now=True)
collection = models.ForeignKey(Collection, on_delete=models.PROTECT)
promotions = models.ManyToManyField(Promotion)
#Error I got:
SystemCheckError
PS - I know I can use 'collection' in list_display directly as it is already a field in my product model, but I want to preload a related field/table using list_select_related and use 'collection_title' in list_display. Please help. Thank You.
ERRORS:
<class 'store.admin.ProductView'>: (admin.E108) The value of 'list_display[3]' refers to 'col
lection_title', which is not a callable, an attribute of 'ProductView', or an attribute or method on 'store.Product'.

I think you're wrong, as far as I know list_select_related is to reduce your query, but your error is something else, here it says "list_display [3]" referred to colection_title, which is not a attribute or callable method of model
Product or ProductView class.
django validate this items(list_display) In the following link, you can see the validate function(_check_list_display):
https://github.com/django/django/blob/950d697b95e66deb3155896e0b619859693bc8c6/django/contrib/admin/checks.py#L732
If you want to access the related field in other models, you can create a function in your ProductView link this:
class ProductView(admin.ModelAdmin):
list_display = ['title', 'unit_price', 'inventory_status', 'collection_title',]
list_editable = ['unit_price']
list_per_page = 10
list_select_related = ['collection']
def collection_title(self, obj):
return obj.collection.title

Related

Object has no a 'get_category_display'

I want to display product detail page using drf but I keep running into one error after another.
urls.py
path('product/<int:id>', views.product_detail_view.as_view(), name='product-detail'),
models.py
class Product(models.Model):
categories = models.ManyToManyField(Category)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="product_owner")
item = models.CharField(max_length=150)
slug = models.SlugField(max_length=255, blank=True, null=True)
brand = models.CharField(max_length=255, default="brand")
image = models.ImageField(upload_to="images/products/")
label = models.CharField(max_length=254, default='', blank=True, null=True)
serializers.py
class product_detail_serializer(serializers.ModelSerializer):
category = serializers.SerializerMethodField()
class Meta:
model = Product
fields = ("id", "categories", "item", "slug", "image")
lookup_field = "id"
def get_category(self, obj):
return obj.get_category_display()
views.py
class product_detail_view(generics.RetrieveAPIView):
serializer_class = product_detail_serializer
lookup_field = "id"
The error I'm getting now is 'Product has no attribute 'get_category_display'
Please how do I fix this error?
You can try defining the id inside the product_detail_serializer class then include it in the url patterns path like this:
serializers.py
class product_detail_serializer(serializers.ModelSerializer):
category = serializers.SerializerMethodField()
id = serializers.IntegerField(read_only=True)
Then include the id in the urlpatherns path
path('product/<int:id>',views.product_detail_view.as_view(),name='product
detail'),
I basically can't explain why this worked. I used the serializer for product instead of creating another serializer for the product detail page.

Filtering issue in DRF

The problem I'm having looks like:
TypeError: init() got an unexpected keyword argument 'name'
"GET /apartmentimages/ HTTP/1.1" 500 136691
I have such a model.py class:
class Apartment(models.Model):
apartment_title = models.CharField(max_length=200)
apartment_description = models.TextField()
apartment_location = models.CharField(max_length=200)
apartment_people_quantity = models.PositiveIntegerField()
apartment_price = models.CharField(max_length=200)
apartment_type = models.CharField(max_length=50, null=True)
def __str__(self):
return self.apartment_title
class ApartmentImage(models.Model):
apartment = models.ForeignKey(Apartment, on_delete=models.CASCADE)
image = models.ImageField(upload_to='images/', null=True, blank=True)
And serializers.py class:
class ApartmentSerializer(serializers.ModelSerializer):
class Meta:
model = Apartment
fields = (
'id',
'url',
'apartment_title',
'apartment_description',
'apartment_location',
'apartment_people_quantity',
'apartment_price',
'apartment_type',
)
class ApartmentImageSerializer(serializers.ModelSerializer):
class Meta:
model = ApartmentImage
fields = ('id', 'url', 'apartment', 'image',)
in views.py:
apartment_id = django_filters.CharFilter(name="apartment__id",
queryset=Apartment.objects.all())
class Meta:
model = ApartmentImage
fields = ('apartment_id',)
class ApartmentImageView(viewsets.ModelViewSet):
queryset = ApartmentImage.objects.all()
serializer_class = ApartmentImageSerializer
filter_backends = (DjangoFilterBackend,)
filter_class = ApartmentImageFilter
You have no name as an attribute in django-filters. Maybe what are you looking for is field_name and neither do you need queryset=Apartment.objects.all(). If you are looking for a field that is field_name then your CharFielter should look like this apartment_id = django_filters.CharFilter(field_name="apartment__id", lookup_expr='iexact') and maybe if you haven't overwritten the id generation it should probably be a NumberFilter() if I am not wrong.

Unable to POST JSON data from multiple select element with Django REST Framework

I would like to be able to send an AJAX POST request to my API endpoint to create a new instance of my Asset model with multiple Category instances referenced in my Asset model, hence the many-to-many field type in my Asset model.
I'm able to successfully POST and create new Asset instances, however my category field won't accept any data at all. The category field remains empty when a new Asset instance is created. I think it has something to do with my CategorySerializer. I'm still learning how to use Django REST Framework so I'd appreciate if I could get some help figuring out how to work with serializers in Django REST Framework.
I've already tried modifying the AssetSerializer create method to handle parsing the JSON and validating the data but that hasn't worked. I've also tried other solutions suggested in other posts I've found on StackOverflow but haven't found anything that works for my situation.
Here's my serializers.py file:
class CategorySerializer(serializers.ModelSerializer):
name = serializers.CharField(required=False, read_only=True)
class Meta:
model = Category
fields = ('id', 'name')
class AssetSerializer(serializers.ModelSerializer):
name = serializers.CharField(allow_null=True)
description = serializers.CharField(allow_null=True)
manufacturer = serializers.CharField(allow_null=True)
uid = serializers.UUIDField(read_only=True, allow_null=True)
borrower = BorrowerSerializer(allow_null=True, read_only=True)
condition = serializers.ChoiceField(choices=Asset.CONDITION_TYPE, default='g', allow_null=True)
owner = serializers.ReadOnlyField(source='owner.username')
return_date = serializers.DateField(allow_null=True)
checked_out = serializers.BooleanField(allow_null=True)
category = CategorySerializer(required=False, many=True)
class Meta:
model = Asset
fields = ('uid',
'name',
'manufacturer',
'model',
'description',
'owner',
'condition',
'category',
'borrower',
'checked_out',
'return_date',
'is_dueback',
)
def update(self, instance, validated_data):
instance.borrower = validated_data.get('borrower', instance.borrower)
instance.return_date = validated_data.get('return_date', instance.return_date)
instance.checked_out = validated_data.get('checked_out', instance.checked_out)
instance.name = validated_data.get('name', instance.name)
instance.manufacturer = validated_data.get('manufacturer', instance.manufacturer)
instance.model = validated_data.get('model', instance.model)
instance.description = validated_data.get('description', instance.description)
instance.condition = validated_data.get('condition', instance.condition)
instance.category = validated_data.get('category', instance.category)
instance.save()
return instance
def create(self, validated_data):
return Asset.objects.create(**validated_data)
Here's my Asset model:
class Asset(models.Model):
"""Model representing an Asset"""
uid = models.UUIDField(primary_key=True, default=uuid.uuid4)
name = models.CharField(max_length=200)
manufacturer = models.CharField(max_length=64)
model = models.CharField(max_length=128)
description = models.TextField()
category = models.ManyToManyField(Category)
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
borrower = models.ForeignKey(Borrower, on_delete=models.CASCADE, null=True, blank=True)
checked_out = models.BooleanField(default=False)
return_date = models.DateField(null=True, blank=True)
CONDITION_TYPE = (
('e', 'Excellent'),
('g', 'Good'),
('f', 'Fair'),
('p', 'Poor'),
)
condition = models.CharField(
max_length=1,
choices=CONDITION_TYPE,
blank=True,
help_text='Asset condition')
class Meta:
ordering = ['return_date']
#property
def is_dueback(self):
if self.return_date and date.today() > self.return_date:
return True
return False
def display_category(self):
"""Create a string for the Category. This is required to display category in Admin."""
return ', '.join(category.name for category in self.category.all())
display_category.short_description = 'Category'
def __str__(self):
return f'{self.uid} - {self.name}'
def get_absolute_url(self):
return reverse('asset-detail', args=[str(self.uid)])
Here's my Category model:
class Category(models.Model):
"""Model representing an Asset category"""
name = models.CharField(max_length=128)
def __str__(self):
return self.name
I'd appreciate any help you could provide. Thank you in advance.
i'm almost new in DRF but i try to help. why you writing all the field in serializer when you using ModelsSerializer? not need to telling ModelSerializer what type of field should be because you are pointing to model in class Meta and DRF know about fields and type and etc . second about allow_null=True in serializer, when Model haven't null=True you can't except DRF can create a not null-able field for instance with null=True so if you wnt a field can be null just add null=True in Model class . for your problem about ManytoMantry field try to use Primary key relation for ManyToMany fields in your serializers then pass id of Category instances in list:
class AssetSerializer(serializers.ModelSerializer):
borrower = BorrowerSerializer(allow_null=True, read_only=True)
category = serializers.PrimaryKeyRelatedField(many=True, queryset=Category.objects.all())
class Meta:
model = Asset
fields = ('uid',
'name',
'manufacturer',
'model',
'description',
'owner',
'condition',
'category',
'borrower',
'checked_out',
'return_date',
'is_dueback',
)
read_only_fields = ( 'uid' , ) # this fields will be read_only
depending on how you using this serializer in your view for save and update have difference way. if your view is generics class so will do create and update itself by POST and PUT method .and for other class view that isn't belong to generics DRF view you can using serializer.save() to create a new instance.wish help you.
pass data something like:
{
"name" : "foo",
"manufacture" : "foo",
.
.
.
"category" : [1,2,3,24,65]
}

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)

django rest serialize level 2 field

Hi I need to add a field in a serializer of a 2 level reference item.
I have the following model:
model.py:
class Company(models.Model):
companyName = models.CharField(max_length=50, blank=True)
class Poll(models.Model):
questionString = models.CharField(max_length=500, blank=True)
companyId = models.ForeignKey(Company, null=True, db_column='companyId', blank=True)
class PossibleAnswer(models.Model):
answerString = models.CharField(max_length=100, blank=True)
pollId = models.ForeignKey(Poll, null=True, db_column='pollId', blank=True,related_name='answers')
token = models.CharField(max_length=10, blank=True)
serializers.py:
class PossibleAnswerSerializer(serializers.ModelSerializer):
#companyId = serializers.RelatedField()
class Meta:
model = PossibleAnswer
fields = ('answerString', 'token', 'pollId', 'companyId')
I want to make a Serializer for the PossibleAnswer object that has a field named company. How to make a this reference? Something similar to: pollId__companyId in a django query set filter.
Another solution...
class PossibleAnswerSerializer(serializers.ModelSerializer):
companyId = serializers.SerializerMethodField()
def get_companyId(self, obj):
return obj.pollId.companyId
class Meta:
model = PossibleAnswer
fields = ('answerString', 'token', 'pollId', 'companyId',)
I the field is read-only you can easily achieve this with a serializers.Field, which accept dotted paths to the source.
Your Serializer would be:
class PossibleAnswerSerializer(serializers.ModelSerializer):
companyId = serializers.Field(source='pollId.companyId')
class Meta:
model = PossibleAnswer
fields = ('answerString', 'token', 'pollId', 'companyId')
I too agree with Erik, that naming model attributes with Id is a bad idea even though the DB representation is only the ID.

Categories

Resources