Context for product search in django - python

I want to search for products in my app by their categories, retrieving data from firebase database. The search works but doesn't display the products and I can't figure out what other context is to be passed. I'm new to Django so any help would be appreciated.
here's my Welcome.html:
<form class="form-inline my-2 my-lg-0" method="get" action="/postsign" id="s">
{% csrf_token %}
<input class="form-control mr-sm-2" type="search" value="{{ category }}" placeholder="Search by category" aria-label="Search" name="Search">
<button class="btn btn-outline-success my-2 my-sm-0" type="submit" onclick="location.href='/postsign/?category={{ category }}'" form="s">Search</button>
</form>
</div>
</nav>
<div class="container">
<div class="col-md-4">
<div class="cards">
{% for product in category %}
<div class="card" style="width: 18rem;">
<img class="card-img-top" src="{{ product.image }}" alt="Card image cap">
<div class="card-body">
<h5 class="card-title">{{ product.pname }}</h5>
<p class="price">{{ product.price }}</p>
<p class="card-text">{{ product.description }}</p>
<button class="btn btn-primary cart">Add to cart</button>
<button class="btn btn-primary" onclick="location.href='{% url 'productView' %}'">View product</button>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
Here's the views:
def postsign(request):
if request.method == 'GET' and 'csrfmiddlewaretoken' in request.GET:
search = request.GET.get('Search')
search = search.lower()
timestamps = database.child("Products").shallow().get().val()
pcategory = []
for i in timestamps:
category = database.child("Products").child(i).child("category").get().val()
category = str(category)+"$"+str(i)
pcategory.append(category)
matching =[str(string) for string in pcategory if search in string.lower()]
s_category = []
s_id = []
for i in matching:
category,ids=i.split("$")
s_category.append(category)
s_id.append(ids)
data = services.get_products()
return render(request, "Welcome.html",{'category':s_category})
Here's how my database looks:
products{
timestamp{
name:...
category:...
}
timestamp{
name:..
category:...
...

Related

problem when try to make ajax request with django

i have a problem when make ajax request to the server to add product to the card using django and jquery,
this the URLs here:
path('add_to_cart/', cartView.add_to_cart, name="add_to_cart")
here the jquery code:
$(document).ready(function () {
$('.addToCartBtn').click(function (e) {
console.log("jjjj")
e.preventDefault();
var product_id = $(this).closest('.product_data').find('.prod_id').val()
var product_qty = $(this).closest('.product_data').find('.qty-input').val()
var token = $('input[name=csrfmiddlewaretoken]').val()
console.log(token)
console.log(product_id)
console.log(product_qty)
$.ajax({
method: 'POST',
url: 'add_to_cart',
data: {
'product_id' : product_id,
'product_qty' : product_qty,
csrfmiddlewaretoken: token
},
success: function(res) {
console.log(res.status)
alertify.success(res.status)
}
})
})
});
and here is the view django code:
from django.http.response import JsonResponse
from django.shortcuts import render, redirect
from django.contrib import messages
from store.models import Product, Cart
def add_to_cart(request):
if request.method == 'POST':
if request.user.is_authenticated:
prod_id = request.POST.get('product_id')
product_check = Product.objects.get(id=prod_id)
if product_check:
if Cart.objects.filter(user=request.user.id, product_id=prod_id):
return JsonResponse({'status': 'Product Already in the Cart'})
else:
prod_qty = int(request.POST.get('product_qty'))
if product_check.quantity >= prod_qty:
Cart.objects.create(user=request.user, product_id=prod_id, product_quantity=prod_qty)
return JsonResponse({'status': 'Product Added Successfully'})
else:
return JsonResponse({'status': "only" + str(product_check.quantity) + "is Available"})
else:
return JsonResponse({'status': 'No Such Product Found'})
else:
return JsonResponse({'status': 'Login To Continue'})
return redirect('/')
and here is the view.html when add to card button exist:
<section style="background-color: #eee;">
{% csrf_token %}
<div class="container py-5 product_data">
<div class="row justify-content-center mb-3">
<div class="col-md-12 col-xl-10">
<div class="card shadow-0 border rounded-3">
<div class="card-body">
<div class="row">
<div class="col-md-12 col-lg-3 col-xl-3 mb-4 mb-lg-0">
<div class="bg-image hover-zoom ripple rounded ripple-surface">
<img src="{{ product.product_image.url }}"
class="w-100"/>
<a href="#!">
<div class="hover-overlay">
<div class="mask"
style="background-color: rgba(253, 253, 253, 0.15);"></div>
</div>
</a>
</div>
</div>
<div class="col-md-6 col-lg-6 col-xl-6">
<h1>{{ product.name }}</h1>
<div class="d-flex flex-row">
<div class="text-danger mb-1 me-2">
<i class="fa fa-star"></i>
<i class="fa fa-star"></i>
<i class="fa fa-star"></i>
<i class="fa fa-star"></i>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-lg-2">
<div class="input-group">
<span class="input-group-btn">
<input type="hidden" value="{{ product.id }}" class="prod_id">
<button type="button" class="quantity-left-minus btn btn-primary btn-number"
data-type="minus" data-field="">
<span class="glyphicon glyphicon-minus"></span>
</button>
</span>
<input type="text" id="quantity" name="quantity"
class="form-control input-number qty-input" value="0" min="1" max="10">
<span class="input-group-btn">
<button type="button" class="quantity-right-plus btn btn-primary btn-number"
data-type="plus" data-field="">
<span class="glyphicon glyphicon-plus"></span>
</button>
</span>
</div>
</div>
</div>
</div>
<div class="mt-1 mb-0 text-muted small">
{{ product.description }}
</div>
</div>
<div class="col-md-6 col-lg-3 col-xl-3 border-sm-start-none border-start">
<div class="d-flex flex-row align-items-center mb-1">
<h4 class="mb-1 me-1">{{ product.selling_price }}</h4>
<span class="text-danger"><s>{{ product.original_price }}</s></span>
</div>
{% if product.trending %}
<h6 class="text-center badge bg-danger" style="font-size: 16px">Trending</h6>
{% endif %}
<div class="d-flex flex-column mt-4">
{% if product.quantity > 0 %}
<button class="addToCartBtn btn btn-primary btn-sm " type="button">Add To Cart</button>
{% endif %}
<button class="btn btn-outline-primary btn-sm mt-2" type="button">
Add to wishlist
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
this is the error message when I click on the button to make a ajax call:
ValueError: The view store.views.product_details didn't return an HttpResponse object. It returned None instead.
[03/May/2022 21:11:11] "POST /category/mobile/add_to_cart HTTP/1.1" 500 65574
I think, it is throwing error the view return None instead since you haven't redirected it inside the if condition where you are handling POST request.
Redirect it inside the if condition.
Try this:
def add_to_cart(request):
if request.method == 'POST':
if request.user.is_authenticated:
prod_id = request.POST.get('product_id')
product_check = Product.objects.get(id=prod_id)
if product_check:
if Cart.objects.filter(user=request.user.id, product_id=prod_id):
return JsonResponse({'status': 'Product Already in the Cart'})
else:
prod_qty = int(request.POST.get('product_qty'))
if product_check.quantity >= prod_qty:
Cart.objects.create(user=request.user, product_id=prod_id, product_quantity=prod_qty)
return JsonResponse({'status': 'Product Added Successfully'})
else:
return JsonResponse({'status': "only" + str(product_check.quantity) + "is Available"})
else:
return JsonResponse({'status': 'No Such Product Found'})
else:
return JsonResponse({'status': 'Login To Continue'})
return redirect('/')

Please how can get the number of listings in a category, i have tried

I have a django app and I need to count the number of listings in a category (as defined by the models below):
here is my complete model
class Category(models.Model):
name = models.CharField(max_length=500)
icon = models.ImageField(upload_to='photos/icons/%Y/%m/%d/')
def __str__ (self):
return self.name
class Listing(models.Model):
name = models.CharField(max_length=300)
category = models.ForeignKey(Category, on_delete=models.CASCADE, default=False, null=True)
email = models.EmailField(max_length=300)
description = RichTextField(blank=False, null=False)
photo_main = models.ImageField(upload_to = 'photos/%Y/%m/%d/')
photo_1 = models.ImageField(upload_to = 'photos/%Y/%m/%d/', blank=True, default=True)
photo_2 = models.ImageField(upload_to = 'photos/%Y/%m/%d/', blank=True, default=True)
photo_3 = models.ImageField(upload_to = 'photos/%Y/%m/%d/', blank=True, default=True)
photo_4 = models.ImageField(upload_to = 'photos/%Y/%m/%d/', blank=True, default=True)
location = models.CharField(max_length=500, null=True)
phone_number = models.CharField(max_length=11, default = "#")
website = models.CharField(max_length=150, blank=True, default="#")
facebook = models.CharField(max_length=150, blank=True, default="#")
instagram = models.CharField(max_length=150, blank=True, default="#")
opening_time = models.CharField(max_length=7)
closing_time = models.CharField(max_length=7)
is_published = models.BooleanField(default=False)
posted_date = models.DateTimeField(auto_now_add=True)
user_id = models.IntegerField(blank=True)
def __str__ (self):
return self.name
here are my views
from django.shortcuts import render
from listings.models import Listing
from listings.models import Category
from testimonies.models import Testimony
from our_team.models import Team_Mate
from testimonies.models import Testimony
from django.db.models import Count
def index(request):
this part is working perfectly.
listings = Listing.objects.order_by('-posted_date').filter(is_published=True)[:6]
category = request.GET.get('category')
categories = Category.objects.all()[:7]
counting listings in a category
count_cate = Category.objects.all()
cate_count = count_cate.count()
if category == None:
listings = Listing.objects.order_by('-posted_date').filter(is_published=True)[:6]
else:
listings = Listing.objects.filter(Category__name=category)
here is my context
context ={
'listings': listings,
'categories': categories,
'cate_count': cate_count,
}
return render(request, 'pages/index.html', context)
Here is my html where I want the number of listings in category to show
{% extends 'base.html' %}
{% load static %}
{% block content %}
<!-- ======= Intro Section ======= -->
<div class="header">
<div class="header-content display-table">
<div class="table-cell">
<div class="container">
<h1 class="header-title text-light text-uppercase pb-3">Explore Bonny Island</h1>
<h3 class="text-light">Find. Connect. Share</h3>
<div class="search mt-3 px-0 py-1 mx-0">
<form action="{% url 'search' %}" method="GET">
{% csrf_token %}
<div class="row d-flex justify-content-center container p-0 m-0 px-1">
<input type="text" name="keywords"
class="form-control col-lg-3 col-md-12 col-sm-12 mx-2 py-4 my-2 border border-5"
placeholder=" Keyword">
<input type="text" name="location"
class="form-control col-lg-3 col-md-12 mx-2 py-4 col-sm-12 my-2 border border-5"
placeholder=" Location">
<input type="text" name="category" value="{{ query }}" list="category"
class="form-control col-lg-3 col-md-12 col-sm-12 mx-2 py-4 my-2 border border-5"
placeholder=" Category (All)">
<datalist id="category">
{% for categories in categories %}
<option>{{ categories.name }}</option>
{% endfor %}
</datalist>
<button type="submit"
class="btn search-bt col-lg-2 col-md-12 mx-2 col-sm-12 py-2 px-2 font-weight-bold my-
2">Search</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div><!-- End Intro Section -->
<!-- ======== most popular categories ========= -->
<section class="main">
<div class="discover pb-1 m-0">
<h2>Explore Categories</h2>
<div class="container">
<div class="row justify-content-around m-0 p-0 pt-3">
{% for category in categories %}
{% if category %}
<div class="col-lg-3 col-md-6 py-2">
<a href="{% url 'listings' %}?category={{ category.name }}" class="card category">
<div class="d-flex justify-content-between align-items-start px-3 m-0 py-2">
<div class="category-name-icon p-0 m-0">
<span class="text-dark font-weight-bold"><img class="category-icon" src="{{
category.icon.url }}">
{{category.name}}</span>
</div>
<div class="category-list-number text-muted font-weight-bold">{{cate_count}}</div>
</div>
</a>
</div>
{% endif %}
{% endfor %}
<div class="col-lg-3 col-md-6 py-2">
<a href="{% url 'category' %}" class="card category" data-bs-toggle="collapse"
href="#collapseExample"
role="button" aria-expanded="false" aria-controls="collapseExample">
<div class="d-flex justify-content-between = px-3 m-0 py-2">
<i class="font-weight-bold py-1 text-secondary">More Categories...</i>
</div>
</a>
</div>
</div>
</div>
</section> <!-- ======== most popular categories end ======== -->
<!-- STRUCTURING THE POPULAR LISTINGS CONTENT-->
<section id="popularListings" class="container mb-5 py-5">
<!-- Popular listenings head title-->
<div class="sectionTitle d-flex justify-content-between align-items-baseline">
<div class="mainTitleContents">
<h2 class="titleText h2 text-blue">Popular Listings</h2>
<p class="subTitleText mb-2">Explore businesses on the island.</p>
</div>
<div class="filterOption">
All Listings
</div>
</div>
<!-- MAIN POPULAR LISTINGS ROW CONTENT-->
<div class="popularListingsRows row py-2">
{% if listings %}
{% for listing in listings %}
<div class="customCard p-1 m-0 col-lg-3 col-md-4 col-sm-6 mt-sm-3">
<div class="card">
<div class="card-header p-0">
<div class="blank rounded" style="background-image: url('{{
listing.photo_main.url }}'); background-repeat: no-repeat;
background-size:cover; width:100%; height: 15em; background-
position:center-top" ;></div>
</div>
<div class="card-body">
<div class="content-details">
<h3 class="m-0 mt-1 mb-2 cardTitle">{{ listing.name }}</h3>
<p class="cardSubTitle">
{%autoescape off%}
{{ listing.description|striptags|truncatechars:100 }}
{%endautoescape%}
</p>
<a href="{% url 'listing' listing.id %}" class="btn btn-sm bg-blue text-
light rounded-none">Read More</a>
</div>
</div>
</div>
</div>
{% endfor %}
{% else %}
<div class="col-md-12">
<p class="text-dark">No listings Available</p>
</div>
{% endif %}
</div>
</section>
{% endblock %}
How can I make this code work as intended?
You should call the count method on the list of objects like...
if category == None:
listings = Listing.objects.order_by('-posted_date').filter(is_published=True)[:6]
else:
listings = Listing.objects.filter(category__name=category).count()
Please ensure where you have Category__name=category you must allow this to match your model field category.
In your html:
<!-- ======= Intro Section ======= -->
<form action="{% url 'search' %}" method="GET">
{% csrf_token %}
<div class="row d-flex justify-content-center container p-0 m-0 px-1">
...
<!--<input type="text" name="category" value="{{ query }}" list="category" class="form-control col-lg-3 col-md-12 col-sm-12 mx-2 py-4 my-2 border border-5" placeholder=" Category (All)">-->
<!-- Remove value="{{ query }}" -->
<input type="text" name="category" list="categories" class="form-control col-lg-3 col-md-12 col-sm-12 mx-2 py-4 my-2 border border-5" placeholder=" Category (All)">
<!-- Should be category in categories instead of categories in categories -->
<datalist id="categories">
{% for category in categories %}
<option value="{{ category.name }}"> <!-- Setting the value here... -->
{% endfor %}
</datalist>
...
</div>
</form>
I solved the it by calling the name of the category i want to count but am still to look for a way to count it without specifying the category name.
cate_count = Listing.objects.filter(category__name="Catering services").count()

Django formtools with custom template

I have the following custom wizard
<div class="container">
<div id="smartwizard">
<ul>
<li>Engagement Setup<br /><small>Basic info</small></li>
<li>File Upload<br /><small>Upload files</small></li>
<li>Business Rules<br /><small>rules</small></li>
<li>Documentation<br /><small>documentation</small></li>
</ul>
<div>
<div id="step-1" class="">
<div id="form-step-0" role="form" data-toggle="validator">
<div class="form-group">
<label for="text">Code <span class="tx-danger">*</span></label>
<input type="text" class="form-control" name="code" id="code" placeholder="Write your code" required>
<div class="help-block with-errors"></div>
</div>
</div>
<hr />
</div>
....
</div>
</div>
<br />
</div>
I have setup the django form as such
class PageOne(forms.Form):
ibs_code = forms.CharField(max_length=100)
engagement_name = forms.CharField(max_length=100)
engagement_manager = forms.CharField(max_length=100)
engagement_partner = forms.CharField(max_length=100)
solution = forms.CharField(label='What solution would you like to use?', widget=forms.Select(choices=FRUIT_CHOICES))
And of course the views..
class TestWizard(SessionWizardView):
file_storage = FileSystemStorage(
location=os.path.join(settings.MEDIA_ROOT, 'temp_uploads'))
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.is_done = False
def get_template_names(self):
if self.is_done:
# return [self.templates['done']]
return [TEMPLATES['done']]
else:
return [TEMPLATES[self.steps.current]]
.....
......
Now I want to use the custom template with the form. Meaning, I want to generate the form fields the way the html/style looks with form-group and such. How can I achieve this?
I tried the documentation but they weren't any sources for custom templating
Update #1: Doing something like this is not sufficient
<div id="form-step-0" role="form">
<div class="form-group">
{% if wizard.form.forms %}
{{wizard.form.management_form }}
{% for form in wizard.form.forms %}
{{form}}
{% endfor %}
{% else %}
{{ wizard.form }}
{% endif %}
</div>
</div>
I need it to look just like the html I put together
First, you can specify the class to be used for your form fields, for example:
class PageOne(forms.Form):
ibs_code = forms.CharField(
max_length=100,
widget=forms.TextInput(
attrs={'class' : 'YourClassName'}
)
)
Second, you can put the individual fields within the template as you want
<div class="container">
<div id="smartwizard">
<ul>
<li>Engagement Setup<br /><small>Basic info</small></li>
<li>File Upload<br /><small>Upload files</small></li>
<li>Business Rules<br /><small>rules</small></li>
<li>Documentation<br /><small>documentation</small></li>
</ul>
<form>
{{ wizard.form.management_form }}
{% csrf_token %}
<div>
<div id="step-1" class="">
<div id="form-step-0" role="form" data-toggle="validator">
<div class="form-group">
<label for="text">Code <span class="tx-danger">*</span></label>
{{ form.ibs_code }}
{{ form.ibs_code.errors }}
</div>
</div>
<hr />
</div>
....
</div>
</form>
</div>
<br />
</div>
EDIT - ACTUAL LIVE EXMAPLE
<form id="" class="max-width-800px margin-center" action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ wizard.management_form }}
{{ wizard.form.media }}
<input name="job-is_user" type="checkbox" hidden {% if request.user.is_authenticated %}checked{% endif %}>
<input name="job-is_company" type="checkbox" hidden {% if request.user.company_user %}checked{% endif %}>
<div class="form-group">
<label for="id_job-plan_"PLANS[0].id >Job Listing Type</label>
{{ wizard.form.plan }}
<div class="alert alert-primary top-3">Jobs are subscription-based and are active until you've filled the position. At the end of your recurring billing cycle you will be charged and your listing will be moved back to the top of its category.</div>
</div>
<div class="form-group row">
<div class="col-6">
<label for="id_job-title">Job Title</label>
{{ wizard.form.title }}
</div>
<div class="col-6">
<label for="id_job-category">Job Category</label>
<span class="form-select">
{{ wizard.form.category }}
</span>
</div>
</div>
<div class="form-group">
<label for="">Job Type</label>
<div class="row">
{% for employment in EMPLOYMENTS %}
<div class="col-4">
<span class="form-radio form-radio-lg">
<input type="radio" id="id_job-employment_{{employment.id}}" name="job-employment" value="{{ employment.id }}" required {% if job.employment.id == employment.id or wizard.form.employment.value|add:"0" == employment.pk %}checked{% endif %}>
<label for="id_job-employment_{{employment.id}}">{{ employment }}</label>
</span>
</div>
{% endfor %}
</div>
</div>
<div class="form-group row">
<div class="col-6">
<label for="id_job-job_level">Job Level</label>
<span class="form-select">
{{ wizard.form.job_level }}
</span>
</div>
<div class="col-6">
<label for="id_job-salary_range">Job Compensation</label>
<span class="form-select">
{{ wizard.form.salary_range }}
</span>
</div>
</div>
<div id="job-location-groupX" class="form-group">
<label for="id_job-office_base">Job Location</label>
<div class="row">
{% for office in OFFICE_BASE %}
<div class="col-6">
<span class="form-radio form-radio-lg">
<input type="radio" id="id_job-office_base_{{office.id}}" name="job-office_base" value="{{ office.id }}" {% if job.office_base.id == office.id or wizard.form.office_base.value|add:"0" == office.pk %}checked{% endif %}>
<label for="id_job-office_base_{{office.id}}">{{ office.name }}</label>
</span>
</div>
{% endfor %}
</div>
<div id="new-job-location-details" class="hidden top-1">
{{ wizard.form.outside_location }}
{{ wizard.form.outside_location.errors }}
<ul class="list-unstyled list-increase-spacing">
<li>
<span class="form-checkbox">
{{ wizard.form.relocation_assistance }}
<label id="label-id_job-relocation_assistance" for="id_job-relocation_assistance">Relocation assistance provided</label>
{{ wizard.form.relocation_assistance.errors }}
</span>
</li>
<li>
<span class="form-checkbox">
{{ wizard.form.visa_sponsorship }}
<label for="id_job-visa_sponsorship">Visa sponsorship provided</label>
{{ wizard.form.visa_sponsorship.errors }}
</span>
</li>
</ul>
</div>
</div>
<div class="form-group">
<label for="id_job-description">Job Description</label>
<div class="col-12">
{{ wizard.form.description }}
{{ wizard.form.description.errors }}
</div>
</div>
<div id="job-how-to-apply-groupX" class="form-group">
<label>How to Apply to This Job</label>
<div class="row">
<div class="col-6">
<span class="form-radio form-radio-lg">
<input type="radio" required id="new-job-apply-us" value="4" name="job-apply_online" {% if job.apply_online == 4 or wizard.form.apply_online.value|add:"0" == 4 %}checked {% endif %}>
<label for="new-job-apply-us">Through us <em class="float-right tablet-hide">(recommended)</em></label>
</span>
</div>
<div class="col-6">
<span class="form-radio form-radio-lg">
<input type="radio" id="new-job-apply-you" name="job-apply_online" value="3" {% if job.apply_online == 3 or wizard.form.apply_online.value|add:"0" == 3 %}checked {% endif %}>
<label for="new-job-apply-you">Through you <em class="float-right tablet-hide">(external URL)</em></label>
</span>
</div>
</div>
<div id="new-job-apply-details" class="hidden top-1">
{{ wizard.form.apply_url }}
{{ wizard.form.howto_apply }}
</div>
</div>
<div id="job-extras" class="form-group">
<h6>Additional Extras <span class="optional-field">(optional)</span></h6>
{{ wizard.form.addons }}
</div>
<button type="submit" class="btn btn-lg btn-solid-teal">{% if request.user.company_user %}Preview Your Listing{% elif request.user.is_authenticated %}Enter Company Details{% else %}User Details{% endif %} →</button>
</form>
forms.py
class JobPostWizardForm1(forms.ModelForm):
error_css_class = "alert alert-error"
category = forms.ModelChoiceField(Category.objects.all(), empty_label='Choose one...', required=False)
job_level = forms.ModelChoiceField(JobLevel.objects.all(), empty_label='Choose one...', required=False)
salary_range = forms.ModelChoiceField(Salary.objects.active(), empty_label='Choose one...', required=False)
plan = forms.ModelChoiceField(Plan.objects.all(), empty_label=None, required=True, widget=PlanSelect)
is_user = forms.BooleanField(required=False)
is_company = forms.BooleanField(required=False)
class Meta:
model = Job
fields = [
'plan','title','category','employment','job_level','salary_range','office_base', 'outside_location',
'relocation_assistance','visa_sponsorship','description','apply_online','howto_apply','addons', 'is_user',
'is_company', 'apply_url'
]
def __init__(self, is_active= False, edit_mode=False, plan=0, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['plan'].initial = Plan.objects.all()[plan]
if is_active : self.fields['plan'].widget.attrs['disabled'] = True
self.fields['description'].required = True
self.fields['apply_url'].widget.attrs['placeholder'] = 'External URL'
self.fields['howto_apply'].widget = forms.Textarea()
self.fields['howto_apply'].widget.attrs['rows']=10
self.fields['howto_apply'].widget.attrs['placeholder']="Additional instructions..."
self.fields['relocation_assistance'].widget = AuthenticJobsCheckbox()
self.fields['visa_sponsorship'].widget = AuthenticJobsCheckbox()
self.fields['addons'].widget = AddOnCheckboxSelectMultiple()
self.fields['addons'].queryset = AddOnItem.objects.filter(active=True)
#if edit_mode : self.fields['addons'].widget.attrs['disabled'] = True
if is_active : self.fields['addons'].widget.attrs['onclick'] = "return false;"
self.error_class = DivErrorList

Saving edited data via formsets

I am trying to edit multiple rows of data in a model via formsets. In my rendered form, I use javascript to delete (hide and assign DELETE) rows, and then save changes with post.
My view:
def procedure_template_modification_alt(request, cliniclabel, template_id):
msg = ''
clinicobj = Clinic.objects.get(label=cliniclabel)
template_id = int(template_id)
template= ProcedureTemplate.objects.get(templid = template_id)
formset = ProcedureModificationFormset(queryset=SectionHeading.objects.filter(template = template))
if request.method == 'POST':
print(request.POST.get)
# Create a formset instance with POST data.
formset = ProcedureModificationFormset(request.POST)
if formset.is_valid():
print("Form is valid")
instances = formset.save(commit=False)
print(f'instances:{instances}')
for instance in instances:
print(f'Instance: {instance}')
instance.template = template
instance.save()
msg = "Changes saved successfully."
print("Deleted forms:")
for form in formset.deleted_forms:
print(form.cleaned_data)
else:
print("Form is invalid")
print(formset.errors)
msg = "Your changes could not be saved as the data you entered is invalid!"
template= ProcedureTemplate.objects.get(templid = template_id)
headings = SectionHeading.objects.filter(template = template)
return render(request, 'procedures/create_procedure_formset_alt.html',
{
'template': template,
'formset': formset,
'headings': headings,
'msg': msg,
'rnd_num': randomnumber(),
})
My models:
class ProcedureTemplate(models.Model):
templid = models.AutoField(primary_key=True, unique=True)
title = models.CharField(max_length=200)
description = models.CharField(max_length=5000, default='', blank=True)
clinic = models.ForeignKey(Clinic, on_delete=models.CASCADE)
def __str__(self):
return f'{self.description}'
class SectionHeading(models.Model):
procid = models.AutoField(primary_key=True, unique=True)
name = models.CharField(max_length=200)
default = models.CharField(max_length=1000)
sortorder = models.IntegerField(default=1000)
fieldtype_choice = (
('heading1', 'Heading1'),
('heading2', 'Heading2'),
)
fieldtype = models.CharField(
choices=fieldtype_choice, max_length=100, default='heading1')
template = models.ForeignKey(ProcedureTemplate, on_delete=models.CASCADE, null=False)
def __str__(self):
return f'{self.name} [{self.procid}]'
My forms:
class ProcedureCrMetaForm(ModelForm):
class Meta:
model = SectionHeading
fields = [
'name',
'default',
'sortorder',
'fieldtype',
'procid'
]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['name'].widget.attrs.update({'class': 'form-control'})
self.fields['default'].widget.attrs.update({'class': 'form-control'})
self.fields['sortorder'].widget.attrs.update({'class': 'form-control'})
self.fields['fieldtype'].widget.attrs.update({'class': 'form-control'})
ProcedureCreationFormset = formset_factory(ProcedureCrMetaForm, extra=3)
ProcedureModificationFormset = modelformset_factory(SectionHeading, ProcedureCrMetaForm,
fields=('name', 'default', 'sortorder','fieldtype', 'procid'),
can_delete=True,
extra=0
# widgets={"name": Textarea()}
)
The template:
{% block content %} {% load widget_tweaks %}
<div class="container">
{% if user.is_authenticated %}
<div class="row my-1">
<div class="col-sm-2">Name</div>
<div class="col-sm-22">
<input type="text" name="procedurename" class="form-control" placeholder="Enter name of procedure (E.g. DNE)"
value="{{ template.title }}" />
</div>
</div>
<div class="row my-1">
<div class="col-sm-2">Description</div>
<div class="col-sm-22">
<input type="text" name="proceduredesc" class="form-control" placeholder="Enter description of procedure (E.g. Diagnostic Nasal Endoscopy)"
value="{{ template.description }}" />
</div>
</div>
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %} {{ formset.management_form }}
<div class="row mt-3">
<div class="col-sm-1">Select</div>
<div class="col-sm-6">Heading</div>
<div class="col-sm-8">Default (Normal description)</div>
<div class="col-sm-2">Sort Order</div>
<div class="col-sm-4">Type</div>
<div class="col-sm-2">Action</div>
</div>
{% for form in formset %}
<div class="row procrow" id="row{{ forloop.counter0 }}">
<div class="" style="display: none;">{{ form.procid }}</div>
<div class="col-sm-6">
{{ form.name }}
</div>
<div class="col-sm-8">
<div class="input-group">
{{ form.default }}
</div>
</div>
<div class="col-sm-2">
<div class="input-group">
{{ form.sortorder }}
</div>
</div>
<div class="col-sm-4">
<div class="input-group">
{{ form.fieldtype }}
</div>
</div>
<div class="col-sm-2">
<div class="input-group">
<div class="input-group-append">
<button id="add{{ forloop.counter0 }}" class="btn btn-success add-row">+</button>
</div>
<div class="input-group-append">
<button id="del{{ forloop.counter0 }}" class="btn btn-danger del-row">-</button>
</div>
</div>
</div>
</div>
{% endfor %} {% endif %}
<div class="row my-3">
<div class="col-sm-8"></div>
<div class="col-sm-8">
<div class="input-group">
<div class="input-group-append mx-1">
<button id="save_report" type="submit" class="btn btn-success"><i class="fal fa-shield-check"></i>
Save Report Format</button>
</div>
<div class="input-group-append mx-1">
<button id="save_report" type="button" class="btn btn-danger"><i class="fal fa-times-hexagon"></i>
Cancel</button>
</div>
</div>
</div>
<div class="col-sm-8"></div>
</div>
<div>
{% for dict in formset.errors %} {% for error in dict.values %} {{ error }} {% endfor %} {% endfor %}
</div>
</form>
</div>
{% endblock %}
My data is displayed as below (Screenshot). I make changes with javascript when the delete button is pressed, so that the html becomes like this:
<div class="row procrow" id="row2" style="display: none;">
<div class="" style="display: none;"><input type="hidden" name="form-2-procid" value="25" id="id_form-2-procid"></div>
<div class="col-sm-6">
<input type="text" name="form-2-name" value="a" maxlength="200" class="form-control" id="id_form-2-name">
</div>
<div class="col-sm-8">
<div class="input-group">
<input type="text" name="form-2-default" value="v" maxlength="1000" class="form-control" id="id_form-2-default">
</div>
</div>
<div class="col-sm-2">
<div class="input-group">
<input type="number" name="form-2-sortorder" value="1000" class="form-control" id="id_form-2-sortorder">
</div>
</div>
<div class="col-sm-4">
<div class="input-group">
<select name="form-2-fieldtype" class="form-control" id="id_form-2-fieldtype">
<option value="heading1" selected="">Heading1</option>
<option value="heading2">Heading2</option>
</select>
</div>
</div>
<div class="col-sm-2">
<div class="input-group">
<div class="input-group-append">
<button id="add2" class="btn btn-success add-row">+</button>
</div>
<div class="input-group-append">
<button id="del2" class="btn btn-danger del-row">-</button>
</div>
</div>
</div>
<input type="checkbox" name="form-2-DELETE" id="id_form-2-DELETE" checked=""></div>
On submitting the data, I get the following output, and data does not reflect the deletion I did. It displays the same thing again. There are no errors. But my edited data is not being saved.
Output:
<bound method MultiValueDict.get of <QueryDict: {'csrfmiddlewaretoken': ['ka3avICLigV6TaMBK5a8zeVJlizhtsKW5OTDBLlYorKd7Iji9zRxCX2vvjBv6xKu'], 'form-TOTAL_FORMS': ['3'], 'form-INITIAL_FORMS': ['3'], 'form-MIN_NUM_FORMS': ['0'], 'form-MAX_NUM_FORMS': ['1000'], 'form-0-procid': ['23'], 'form-0-name': ['External ear canal'], 'form-0-default': ['Bilateral external ear canals appear normal. No discharge.'], 'form-0-sortorder': ['100'], 'form-0-fieldtype': ['heading1'], 'form-1-procid': ['24'], 'form-1-name': ['Tympanic membrane'], 'form-1-default': ['Tympanic membrane appears normal. Mobility not assessed.'], 'form-1-sortorder': ['500'], 'form-1-fieldtype': ['heading1'], 'form-2-procid': ['25'], 'form-2-name': ['a'], 'form-2-default': ['v'], 'form-2-sortorder': ['1000'], 'form-2-fieldtype': ['heading1'], 'form-2-DELETE': ['on']}>>
Form is valid
instances:[]
Deleted forms:
{'name': 'a', 'default': 'v', 'sortorder': 1000, 'fieldtype': 'heading1', 'procid': <SectionHeading: a [25]>, 'DELETE': True}
You actually need to delete the instances: Loop through the formsets' deleted_objects property after you called saved(commit=False) and delete them.

data did'nt validate error django

Can anyone please help me..... I keep on getting "data didn't validate" error when saving data from a ModelForm. Everything worked fine for me until I added some CSS and JS for the frontend, used form widgets and manually displayed the form field on the template.
Here are the codes:
forms.py
from django import forms
from .models import List_of_Res
class fordtp(forms.Form):
month_choices=(
('JAN','January'),
('FEB','February'),
('MAR','March'),
('APR','April'),
('MAY','May'),
('JUN','June'),
('JUL','July'),
('AUG','August'),
('SEP','September'),
('NOV','November'),
('DEC','December'),
)
day_choices=[]
for ddd in range(1,32):
day_toS=(str(ddd),str(ddd))
day_choices.append(day_toS)
year_choices=[]
for yyy in range(1990,2100):
year_toS=(str(yyy),str(yyy))
year_choices.append(year_toS)
month = forms.ChoiceField(choices = month_choices,widget=forms.Select(attrs={'class':'form-control form-control-sm'}))
year = forms.ChoiceField(choices = year_choices,widget=forms.Select(attrs={'class':'form-control form-control-sm'}))
day = forms.ChoiceField(choices = day_choices,widget=forms.Select(attrs={'class':'form-control form-control-sm'}))
class ResearchForm(forms.ModelForm):
class Meta:
model = List_of_Res
fields={
'prog_title',
'proj_title',
'stud_title',
'prog_lead',
'stud_lead',
'co_res',
'res_site',
'campus',
'category_res',
'classif_res',
'amt_granted',
'date_started',
'res_status',
'date_completed',
'res_SF',
'res_pubstat',
'res_JN',
'res_JV',
'date_pub',
'res_iprstat',
'apptype',
'date_appl',
'date_pprv',
'app_pending',
'res_abs'
}
widgets = {
'prog_title': forms.TextInput(attrs={'class':'form-control'}),
'proj_title': forms.TextInput(attrs={'class':'form-control'}),
'stud_title': forms.TextInput(attrs={'class':'form-control'}),
'prog_lead': forms.TextInput(attrs={'class':'form-control'}),
'stud_lead': forms.TextInput(attrs={'class':'form-control'}),
'co_res': forms.Textarea(attrs={'class':'form-control','placeholder':'Enter 1 name per line'}),
'res_site': forms.Textarea(attrs={'class':'form-control','placeholder':'Enter 1 site per line'}),
'campus': forms.Select(attrs={'class':'form-control'}),
'category_res': forms.RadioSelect(attrs={'class':'form-check-input'}),
'classif_res': forms.Select(attrs={'class':'form-control'}),
'amt_granted': forms.TextInput(attrs={'class':'form-control'}),
'date_started': forms.DateInput(attrs={'placeholder':'YYYY-MM-DD','class':'form-control'}),
'res_status': forms.RadioSelect(attrs={'class':'form-check-input'}),
'date_completed': forms.DateInput(attrs={'placeholder':'YYYY-MM-DD','class':'form-control'}),
'res_SF': forms.CheckboxSelectMultiple(attrs={'class':'form-check-input'}),
'res_pubstat': forms.RadioSelect(attrs={'class':'form-check-input'}),
'res_JN': forms.TextInput(attrs={'class':'form-control'}),
'res_JV': forms.TextInput(attrs={'class':'form-control'}),
'date_pub': forms.DateInput(attrs={'placeholder':'YYYY-MM-DD','class':'form-control'}),
'res_iprstat':forms.RadioSelect(attrs={'class':'form-check-input'}),
'apptype':forms.RadioSelect(attrs={'class':'form-check-input'}),
'date_appl':forms.DateInput(attrs={'placeholder':'YYYY-MM-DD','class':'form-control'}),
'date_pprv':forms.DateInput(attrs={'placeholder':'YYYY-MM-DD','class':'form-control'}),
'app_pending': forms.RadioSelect(attrs={'class':'form-check-input'}),
'res_abs': forms.Textarea(attrs={'class':'form-control'})
}
(views.py):
from django.shortcuts import render
from django.http import HttpResponse
from .forms import ResearchForm
from .models import List_of_Res
def RIS_Home(request):
return render(request,'RIS/RIS_Home.html')
def Add_Res(request):
if request.method=='POST':
form = ResearchForm(request.POST)
if form.is_valid():
resAdd=form.save(commit=False)
resAdd.save()
else:
form = ResearchForm()
args = {'form':form}
return render(request,'RIS/RIS_Add-Edit.html',args)
(models.py)
from django.db import models
class List_of_Res(models.Model):
Yes_no_Choices = (('YES','YES'),('NO','NO'))
Stat_choices = (("COMPLETED","Completed"),("ON_GOING","On-Going"))
Campus_choices = (
("APARRI","Aparri"),
("LASAM","Lasam"),
("LALLO","Lal-lo"),
("SANCHEZ_MIRA","Sanchez Mira"),
("CARIG","Carig"),
("ANDREWS","Andrews"),
("PIAT","Piat")
)
Category_choices = (
("BASIC","Basic"),
("APPLIED","Applied"),
("PILOT_TESTING","Pilot Testing"),
("TECHNOLOGY_PROMOTION_COMMERCIALIZATION","Technology Promotion / Commercialization")
)
Classification_choices = (
("AGRICULTURE","Agriculture"),
("BIOTECHNOLOGY","Biotechnology"),
("ICT","ICT"),
("HEALTH_PRODUCTS","Health Products"),
("ALTERNATIVE_ENERGY","Alternative Energy"),
("CLIMATE_CHANGE","Climate Change"),
("ENVIRONMENT","Environment"),
("SOCIO_ECONOMIC","Socio-economic"),
("NATURAL_PRODUCTS","Natural Products"),
("OTHER","Other")
)
Source_fund_choices = (
("CSU","CSU"),
("CHED","CHED"),
("DA_BAR","DA-BAR"),
("DOST","DOST"),
("PCCARRD","PCCARRD"),
("PCIERD","PCIERD"),
("PCHRD","PCHRD"),
("DA","DA"),
("OTHER","Other")
)
IPR_Type_choices = (
("PATENT","Patent"),
("UTILITY_MODEL","Utility Model"),
("TRADEMARK_TRADENAME","Trademark/Tradename"),
("COPYRIGHT","Copyright"),
("OTHER","Other")
)
prog_title = models.CharField(max_length=1000)
proj_title = models.CharField(max_length=1000)
stud_title = models.CharField(max_length=1000)
prog_lead = models.CharField(max_length=300)
stud_lead = models.CharField(max_length=300)
co_res = models.TextField()
res_site = models.TextField()
campus = models.CharField(max_length=50,choices=Campus_choices,default='ANDREWS')
category_res = models.CharField(max_length=50,choices=Category_choices,default='BASIC')
classif_res = models.CharField(max_length=50,choices=Classification_choices,default='ICT')
amt_granted = models.TextField()
date_started = models.TextField()
res_status = models.CharField(max_length=10, choices=Stat_choices, default='COMPLETED')
date_completed = models.TextField()
res_SF = models.TextField(choices=Source_fund_choices,default='CSU')
res_pubstat = models.CharField(max_length=5,choices=Yes_no_Choices, default='YES')
res_JN = models.TextField()
res_JV = models.CharField(max_length=100)
date_pub = models.TextField()
res_iprstat = models.CharField(max_length=10, choices=Yes_no_Choices, default='YES')
apptype = models.CharField(max_length=100,choices=IPR_Type_choices,default='PATENT')
date_appl = models.TextField()
date_pprv = models.TextField()
app_pending = models.CharField(max_length=10, choices=Yes_no_Choices, default='YES')
res_abs = models.CharField(max_length=1000)
end this is the html template
{% extends 'RIS/RIS_Home.html' %}
{% block body %}
<div class="container">
<form method="post">
<div>
{% csrf_token %}
<div>
<div class="row"><div class="boxed_content">Title of Research</div></div>
<br>
<div class="row">
<label class="label_style_AEform">Program Title</label>
<br>
{{ form.prog_title }}
</div>
<div class="row">
<label class="label_style_AEform">Project Title</label>
<br>
{{ form.proj_title }}
</div>
<div class="row">
<label class="label_style_AEform">Study Title</label>
<br>
{{ form.stud_title }}
</div>
</div>
<br>
<div>
<br>
<div class="row"><div class="boxed_content">Researcher/s</div></div>
<br>
<div class="row">
<div class="col">
<div class="row">
<label class="label_style_AEform">Program Leader</label>
<br>
{{ form.prog_lead }}
</div>
<br><br><br>
<div class="row">
<label class="label_style_AEform">Study Leader</label>
<br>
{{ form.stud_lead }}
</div>
</div>
<div class="col">
<label class="label_style_AEform">Co-Researcher/s</label>
<br>
{{ form.co_res }}
</div>
</div>
</div>
<div>
<br>
<div class="row"><div class="boxed_content">Site / Location of study</div></div>
<br>
<div class="row">
{{ form.res_site }}
</div>
</div>
<div>
<br>
<div class="row"><div class="boxed_content">Category of Research</div></div>
{% for rdo in form.category_res %}
<div class="form-check form-check-inline">
{{ rdo }}
</div>
{% endfor %}
</div>
<br>
<div>
<div class="row">
<div class="col">
<div class="row"><div class="boxed_content">Classification of Research<br>
{{ form.classif_res }}
</div></div>
</div>
<div class="col">
<div class="row"><div class="boxed_content">Campus<br>
{{ form.campus }}
</div></div>
</div>
</div>
</div>
<br>
<div>
<div class="row">
<div class="col">
<div class="row"><div class="boxed_content">Source of Fund</div></div>
{% for chk in form.res_SF %}
<div class="form-check form-check-inline">
{{ chk }}
</div>
{% endfor %}
</div>
<div>
<div class="col">
<div class="row"><div class="boxed_content">Amount Granted<br>{{ form.amt_granted }}</div></div>
</div>
</div>
</div>
</div>
<br>
<div>
<div class="row">
<div class="col">
<div class="row"><div class="boxed_content">Status of Research</div></div>
{% for rdo in form.res_status %}
<div class="form-check form-check-inline">
{{ rdo }}
</div>
{% endfor %}
</div>
<div class="col">
<div class="row"><div class="boxed_content">Date Started<br>
<div class="form-check form-check-inline">
{{ form.date_started }}
</div>
</div></div>
</div>
<div class="col">
<div class="row"><div class="boxed_content">Date Completed<br>
<div class="form-check form-check-inline">
{{ form.date_completed }}
</div>
</div></div>
</div>
</div>
</div>
<br>
<div class="row">
<div class="boxed_content">Is the research published?
{% for rdo in form.res_pubstat %}
<div class="form-check form-check-inline">
{{ rdo }}
</div>
{% endfor %}
</div>
<br>
<div class="row">
<div class="col">
<label class="label_style_AEform">If Yes,</label>
</div>
<div class="col">
<label class="label_style_AEform">Name of Journal</label>
{{ form.res_JN }}
</div>
<div class="col">
<label class="label_style_AEform">Volume</label>
{{ form.res_JV }}
</div>
<div class="col">
<label class="label_style_AEform">Date Published</label>
<div class="form-check form-check-inline">
{{ form.date_pub }}
</div>
</div>
</div>
</div>
<br>
<div class="row">
<div class="boxed_content">Does the research have IPR application?
{% for rdo in form.res_iprstat %}
<div class="form-check form-check-inline">
{{ rdo }}
</div>
{% endfor %}
</div>
<br>
<div class="row">
<div class="col">
<label class="label_style_AEform">If Yes, Application Type: </label>
{% for rdo in form.apptype %}
<div class="form-check form-check-inline">
{{ rdo }}
</div>
{% endfor %}
</div>
</div>
<div class="row">
<div class="col">
<label class="label_style_AEform">Date of Application</label>
<div class="form-check form-check-inline">
{{ form.date_appl }}
</div>
</div>
<div class="col">
<label class="label_style_AEform">Date of Approval of application</label>
<div class="form-check form-check-inline">
{{ form.date_pprv }}
</div>
</div>
<br>
<div class="col">
<label class="label_style_AEform">Is the application Pending? </label>
{% for rdo in form.app_pending %}
<div class="form-check">
{{ rdo }}
</div>
{% endfor %}
</div>
</div>
</div>
<div class="row">
<div class="boxed_content">Abstract of the study</div>
<br>
{{ form.res_abs }}
</div>
</div>
<div class="row"><button type="submit" class="btn btn-primary mb-2">SAVE</button></div>
</form>
</div>
{% endblock %}
You should use MultipleChoiceField in your forms as a widget.
'res_SF': forms.MultipleChoiceField(attrs={'class':'form-check-input'}),

Categories