Object has no a 'get_category_display' - python

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.

Related

Django list_select_related gives me this error

#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

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

Django get objects from url slug not working

I'm trying to make it so that I can show only briefs with the slug name as the category, however it does not work.
At the minute I can only use it by showing all briefs using .objects.all() however this is not suitable for my desired use case.
Do i need a slug field in the brief section too?
Models.py
class Category(models.Model):
name = models.CharField(max_length=200, unique=True)
slug = models.SlugField(max_length=50, unique=True)
class Meta:
verbose_name_plural = 'categories'
verbose_name = 'category'
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('browse')
class Brief(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
brandname = models.CharField(max_length=28)
description = models.CharField(max_length=200)
date = models.DateTimeField(auto_now=True, blank=True)
category = models.ForeignKey(Category, on_delete=CASCADE)
def get_absolute_url(self):
return reverse('homepage')
Urls.py
path('browse/categories/<slug:catslug>/', views.postsinthecategory, name = 'catslug'
views.py
def postsinthecategory(request, catslug):
categories = Category.objects.all()
brief = Brief.objects.all()
if catslug:
category = get_object_or_404(Category, slug = catslug)
brief = Brief.objects.get(category=catslug)
template = 'users/categoryposts.html'
context = {'categories': categories, 'brief': brief, 'category': category}
return render(request, template,context)
You can use __slug to filter on the related model's slug field. Use filter instead of get, because you want a queryset that can contain more than brief. I would rename brief to briefs in your view to make that clearer.
briefs = Brief.objects.filter(category__slug=catslug)
Or, since you fetched the category on the previous line, you could do:
category = get_object_or_404(Category, slug = catslug)
briefs = Brief.objects.filter(category=category)

Django generating multiple urls for the same subcategory

In my app, there's a list of categories and subcategories with a ForeignKey relationship. Say, there're:
Subcategory1 related to Category1
Subcategory2 related to Category2
I expect to get the following subcategory urls:
http://127.0.0.1:8000/cat1/subcat1
http://127.0.0.1:8000/cat2/subcat2
These urls work fine. However, django also generates these urls that I don't need:
http://127.0.0.1:8000/cat1/subcat2
http://127.0.0.1:8000/cat2/subcat1
Why do they appear in my app? How do I get rid of them? Thanks in advance!
models.py:
class Category(models.Model):
categoryslug = models.SlugField(max_length=200, default="",unique=True)
def get_absolute_url(self):
return reverse("showrooms_by_category",kwargs={'categoryslug': str(self.categoryslug)})
class Subcategory(models.Model):
subcategoryslug = models.SlugField(max_length=200, default="",unique=True)
category = models.ForeignKey('Category', related_name='subcategories',
null=True, blank=True, on_delete = models.CASCADE)
def get_absolute_url(self):
return reverse("showrooms_by_subcategory",
kwargs={'categoryslug': str(self.category.categoryslug), 'subcategoryslug': str(self.subcategoryslug)})
views.py:
class ShowroomCategoryView(DetailView):
model = Category
context_object_name = 'showrooms_by_category'
template_name = "website/category.html"
slug_field = 'categoryslug'
slug_url_kwarg = 'categoryslug'
class ShowroomSubcategoryView(DetailView):
model = Subcategory
context_object_name = 'showrooms_by_subcategory'
template_name = "website/subcategory.html"
slug_field = 'subcategoryslug'
slug_url_kwarg = 'subcategoryslug'
urls.py:
urlpatterns = [
path('<slug:categoryslug>/<slug:subcategoryslug>/', views.ShowroomSubcategoryView.as_view(), name='showrooms_by_subcategory'),
path('<slug:categoryslug>/', views.ShowroomCategoryView.as_view(), name='showrooms_by_category'),
]
I think the reason for this is foreign_key. So, I think as you can use one to one field to get the target, like:
subcategoryslug = models.SlugField(max_length=200, default="",unique=True)
category = models.OneToOneField('Category', related_name='subcategories',null=True, blank=True, on_delete = models.CASCADE)
*Note:- Please understand the logic too behind it. For that, do research more.

django restframework : url filter with two model field

I want to design a url like :
url(r'^theaters/(?P<area>.+)/(?P<title>.+)/$', TheaterAreaList.as_view(), name='theater-area'),
and then I can go to the link like:
http://127.0.0.1:8000/theaters/north/moviename
But the title and area are in different models with manytomany relationship :
models.py
class Movie(models.Model):
link = models.URLField()
title = models.CharField(max_length=255, null=True)
class MovieTheater(models.Model):
movietheater = models.ManyToManyField(Movie,null=True,blank=True,through="MovieShowtime")
movie_theater = models.CharField(max_length=255, null=True)
city = models.CharField(max_length=255, null=True) #east west north south
class MovieShowtime(models.Model):
theater = models.ForeignKey( MovieTheater, null=True,blank=True,related_name = 'theater' )
movie = models.ForeignKey( Movie, null=True,blank=True,related_name = 'movie' )
time = models.TextField(null=True,blank=True)
my views.py has error QuerySet' object has no attribute 'movietheater_set'
views.py:
class TheaterAreaList(generics.ListAPIView):
serializer_class = TheaterSerializer
def get_queryset(self):
area = self.kwargs['city']
title = self.kwargs['title']
return MovieTheater.objects.filter(city=area).movietheater_set.filter(title=title)
Please teach me how to query with two models ,Thank you very much.
The _set would work only for objects, and not filtered querysets.
Try this:
MovieTheater.objects.filter(city=area, movietheater__movie__title=title)
Here is the relevant documentation

Categories

Resources