Django category view - django

I am new to django and maybe this is a stupid question but i got stuck with this for a while now.. so i have a few categories of meds, like AINS, antidepressants and each of this category has its own meds, and i am trying to show my users all the meds of a specific category: so if a users types in www.namesite.com/meds/AINS the it will show only the meds for that specific category .. AINS.I think that i should get the absolute url of every category and filter all the meds in that specific category?
Model:
class Category(models.Model):
category = models.CharField(max_length=30)
slug = models.SlugField()
def __str__(self):
return self.category
def get_absolute_url(self):
return reverse("meds", kwargs={'slug':self.category})
class Meta:
verbose_name_plural = 'Categorii'
class Medicament(models.Model):
title = models.CharField(max_length=50)
description = models.TextField(max_length=200)
category = models.ForeignKey(Category, on_delete='CASCADE')
price = models.DecimalField(decimal_places=2, max_digits=4)
prospect = models.TextField(default='Prospect')
company = models.TextField(default = 'company')
nr_unitati = models.IntegerField()
quantity = models.CharField(max_length=5, default='mg')
date_added = models.DateTimeField(auto_now_add=True)
rating = models.IntegerField(null=True, blank=True)
amount = models.IntegerField(default=0)
def __str__(self):
return self.title + ' ' + self.company + ' ' + str(self.nr_unitati) + ' ' + self.quantity
class Meta:
verbose_name_plural = 'Medicamente'
Views:
class MedCategoriesView(DetailView):
model = Category
template_name = 'products/AINS.html'
context_object_name = 'all_categories'
def get_context_data(self, **kwargs):
context = super(AINS_ListView, self).get_context_data(**kwargs)
context['meds'] = Medicament.objects.filter(category=self.object)
return context
Urls:
path('medicaments/<slug>/', MedCategoriesView.as_view(), name='meds'),

Using function based views.
def medicament(request, slug):
try:
medicaments = Medicament.objects.filter(category__slug=slug)
except Medicament.DoesNotExist:
raise Http404("Medicament does not exist")
return render(request, 'products/AINS.html', {'medicaments': medicaments})

Related

Convert function base view to class based view (DRF)

can someone help me convert this function component to class based view (rest framework concrete view)?
I tried converting but landed with errors where serializer is false.
Product image is required in the query.
class Product(models.Model):
title = models.CharField(max_length=200, unique=True)
slug = models.SlugField(max_length=200, unique=True)
description = models.TextField()
price = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
stock = models.IntegerField()
is_available = models.BooleanField(default=True)
brand = models.ForeignKey(Brand, on_delete=models.CASCADE)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
created_date = models.DateTimeField(auto_now_add=True)
updated_date = models.DateTimeField(auto_now=True)
class ProductImage(models.Model):
image = models.ImageField(upload_to=get_upload_path)
product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name="product_images")
def store(request, category_slug):
cat = None
products = None
if category_slug != None:
cat = get_object_or_404(Category, slug=category_slug)
products = Product.objects.filter(category=cat)
product_count = products.count()
else:
products = Product.objects.filter(is_available=True)
products.count()
context = {
'products': products,
'product_count': product_count
}
return render(request, 'store.html', context)
what i tried with rest framework.
Serializers:
class ProductImageSerializer(serializers.ModelSerializer):
class Meta: model = ProductImage
fields = ('image',)
class ProductSerializer(serializers.ModelSerializer):
product_images = ProductImageSerializer(many=True, read_only=True)
class Meta:
model = Product
fields = "__all__"
def create(self, validated_data):
profile_data = validated_data.pop('product_images')
product = Product.objects.create(**validated_data)
return product
View:
I tried with concrete views, product is filtered by category.
class Store(generics.ListCreateAPIView):
queryset = Product.objects.filter(is_available=True)
serializer_class = ProductSerializer
lookup_field = 'category_slug'
lookup_url_kwarg = 'category_slug'
def list(self, request, *args, **kwargs):
queryset = self.get_queryset()
cat_slug = self.kwargs.get('category_slug')
products = None
if cat_slug is not None:
category = get_object_or_404(Category, slug=cat_slug)
products = queryset.filter(category=category, is_available=True)
else:
products = queryset.filter(is_available=True)
if products.count() == 1:
serializer = ProductSerializer(data=products.first())
elif products.count() > 1:
serializer = ProductSerializer(data=products, many=True)
if not serializer.is_valid():
print(serializer.errors)
data = serializer.data
return Response(data, status=status.HTTP_200_OK)
any help is appreciated.

Moving logic from Django views to models

This is my model:
class Car(models.Model):
make = models.CharField(max_length=30)
model = models.CharField(max_length=30)
rating = models.PositiveIntegerField(validators=[MinValueValidator(1), MaxValueValidator(5)], default=0, blank=True)
avg_rating = models.FloatField(default=0, blank=True)
rates_number = models.IntegerField(default=0, blank=True)
def __str__(self):
return self.make + ' ' + self.model
What's the best way to move the logic from the following perform_create function (in views.py) to my models?
class CarRate(generics.CreateAPIView):
serializer_class = CarRatingSerializer
queryset = Car.objects.all()
def perform_create(self, serializer):
pk = serializer.validated_data['car_id']
rating = serializer.validated_data['rating']
queryset = Car.objects.all()
car_queryset = get_object_or_404(queryset, pk=pk)
if car_queryset.rates_number == 0:
car_queryset.avg_rating = rating
else:
car_queryset.avg_rating = (car_queryset.avg_rating + rating)/2
car_queryset.avg_rating = round(car_queryset.avg_rating, 1)
car_queryset.rates_number = car_queryset.rates_number + 1
car_queryset.save()
It would be much better to create two models. Think about how you are counting average rating. This would be some better idea for now:
class Car(models.Model):
make = models.CharField(max_length=30)
model = models.CharField(max_length=30)
def rates_number(self):
return self.rates.all().count()
def avg_rating(self):
# count average_rating from relation to Rate objects and return it
return average_rating
class CarRate(models.Model):
value = models.PositiveIntegerField(validators=[MinValueValidator(1), MaxValueValidator(5)], default=0, blank=True)
car = models.ForeignKey(Car, on_delete=models.CASCADE, related_name='rates')

Passing a placeholder text using django-filter and different views

I have a model:
class Movie (models.Model):
category = models.CharField(max_length=50, verbose_name='Kategoria filmu', default= 'unassigned', null=False, choices=category_choices)
source = models.CharField(max_length=50, verbose_name='Źródło filmu', default= 'unassigned', null=False, choices=source_choices)
promotion = models.BooleanField(default=False, verbose_name='PROMOCJA FILMU')
author = models.CharField(max_length=50, verbose_name='Nazwa influencera')
title = models.CharField(max_length=50, verbose_name='Nazwa filmu')
content = models.TextField(max_length=10000, verbose_name='HTML EMBEDED do filmu')
date_posted = models.DateTimeField(default=timezone.now)
youtube_url = models.URLField(blank=True, max_length=300)
tiktok_url = models.URLField(blank=True, max_length=300)
insta_url = models.URLField(blank=True, max_length=300)
I am passing it to the view with djnago-filter with different category choice:
views.py:
#HotTop View
class HotTopView (FilterView):
model = Movie
template_name = 'pages/hot_top.html'
filterset_class = MovieFilter
paginate_by = 6
def get_queryset(self):
category_qs = self.model.objects.filter(category="HOT-TOP")
return category_qs.order_by('-date_posted')
#Odkrycia View
class OdkryciaView (FilterView):
model = Movie
template_name = 'pages/odkrycia.html'
filterset_class = MovieFilter
paginate_by = 6
def get_queryset(self):
category_qs = self.model.objects.filter(category="ODKRYCIA")
return category_qs.order_by('-date_posted')
and my filters.py:
class MovieFilter(django_filters.FilterSet):
author = django_filters.CharFilter(label='', lookup_expr='contains', widget=TextInput(attrs={'placeholder': 'Search'}))
class Meta:
model = Movie
fields = ['author']
The question is how can i change placeholder of my serach form depending on the view (HotTop or Odkrycia). I want it to be - when i am in HotTop View -> Search in Hot Top and when i am in Odkrycia - > Search in Odkrycia
I think you could pass an argument
class MovieFilter(django_filters.FilterSet):
author = django_filters.CharFilter(label='', lookup_expr='contains', widget=TextInput(attrs={'placeholder': 'Search'}))
class Meta:
model = Movie
fields = ['author']
def __init__(self, *args, **kwargs):
placeholder = kwargs.pop('placeholder', None)
super().__init__(*args, **kwargs)
if placeholder :
self.fields['author'].widget = TextInput(attrs={'placeholder': f'Search in {placeholder}'})
and then in the views you can use get_filterset_kwargs method to pass the view name.
#HotTop View
class HotTopView(FilterView):
...
def get_filterset_kwargs(self):
kwargs = super(HotTopView, self).get_filterset_kwargs()
kwargs['placeholder'] = "Hot Top"
return kwargs
...
the other view:
#Odkrycia View
class OdkryciaView(FilterView):
...
def get_filterset_kwargs(self):
kwargs = super(OdkryciaView, self).get_filterset_kwargs()
kwargs['placeholder'] = "Odkrycia"
return kwargs
...
I hope that answers your question.

how to return several FileField from Queryset in Django?

I have a models with FileField for videos.
When i upload only one video i can return it with this code in the view.py:
def cours(request, id, slug):
c = Cours.objects.get(id=id, slug=slug)
p = Plan_simple.objects.get(cours=c)
return render(request, 'upload/cours.html', locals())
But when i upload two or more videos whith formset, and i change get fuction by filter it doesn't work:
def cours(request, id, slug):
c = Cours.objects.get(id=id, slug=slug)
p = Plan_simple.objects.filter(cours=c)
return render(request, 'upload/cours.html', locals())
the models.py
class Cours(models.Model):
titre = models.CharField(max_length=100)
slug = models.SlugField(max_length=100)
auteur = models.CharField(max_length=42)
comment = models.TextField(null=True)
link = models.CharField(max_length=100)
date = models.DateTimeField(default=timezone.now, verbose_name="Date de parution")
categorie = models.ForeignKey('Categorie', on_delete=models.CASCADE)
def save(self, *args, **kwargs):
self.slug = slugify(self.titre)
super(Cours, self).save(*args, **kwargs)
class Meta:
verbose_name = "cours"
db_table = "cours"
ordering = ['date']
class Plan_simple(models.Model):
partie = models.CharField(blank=True, max_length=100)
date = models.DateTimeField(default=timezone.now, verbose_name="Date de parution")
vid = models.FileField(upload_to='file/', blank=True, null = True)
cours = models.ForeignKey(Cours, related_name = "plan_simple", on_delete=models.CASCADE)
def __str__(self):
return self.partie
class Meta:
db_table = "plan_simple"
Can you help me?
Thanks
The issue is with this line. It does not request anything from the database. It only specifies a filter.
p = Plan_simple.objects.filter(cours=c)
You should change it to this...
p = Plan_simple.objects.filter(cours=c).all()

Three-way query in django

I have the following model:
class Video(models.Model):
name = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
filename = models.CharField(max_length=200)
duration = models.IntegerField(default=0)
votes_up = models.IntegerField(default=0)
votes_down = models.IntegerField(default=0)
width = models.IntegerField(default=0)
height = models.IntegerField(default=0)
def __unicode__(self):
return self.name
class Category(models.Model):
name = models.CharField(max_length=200)
def __unicode__(self):
return self.name
class VideoCategory(models.Model):
video = models.ForeignKey('Video')
category = models.ForeignKey('Category')
def __unicode__(self):
return u"{} >> {}".format(self.video.name, self.category.name)
And this view:
def video_list(request):
if 'category' in request.POST:
#####
else:
video_list = Video.objects.order_by('pub_date')
context = {}
context['videos'] = []
for video in video_list:
video_data = {'name': video.name,
'file': video.filename,
'duration': video.duration,
'resolution': [video.width, video.height],
}
context['videos'].append(video_data)
return HttpResponse(json.dumps(context), content_type="application/json")
Everything works as expected.
Now I want to filter videos through categories. How can I construct a query like:
"Give me all the 'Videos', which have an entry in 'VideoCategory' with the 'Category'.name like 'xxxxxxx'"
You can do:
videos = Video.objects.filter(videocategory__category__name='xxxx')
(notice the lower case model name to access the reverse relationship)
You can read upon how to query lookups that span relationships here