There is a product filter in which you need to exclude other attributes when choosing a brand.
For example, we have color, size, weight, brand.
When choosing a brand, we only have certain colors, sizes and weights. How to disable their checkboxes when they are not assigned to the selected brand.
My code:
models.py
class CategoryFeature(models.Model):
category = models.ForeignKey("product.Category", on_delete=models.CASCADE)
feature_name = models.CharField(max_length=50)
feature_filter_name = models.CharField( max_length=50)
unit = models.CharField(max_length=50, null=True, blank=True)
class Meta:
unique_together = ('category', 'feature_name', 'feature_filter_name')
class FeatureValidator(models.Model):
category = models.ForeignKey("product.Category", on_delete=models.CASCADE)
feature_key = models.ForeignKey(CategoryFeature, on_delete=models.CASCADE)
valid_feature_value = models.CharField(max_length=100)
class ProductFeatures(models.Model):
product = models.ForeignKey("product.Product", on_delete=models.CASCADE)
feature = models.ForeignKey(CategoryFeature, on_delete=models.CASCADE)
value = models.CharField(max_length=255)
appstags.py
#register.filter
def product_spec(category):
product_features = ProductFeatures.objects.filter(product__category=category)
feature_and_values = defaultdict(list)
for product_feature in product_features:
if product_feature.value not in feature_and_values[(product_feature.feature.feature_name, product_feature.feature.feature_filter_name)]:
feature_and_values[
(product_feature.feature.feature_name, product_feature.feature.feature_filter_name)
].append(product_feature.value)
print(feature_and_values)
search_filter_body = """<div class="col-md-12"><center><strong>ФИЛЬТР</strong></center> <hr>{}</div>"""
mid_res = ""
for (feature_name, feature_filter_name), feature_values in feature_and_values.items():
feature_name_html = f"""<p><b>{feature_name}</b></p>"""
feature_values_res = ""
for f_v in feature_values:
mid_feature_values_res = \
"<input type='checkbox' class='check' id='check-option-{feature_name}' name='{f_f_name}' value='{feature_name}' onchange='this.form.submit();'> {feature_name}</br>".format(
feature_name=f_v, f_f_name=feature_filter_name
)
feature_values_res += mid_feature_values_res
feature_name_html += feature_values_res
mid_res += feature_name_html + '<hr>'
res = search_filter_body.format(mid_res)
return mark_safe(res)
views.py
class CategoryDetailView(ListView):
model = Product
context_object_name = 'category_products'
template_name = 'category_products.html'
def querystring_url(self):
data = self.request.GET.copy()
data.pop(self.page_kwarg, None)
return data.urlencode()
def get_queryset(self):
qs = super().get_queryset().filter(
category__slug=self.kwargs['slug']
)
qd = self.request.GET.copy()
qd.pop(self.page_kwarg, None)
if 'search' in self.request.GET:
qs = qs.filter(title__icontains=self.request.GET['search'])
elif qd:
url_kwargs = {}
for item in self.request.GET:
if len(self.request.GET.getlist(item)) > 1:
url_kwargs[item] = self.request.GET.getlist(item)
else:
url_kwargs[item] = self.request.GET.get(item)
q_condition_queries = Q()
for key, value in url_kwargs.items():
if isinstance(value, list):
q_condition_queries.add(Q(**{'value__in': value}), Q.OR)
else:
q_condition_queries.add(Q(**{'value': value}), Q.OR)
pf = ProductFeatures.objects.filter(
q_condition_queries
).prefetch_related('product', 'feature').values('product_id')
qs = qs.filter(id__in=[pf_['product_id'] for pf_ in pf])
return qs
Related
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.
Hi I have problems with some filters in django.
I have my own view where I can choose the day of the week which is a select choice field
once chosen it is saved in the db.
I would like to filter those already present so as not to repeat them if I had to choose another day.
Can anyone help me out please?
models.py
class Piano(models.Model):
nome_piano = models.CharField(max_length=100)
data_inizio = models.DateField()
data_fine = models.DateField()
utente_piano = models.ForeignKey(
User,
on_delete = models.CASCADE,
related_name = 'utente_piano'
)
def __str__(self):
return self.nome_piano
class Meta:
verbose_name = "Piano alimentare"
verbose_name_plural = "Piani alimentari"
class PianoSingleDay(models.Model):
giorni_settimana_scelta = [
("1","Lunedì"),
("2","Martedì"),
("3","Mercoledì"),
("4","Giovedì"),
("5","Venerdì"),
("6","Sabato"),
("7","Domenica")
]
giorni_settimana = models.CharField(
choices = giorni_settimana_scelta,
max_length = 300
)
single_piano = models.ForeignKey(
Piano,
on_delete = models.CASCADE,
related_name = 'single_piano'
)
def __str__(self):
return self.giorni_settimana
class Meta:
verbose_name = "Piano singolo"
verbose_name_plural = "Piani singoli"
views.py
#login_required
def PianoSingleView(request, id):
piano = get_object_or_404(models.Piano, id = id, utente_piano = request.user)
if request.method == 'POST':
giorno_form = PianoSingleDayForm(request.POST, prefix = 'giorno')
if giorno_form.is_valid():
day_piano = giorno_form.save(commit = False)
day_piano.single_piano = piano
day_piano.save()
return redirect('gestione-piano', id = piano.id)
else:
giorno_form = PianoSingleDayForm(prefix = 'giorno')
context = {'piano': piano, 'giorno_form': giorno_form}
return render(request, 'crud/create/gestione_piano_single.html', context)
forms.py
class PianoSingleDayForm(forms.ModelForm):
class Meta:
model = models.PianoSingleDay
exclude = ['single_piano']
1
2
You can let the PianoSingleDayForm exclude the days that have already been selected for that Piano with:
class PianoSingleDayForm(forms.ModelForm):
def __init__(self, *args, piano=None, **kwargs):
super().__init__(*args, **kwargs)
if piano is not None:
days = set(PianoDaySingle.objects.filter(
single_piano=piano
).values_list('giorni_settimana', flat=True))
self.fields['giorni_settimana'].choices = [
(k, v)
for k, v in self.fields['giorni_settimana'].choices
if k not in days
]
class Meta:
model = models.PianoSingleDay
exclude = ['single_piano']
We can then use this in the view by passing the Piano object to the form both in the GET and POST codepath:
#login_required
def PianoSingleView(request, id):
piano = get_object_or_404(models.Piano, id=id, utente_piano=request.user)
if request.method == 'POST':
giorno_form = PianoSingleDayForm(request.POST, piano=piano, prefix='giorno')
if giorno_form.is_valid():
giorno_form.instance.single_piano = piano
giorno_form.save()
return redirect('gestione-piano', id=piano.id)
else:
giorno_form = PianoSingleDayForm(piano=piano, prefix='giorno')
context = {'piano': piano, 'giorno_form': giorno_form}
return render(request, 'crud/create/gestione_piano_single.html', context)
My model is like this:
class Hospital(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='author')
hospital_name = models.CharField(max_length=1000)
hospital_ategory = models.CharField(max_length=1000, choices=ETABLISSEMENTS)
imagePopup = models.ImageField(upload_to='default/', default='default/musta.jpg')
wilaya = models.CharField(max_length=200, choices=WILAYA)
active = models.BooleanField(default=True)
location = PointField(srid=4326)
#property
def lat_lng(self):
return list(getattr(self.location, 'coords', []) [::-1])
def __str__(self):
return self.hospital_name
class Hospitalservice(models.Model):
post = models.ForeignKey(Hospital, on_delete=models.CASCADE, related_name='services')
name_service = models.CharField(max_length=10000, null=True, blank=True)
responsable_service = models.CharField(max_length=10000, null=True, blank=True)
service_date = models.DateTimeField(default=timezone.now)
service_update = models.DateTimeField(auto_now=True)
active = models.BooleanField(default=True)
def __str__(self):
return "{} à l'hopital {}".format(self.name_service, self.post.hospital_name)
class Meta:
ordering = ('-service_date', )
class Bedservice(models.Model):
post_bed = models.ForeignKey(Hospitalservice, on_delete=models.CASCADE, related_name='bed')
bed_number_total = models.IntegerField(null=True, blank=True)
bed_number_used = models.IntegerField(null=True, blank=True)
active = models.BooleanField(default=True)
def __str__(self):
return self.post_bed.name_service
`
views.py looks like this:
class HospitalTemplateView(TemplateView):
template_name = 'health/hospital_map.html'
queryset = Hospital.objects.all()
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["form"] = HospitalForm()
...
...
...
return context
def detail_imp_map(request, id):
post = get_object_or_404(Hospital, id=id)
services = post.services.filter(active=True)
post_bed = get_object_or_404(Hospitalservice, pk=id)
bed_service = post_bed.bed.filter(active=True)
columns = ['bed_number_total']
num = reduce(add, (F(column) for column in columns ))
Total_sum= Bedservice.objects.aggregate(total=Sum(num))
if request.method == "POST":
service_form = HospitalServiceForm(request.POST, request.FILES)
if service_form.is_valid():
new_point = service_form.save(commit=False)
new_point.post = post
new_point.save()
return redirect('hospital_map')
else:
service_form = HospitalServiceForm()
context={
'post': post,
'post_bed': post_bed,
'Total_sum': Total_sum,
'services':services,
'service_form':service_form,
}
return render(request, 'health/detail_imp_from_map.html', context)
def detail_hosp_map(request, id):
result = Bedservice.objects.all().annotate(difference=F('bed_number_total') -
F('bed_number_used'))
post_bed = get_object_or_404(Hospitalservice, id=id)
bed_service = post_bed.bed.filter(active=True)
post_medecin = get_object_or_404(Hospitalservice, id=id)
medecin_service = post_medecin.medecin.filter(active=True)
if request.method == "POST":
service_bed_form = BedserviceForm(request.POST, request.FILES)
medecin_service_form = MedecinForm(request.POST, request.FILES)
if service_bed_form.is_valid():
new_point_service_bed = service_bed_form.save(commit=False)
new_point_service_bed.post_bed = post_bed
new_point_service_bed.save()
return redirect('hospital_map')
if medecin_service_form.is_valid():
new_point_service_medecin = medecin_service_form.save(commit=False)
new_point_service_medecin.post_medecin = post_medecin
new_point_service_medecin.save()
return redirect('hospital_map')
else:
service_bed_form = BedserviceForm()
medecin_service_form = MedecinForm()
context={
'result':result,
'bed_service': bed_service,
'medecin_service': medecin_service,
'post_bed': post_bed,
'post_medecin': post_medecin,
'service_bed_form': service_bed_form,
'medecin_service_form': medecin_service_form,
}
return render(request, 'health/detail_service.html', context)
urls.py :
urlpatterns = [
path('admin/', admin.site.urls),
path(r'hospital_map/', HospitalTemplateView.as_view(), name='hospital_map'),
path(r'hospital_map/<int:id>/', detail_imp_map, name='detail'),
path(r'detail_service/<int:id>/', detail_hosp_map, name='detail_service'),
url('^health/', include('health.urls', namespace='health')),
path('add_impact/', addImpactOnMap, name='add_impact'),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
By using
columns = ['bed_number_total']
num = reduce (add, (F (column) for column in columns))
Total_sum = Bedservice.objects.aggregate (total = Sum (num))
I get bed_number_total in all departments of all hospitals. So what I want here. How to display the sum of bed_number_total and the sum of bed_number_used for all departments in each hospital (each hospital has its own id). So if anyone can provide any advice on this it would be greatly appreciated.
Assuming you don't want to change your models (you could include the counts in the model).
Without getting into complicated aggregates. In the case you want to count it per hospital you can either loop throught the objects and count it:
hospitals_res = Hospital.objects.all()
result = []
for hospital_find in hospitals_res:
hospitalservices = Hospitalservice.objects.filter(post = hospital_find)
for service in hospitalservices:
bed_services = Bedservice.objects.filter(post_bed = service)
used = 0
total = 0
for bed_serv in bed_services:
used = used + bed_serv.bed_number_used
total = total + bed_serv.bed_number_total
result.append({'hospital_id': hospital_find.id, 'used_beds':used, 'total_beds':total})
Or just use a raw query: (always be careful to escape any parameters passed)
query = """
SELECT
hospital.id as id,
SUM(bedservice.bed_number_total) as total,
SUM(bedservice.bed_number_used) as used
FROM
backend_admin_hospital AS hospital
LEFT JOIN backend_admin_hospitalservice AS hospitalservice ON post_id = hospital.id
LEFT JOIN backend_admin_bedservice AS bedservice ON post_bed_id = hospitalservice.id
GROUP BY hospital.id
"""
result = Hospital.objects.raw(query)
I use ModelChoiceField with initial value just for display (readonly field).
But value displayed is model id and I want to display customized value that will be a concatenation of 3 fields. I've override ____str____ method but it is not applyed.
I try to make customize ModelChoiceFiedl to define label_from_instance that seems to be the way to do what I want but it is not applyed...
models.py
class Utilisateur(SafeDeleteModel):
_safedelete_policy = SOFT_DELETE_CASCADE
uti_ide = models.AutoField(primary_key = True)
# pro_ide = models.ForeignKey(Projet, on_delete = models.CASCADE) # related project
projets = models.ManyToManyField(Projet, through='UtilisateurProjet')
uti_nom = models.CharField("Nom", max_length=20)
uti_pre = models.CharField("Prénom", max_length=20)
uti_mai = models.CharField("Email", max_length=40)
uti_sit = models.CharField("Equipe", max_length=20, null=True, blank=True)
uti_pro = models.CharField("Fonction/profil", max_length=200, null=True, blank=True)
uti_log = models.CharField("Log utilisateur", max_length=20, null=True, blank=True)
uti_dat = models.DateTimeField("Date log",auto_now_add=True, null=True, blank=True)
log = HistoricalRecords()
#classmethod
def options_list(cls,pro_ide):
# projet = Projet.objects.get(pro_ide=pro_ide)
# utilisateurs = Utilisateur.objects.filter(pro_ide=projet.pro_ide)
utilisateurs = Utilisateur.objects.filter(projets__pro_ide=pro_ide)
the_opts_list = [(utilisateur.uti_ide, utilisateur.uti_nom+', '+utilisateur.uti_pre) for utilisateur in utilisateurs]
the_opts_list.insert(0, (None, ''))
return the_opts_list
class Meta:
db_table = 'tbl_uti'
verbose_name_plural = 'Utilisateurs'
ordering = ['uti_ide']
def __str__(self):
return f"{self.uti_nom}, {self.uti_pre} ({self.uti_mai})"
forms.py
class UtilisateurModelChoiceField(ModelChoiceField):
def label_from_instance(self, obj):
print('label')
return obj.uti_nom+', '+obj.uti_pre+' ('+obj.uti_mai+')'
class UtilisateurProjetUpdateForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop("request")
super(UtilisateurProjetUpdateForm, self).__init__(*args, **kwargs)
# print('kwargs',self.request)
# print('projet',self.request['projet'])
# print('utilisateur',self.request['utilisateur'])
PROJETS = Projet.objects.all()
UTILISATEURS = Utilisateur.objects.all()
self.fields["pro_ide"] = forms.ModelChoiceField(queryset = PROJETS, label = "Nom projet", widget = forms.HiddenInput(), initial = Projet.objects.get(pro_ide=self.request['projet']))
self.fields["uti_ide"] = UtilisateurModelChoiceField(queryset = UTILISATEURS, label = "Nom, prénom de l'utilisateur", widget = forms.TextInput(attrs={'readonly':'readonly'}), initial = Utilisateur.objects.get(uti_ide=self.request['utilisateur']),) #,to_field_name="uti_nom"
class Meta:
model = UtilisateurProjet
fields = ('pro_ide','uti_ide',)
in forms.py under that last class Meta: you need to add:
field_classes = {
'pro_ide': UtilisateurModelChoiceField,
'uti_ide': UtilisateurModelChoiceField,
}
I am trying to add object to m2m with add method but neither its showing error nor adding item, I can't understand why
Here is my view :
class UpdateCartView(generic.UpdateView):
model = Cart
fields = ['products']
template_name = 'update_cart.html'
success_url = reverse_lazy('carts:home')
def form_valid(self,form):
product = ProductCreateModel.objects.get(pk = self.request.POST.get('product'))
size = Size.objects.get(pk = self.request.POST.get('size'))
colour = Colour.objects.get(pk = self.request.POST.get('colour'))
products = Products.objects.create(product = product,
size = size,
quantity = int(self.request.POST.get('quantity')),
colour = colour)
product.save()
cart = self.get_object()
print(products)
cart.products.add(products)
cart.save()
return super(UpdateCartView,self).form_valid(form)
def get_object(self):
cart_obj, cart_created = Cart.objects.new_or_get(self.request)
return cart_obj
Here is my models :
class Products(models.Model):
product = models.ForeignKey(ProductCreateModel,on_delete=models.CASCADE,related_name='cart_product')
quantity = models.PositiveIntegerField(default=1,validators=[MinValueValidator(1)])
size = models.ForeignKey(Size,related_name='cart_product_size',on_delete=models.CASCADE,null=True,blank=False)
colour = models.ForeignKey(Colour,related_name='cart_product_colour',on_delete=models.CASCADE,null=True,blank=False)
def __str__(self):
return '{product}({quantity})'.format(product=self.product,quantity=self.quantity)
class Cart(models.Model):
MESSAGE_CHOICES = (
('A' , 'Items are added to you cart'),
('R' , 'Items are removed from cart'),
('PC' , 'Price of some items has changed'),
)
messages = models.CharField(max_length=1, choices=MESSAGE_CHOICES,null=True,blank=True)
user = models.ForeignKey(User, null=True, blank=True, on_delete=models.CASCADE)
products = models.ManyToManyField(Products, blank=True)
subtotal = models.DecimalField(default=0.00, max_digits=100, decimal_places=2)
total = models.DecimalField(default=0.00, max_digits=100, decimal_places=2)
updated = models.DateTimeField(auto_now=True)
timestamp = models.DateTimeField(auto_now_add=True)
objects = CartManager()
def __str__(self):
return str(self.id)
def m2m_changed_cart_receiver(sender, instance, action, *args, **kwargs):
if action == 'post_add' or action == 'post_remove' or action == 'post_clear':
products = instance.products.all()
total = 0
for x in products:
total += (x.product.final_price * x.quantity)
if instance.subtotal != total:
instance.subtotal = total
instance.save()
def pre_save_cart_receiver(sender, instance, *args, **kwargs):
if instance.subtotal > 0:
instance.total = Decimal(instance.subtotal) * Decimal(1.08) # 8% tax
else:
instance.total = 0.00
Everything is working fine, no errors, also print the products but in my admin panel its showing empty cart means cart.products.add(products) not added products why ?