Django - Saving multiple selection boxes in one form - python

I need to save multiple selections in one form, but it is not saving the values to my model. This is how the form looks:
This is my models.py
class ChoiceManager(models.Manager):
def rates (self, Task_id, rating2, yo):
assignment = Assignment.objects.get(id=Assignment_id)
rating = rating2
yo = FiscalYear.objects.get(fy_year=years)
for i in range(len(rating2)):
rated = Prog_capability.objects.create(
task = task,
rating2 = rating[i],
fy = yo[i]
)
class NewYear(models.Model):
year = models.CharField(max_length=5)
new_year = models.CharField(max_length=5)
class Choice(models.Model):
rating = models.CharField(max_length=255, blank=True, null=True)
year = models.ForeignKey(NewYear, related_name="choices")
assignment = models.ForeignKey(Assignment, related_name="choice")
objects = ChoiceManager()
This is my views.py
def task_rating(request, Assignment_id):
ratings = request.POST.getlist('rating2',[])
years= request.POST.getlist('yo",[])
rates= Choice.objects.rates(Assignment_id, ratings, years)
return redirect ((reverse('Project:assignment_page', kwargs={'Assignment_id': Assignment_id})))
HTML
<form action="{% url 'project:rating' %}" method="post">
{% csrf_token %}
{% for year in years %}
<li class=cap_select>
<div id=fyc>{{year.fy_year}}</div>
<select name="rating2" id="{{assignment.id}}-{{year.id}}">
<option>Choose From List</option>
<option class=hi value="high">High</option>
<option class=med value="medium">Medium</option>
<option class=low value="low">Low</option>
<option class=na value="n/a">N/A</option>
</select>
<input type="hidden" name="yo" value={{year.fy_year}}>
</li>
{% endfor %}
<br>
<input id=save_cap type="submit" value="Save">
</form>
I'm getting a
"NewYear matching query does not exist." and cannot save the data.
I've been on this for a couple of days. Any help will be appreciated.

Yes you are right
POST data is not coming as dictionary.
You are looping on years and rendering select and input tag inside form and the name attribute of all select and input tags are same that is rating and year simultaneously
in that case when you submit your form you will get a list of rating and year so you should use getlist() method while fetching it from request.POST QueryDict.
request.POST.getlist('rating[]')
request.POST.getlist('year[]')
if above doesn't work use it like
request.POST.getlist('rating', [])
request.POST.getlist('year', [])
Update your rates method like.
class ChoiceManager(models.Manager):
def rates (self, Assignment_id, rating, year):
...
# you can use year also to find the length
for i in range(len(rating)):
rated = Choice.create(
assignment = assignment,
year = year[i],
rating = rating[i]
)
change method call.
rates = Choice.objects.rates(Assignment_id,request.POST.getlist('rating[]'), request.POST.getlist('year[]'))

So this is what worked in the end:
models.py
class ChoiceManager(models.Manager):
def rates (self, Assignment_id, rating2, years, rating_id):
Assignment = Assignment.objects.get(id=Assignment_id)
rating = rating2
rating_id = rating_id
for i in range(len(rating2)):
year =NewYear.objects.get(fy_year=years[i])
rated = Choice.objects.create(
assignment = assignment,
rating = rating[i],
fy = year,
rating_id = rating_id[i]
)
views.py
def task_rating(request, Assignment_id):
ratings= request.POST.getlist('rating2',[])
years= request.POST.getlist('yo',[])
rating_id = request.POST.getlist('rating_id',[])
rates = Choice.objects.rates(Assignment_id,ratings, years,rating_id)
return redirect ((reverse('assignment:assignment_page', kwargs={'Assignment_id': Assignement_id})))
HTML
<form action="{% url 'project:rating' %}" method="post">
{% csrf_token %}
{% for year in years %}
<select name="rating2" id="{{assignment.id}}-{{year.id}}">
<option>Choose From List</option>
<option class=hi value="high">High</option>
<option class=med value="medium">Medium</option>
<option class=low value="low">Low</option>
<option class=na value="n/a">N/A</option>
</select>
<input type="hidden" name="yo" value={{year.fy_year}}>
<input type="hidden" name="rating_id" value="{{tasks.id}}-{{year.id}}">
{% endfor %}
<br>
<input id=save_cap type="submit" value="Save">
</form>

Related

how to get filter data between two dates in django

I am working on Django project How to get filter data between two dates I mean (from-date and to-date) mfdate is a foreign key and coming from another model. how can I do this can anyone help me to solve this problem I have tried multiple time but it is not working
here is my Code
models.py
class ManufacturingYM(models.Model):
ManufacturingYMID = models.AutoField(primary_key=True)
ManufacturingDate = models.DateField(auto_now_add=False, blank= True,null=True)
def __str__(self):
return str(self.ManufacturingDate)
class Car(models.Model):
CarID = models.AutoField(primary_key=True)
CarName = models.CharField(max_length=500, blank=True, null=True, verbose_name="Car Name")
mfdate = models.ForeignKey(ManufacturingYM, blank= True,null=True, on_delete=models.DO_NOTHING, verbose_name="Manufacturing Date")
def __str__(self):
return self.CarName
views.py
def searchdd(request):
carForm = Car.objects.all()
fromdate = str(request.POST.get('from_date'))
todate = str(request.POST.get('to_date'))
if fromdate:
carForm= Car.objects.filter(mfdate=fromdate)
if todate:
carForm= Car.objects.filter(mfdate=todate)
context = {'carForm':carForm}
return render(request, 'app/searchdd.html', context)
home.html
<form method="post" id="indexForm" action="/searchdd" data-cars-url="{% url 'ajax_load_cars' %}">
{% csrf_token %}
<div class="col-md-12">
<div class="row">
<div class="col-md-3">
<label for="" class="white">From Year</label>
<select name="from_date" id="fromdate" class="dp-list">
<option disabled selected="true" value="">--select Year--</option>
{% for mfd in manfd %}
<option value="{{car.CarID}}">{{mfd.ManufacturingDate|date:'Y'}}</option>
{% endfor %}
</select>
</div>
<div class="col-md-3">
<label for="" class="white">To Year</label>
<select name="to_date" id="todate" class="dp-list">
<option disabled selected="true" value="">--select Year--</option>
{% for mfd in manfd %}
<option value="{{car.CarID}}">{{mfd.ManufacturingDate|date:'Y'}}</option>
{% endfor %}
</select>
</div>
</div>
</div>
If from_date and get_date have as format YYY-MM-DD, then you can filter with:
def searchdd(request):
carForm = Car.objects.all()
fromdate = request.POST.get('from_date')
todate = request.POST.get('to_date')
if fromdate:
carForm = carForm.filter(mfdate__ManufacturingDate__gte=fromdate)
if todate:
carForm = carForm.filter(mfdate__ManufacturingDate__lte=todate)
context = {'carForm':carForm}
return render(request, 'app/searchdd.html', context)
If the request does not contain a from_date or to_date, then that filter is omitted. If both are thus omitted, all Cars will be returned. If to_date is 2021-1-1, then you will retrieve all Cars that have been manufactued before or on January 1st, 2021.
As for the form, you should format the items correctly, so:
<select name="from_date" id="fromdate" class="dp-list">
<option disabled selected="true" value="">--select Year--</option>
{% for mfd in manfd %}
<option value="{{ mfd.ManufacturingDate.year }}-1-1">{{mfd.ManufacturingDate|date:'Y'}}</option>
{% endfor %}
</select>
the same for the to_date, but then it is {{ mfd.ManufacturingDate.year }}-12-31.

Filtered search for MultiSelectField in Django 3

Now that I change some choice fields into multi select fields for usability. When I set up the drop down filtering for sorting using iexact with the MultipleSelectField it is no longer or not supported supported.
Is there a way to Filtered search for MultiSelectField using unique individual values to find both individual and multiple results.
Desired functionality
I am try to get to a drop down to sort with only one choice of each decade for the multiple select fields that can find. Then the search to find single or multiple select results.
Select decade
1950s
...
2000
2010
2020
Currently, the front end displays what is created for each new entry so if single of combination it creates a unique entry for each combo or single entry so its kind of ugly and messy. The .distinct() worked good when only one choice per choices but with many possibilities of combinations are now also unique. I assume the iexact no longer working for filtering.
Select decade
1950s, 1960s, 1970s
...
2000
2010, 2020
2020
In the view it search for the keyword in the field
act / views.py
# SEARCH BASED-KEYWORD
def search(request):
act = Act.objects.order_by('-created_date')
demographics_search = Act.objects.values_list('demographics', flat=True).distinct()
defaultgenre_search = Act.objects.values_list('defaultgenre', flat=True).distinct()
decade_search = Act.objects.values_list('decade', flat=True).distinct()
genre_search = Act.objects.values_list('genre', flat=True).distinct()
# if has keyword request from the url
if 'keyword' in request.GET:
keyword = request.GET['keyword']
# check if keyword is not blank, find the keyword in the whole of the description
if keyword:
act = act.filter(description__icontains=keyword)
# if has keyword request from the url
if 'demographics' in request.GET:
demographics = request.GET['demographics']
# check if keyword is not blank, find the keyword in the whole of the description
if demographics:
act = act.filter(demographics__iexact=demographics)
if 'defaultgenre' in request.GET:
defaultgenre = request.GET['defaultgenre']
# check if keyword is not blank, find the keyword in the whole of the description
if defaultgenre:
act = act.filter(defaultgenre__iexact=defaultgenre)
act / models.py
from django.db import models
from django.db.models import CharField
from django.utils import timezone
from ckeditor.fields import RichTextField
from multiselectfield import MultiSelectField
# Create your models here.
class Act(models.Model):
artists_name = models.CharField(max_length=255)
description = RichTextField(blank=True)
call_to_action = models.CharField(max_length=255)
artists_photo = models.ImageField(upload_to='photo/%y/%m/%d/')
act_page_title = models.CharField(max_length=255)
act_page_description = models.CharField(max_length=255)
act_page_keywords = models.CharField(max_length=255)
created_date = models.DateTimeField(auto_now_add=True)
defaultgenre_choices = [
('Adult Contemporary','Adult Contemporary'),
('Classic Rock','Classic Rock'),
('Country Music','Country Music'),
('Disco & Funk','Disco & Funk'),
('Trap Music', 'Trap Music'),
('Folk Music', 'Folk Music'),
('Singer / Songwriter', 'Singer / Songwriter'),
('Latin Music', 'Latin Music'),
]
defaultgenre = models.CharField(
choices= defaultgenre_choices,
max_length= 100,)
decades_choices = [
(1,'1950s'),
(2,'1960s'),
(3,'1970s'),
(4,'1980s'),
(5,'1990s'),
(6,'2000s'),
(7,'2010s'),
(8,'2020s'),
]
decade = MultiSelectField(max_length=100,
choices= decades_choices,)
def __str__(self):
return self.artists_name
home.html
<div class="search-box-4 sb-8">
<form action="{% url 'search' %}" method="">
<div class="form-group">
<input type="text" name="keyword" placeholder="Search by name" class="form-control">
</div>
<div class="form-group">
<select class="form-control search-fields" name="demographics">
<option selected="true" disabled="disabled">Demographics</option>
{% for demographics in demographics_search %}
<option value= "{{demographics}}">{{demographics}}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<select class="form-control search-fields" name="defaultgenre">
<option selected="true" disabled="disabled">Default Genres</option>
{% for defaultgenre in defaultgenre_search %}
<option value= "{{defaultgenre}}">{{defaultgenre}}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<select class="form-control search-fields" name="decade">
<option selected="true" disabled="disabled">Decade</option>
{% for decade in decade_search %}
<option value= "{{decade}}">{{decade}}</option>
{% endfor %}
</select>
</div>
Not working with multiselectfeild
Working without multiselectfield
According your decades_choices:
decades_choices = [
(1,'1950s'),(2,'1960s'),(3,'1970s'),(4,'1980s'),
(5,'1990s'),(6,'2000s'),(7,'2010s'),(8,'2020s'),
]
I assume that your values look like this:
<div class="form-group">
<select class="form-control search-fields" name="decade">
<option selected="true" disabled="disabled">Decade</option>
<option value="7, 8">2010s, 2020s</option>
<option value="8">2020s</option>
</select>
</div>
Then to filter by decade you have to do so:
decade = request.GET.get("decade")
if decade:
# convert string to list
decade = decade.split(",")
act = act.filter(decade=decade)

Django filtering using multiple queries

On my homepage I have a search bar and when you search something it redirects you to a page with the results(titles and document types). On the left side of the page I want to implement a filter by document type.
After the search my url looks like this: http://127.0.0.1:8000/search/?q=something
After applying the filter: http://127.0.0.1:8000/search/?document_type=Tehnical+report
I don't know how to implement the filters to search just in the objects list filtered by the query (q) on the search page. Also, I'm not sure if the url should look like this : http://127.0.0.1:8000/search/?q=something&document_type=Tehnical+report or like this http://127.0.0.1:8000/search/?document_type=Tehnical+report after applying the filter.
models.py
DOCUMENT_TYPES = [
('Tehnical report','Tehnical report'),
('Bachelor thesis','Bachelor thesis'),
...
]
class Form_Data(models.Model):
title = models.CharField(unique=True, max_length=100, blank=False)
author = models.CharField(max_length=100)
document_type = models.CharField(choices=DOCUMENT_TYPES, max_length=255, blank=False, default=None)
views.py
def search_list(request):
object_list = Form_Data.objects.none()
document_types = DOCUMENT_TYPES
query = request.GET.get('q')
query_list = re.split("\s|(?<!\d)[,.](?!\d)", query)
document_type_query = request.GET.get('document_type')
for item in query_list:
object_list |= Form_Data.objects.filter( Q(title__icontains=item) | Q(author__icontains=item))
return render(request, "Home_Page/search_results.html")
home_page.html
<div class="Search">
<form action="{% url 'home_page:search_results' %}" method="get">
<input id="Search_Bar" type="text" name="q">
<button id="Button_Search" type="submit"></button>
</form>
</div>
search_results.html
{% for form_data in object_list %}
<h5>{{ form_data.title }}</h5>
<h5>{{ form_data.document_type }}</h5>
{% endfor %}
<form method="GET" action=".">
<select class="form-control" name="document_type">
{% for tag, label in document_types %}
<option value="{{ tag }}">{{ tag }}</option>
{% endfor %}
</select>
</form>
In my opinion you are doing it the wrong way... I mean I didn't understand why you are looping your query for filtering. As far as I know it was looping every letters of your query.
I was doing it I would do it like this (using my own example):
<form action='{% url 'products:search' %}' method='get'>
<input type='text' name='q' id='search' value='' >
<select name='category' id='category'>
<option value='' selected ></option>
<option value='packet'>Packet</option>
<option value='food'>Food</option>
<option value='vegetable'>Vegetable</option>
</select>
<input type='button' value='submit' >
</form>
views.py:
def search(request):
products = None
query = request.GET.get('q')
category = request.GET.get('category')
if query:
products = Product.objects.filter(
Q(name__icontains=query)|
Q(brand__icontains=query)
)
if category:
# since it is a choice field in the model
products |= Products.objects.filter(category=category)
context = {
'products': products,
}
return render(request, 'products/search_products.html', context)
in this case if I press the submit button I would get a url like:
http://localhost:8000/products/search/?q=something&category=food
with this data I can filter products by name or any other fields I want.
I don't see any instance where someone would enter their query and search result will have all the products that has any of the letters entered in the input field.
This would be the model filtering:
query = request.GET.get('q')
document_type_query = request.GET.get('document_type')
object_list = FormData.objects.none()
for item in query.split():
item_qs = FormData.objects.filter(Q(title__icontains=item) | Q(author__icontains=item))
if document_type_query:
item_qs = item_qs.filter(document_type=document_type_query)
object_list |= item_qs
return render(request, "Home_Page/search_results.html", {"object_list": object_list})
And this is the URL:
http://127.0.0.1:8000/search/?q=something%20with%20spaces&document_type=Tehnical+report

Filtering items using drop down list

Would like to filter features(products) by using dropdown menu. Each of the feature(product) got a tag (e.g. food, drink, random). Idea is when user selects the tag on a menu, it shows only those items who's got that tag.
So far I went as far, but doesn't seem to work yet. PyCharm does not give an error, but not functioning. What I am missing? Thank you!
my models.py
class Feature(models.Model):
FOOD = 'food'
DRINK = 'drink'
RANDOM = 'random'
TAGS = (
(FOOD, 'food'),
(DRINK, 'drink'),
(RANDOM, 'random')
)
name = models.CharField(max_length=40, default='')
tags = models.CharField(max_length=20, choices=TAGS, default=ALL)
def __str__(self):
return self.name
my views.py
def tags(request):
if request.GET.get('tags'):
features_filter = request.GET.get('tags')
listings = Feature.objects.filter(features_filter=features_filter)
else:
listings = Feature.objects.all()
context = {'listings': listings}
return render(request, 'index', context)
my index.html
<form action="{% url 'index' %}" method="get" accept-charset="utf-8">
{% csrf_token %}
<select name="tags">
{% for feat in features %}
<option value="{{feat.tags}}">{{ feat.tags }}</option>
{% endfor %}
</select>
<input type="submit" value="submit">
</form>
{% for feature in features %}
<h1{{ feature.name }}</strong></h1>
{% endfor %}
Try changing this
listings = Feature.objects.filter(features_filter=features_filter)
to
listings = Feature.objects.filter(tags=features_filter)

Transferring from Database to django dropbox

I am trying to fill a dropbox with values from my database using Django and HTML. I have been trying to figure out how for hours but it is not updating.
Here is the HTML code:
<select id = "classChoice" >
<option value = "base"> ----- </option>
{% for class.name in objectlist %}
<option value = "class.name"> {{ class.name }} </option>
{% endfor %}
</select>
Here is the forms.py:
class searchPageForm(forms.Form):
className = forms.ModelChoiceField(queryset= Classroom.objects.all())
studentName = forms.CharField(max_length=120)
studentID = forms.CharField(max_length=20)
Here is the views.py:
def search(request):
form = searchPageForm()
if request.GET.get('class.name'):
featured_filter = request.GET.get('class.name')
objectlist = searchPageForm.objects.all()
return render(request, 'pollingSite/search.html', {'objectlist': objectlist})
else:
classNames = Classroom.objects.filter(instructor = request.user)
return render(request, 'pollingSite/search.html', locals())
I am stuck and have tried everything and it's just not populating.
In your html page, the {% for object in objectlist %} means that it will iterate over the objectlist and assign each object in the list to object. This means that you can access the attributes of Classroom using the instance object. So change the html as follows:
<select id="classChoice">
<option value = "base"> ----- </option>
{% for object in objectlist %} <!-- You were making mistake here -->
<option value = "{{ object.id }}"> {{ object.name }} </option>
{% endfor %}
</select>
And in your forms.py:
class searchPageForm(forms.Form):
className = forms.CharField(max_length=120)
studentName = forms.CharField(max_length=120)
studentID = forms.CharField(max_length=20)

Categories