Django dynamic Search View based on filled GET request keys - python

please how is possible in Django to reach a view, which will be filtering based on filled keys from GET request?
I am using only one search view, but two forms:
I am taking these requests:
q = request.GET.get('q') # this is for VIN and LOT number (two columns in Model/DB)
make = request.GET.get('make')
model = request.GET.get('model')
year_from = request.GET.get('year_from')
year_to = request.GET.get('year_from')
There are no required fields/requests, so it should work dynamically. If the user fills "q" - it will filter out by VIN or LOT number.
If the user will fill Make and Year, it will filter out by make and to year...
How is possible to do this, some better way, than if , elif, elif, elif, ... Is there any proper way, please?
This is my solution, but I really dont like it, it is not professional and I don't know, how to find a better solution
def is_valid_queryparam(param):
return param != '' and param is not None
def search_filer(request):
qs = Vehicle.objects.all()
# VIN and Lot number
q = request.GET.get('q')
make = request.GET.get('make')
model = request.GET.get('model')
year_from = request.GET.get('year_from')
year_to = request.GET.get('year_from')
if is_valid_queryparam(q):
qs = qs.filter(Q(vin__icontains=q) | Q(lot_number__icontains=q))
elif is_valid_queryparam(make):
qs = qs.filter(make__name__exact=make)
elif is_valid_queryparam(model):
qs = qs.filter(model__name__exact=model)
elif is_valid_queryparam(year_from):
qs = qs.filter(year__gte=year_from)
elif is_valid_queryparam(year_to):
qs = qs.filter(year__lte=year_to)
elif is_valid_queryparam(make) and is_valid_queryparam(model):
qs = qs.filter(make__name__exact=make)\
.filter(model__name__exact=model)
elif is_valid_queryparam(make) and is_valid_queryparam(model) and is_valid_queryparam(year_from):
qs = qs.filter(make__name__exact=make)\
.filter(model__name__exact=model)\
.filter(year__gte=year_from)
elif is_valid_queryparam(make) and is_valid_queryparam(model)\
and is_valid_queryparam(year_from) and is_valid_queryparam(year_to):
qs = qs.filter(make__name__exact=make)\
.filter(model__name__exact=model)\
.filter(year__gte=year_from)\
.filter(year__lte=year_to)
...
...
...
return qs
def search_view(request):
qs = search_filer(request)
# Year field for search form
today = datetime.now()
context = {
'queryset': qs,
'years_from': reversed(range(1920, today.year + 1)),
'years_to': reversed(range(1920, today.year + 1))
}
return render(request, 'search.html', context)
Thank you for any advice!
And also I don know, why context is not reusable, as you can see, I have created two variables years_from and years_to because I am looping through them in the template:
<option value>From ...</option>
{% for y in years_from %}
<option value="{{ y }}">{{ y }}</option>
{% endfor %}
<option value>To ...</option>
{% for y in years_to %}
<option value="{{ y }}">{{ y }}</option>
{% endfor %}
When I tried to create only a one-year variable and loop through in template, it was working. But when I created another loop with the same variable, no values were shown. So I have created exact same variable and looped.
Thank you very much!

I have figured out, how to solve that. It is really not professional, but it does the desired work. I will be glad for any advice or hints, to make my code better. If someone will be trying something like me, here is my solution:
def is_valid_queryparam(param):
return param != '' and param is not None
def is_valid_name(name):
return name == 'make' or name == 'model' or name == 'year_from' or name == 'year_to'
def get_filter(key):
if key == 'make':
return 'make__name__exact'
if key == 'model':
return 'model__name__exact'
if key == 'year_from':
return 'year__gte'
if key == 'year_to':
return'year__lte'
def search_view(request):
queryset = None
valid_params = False
# VIN and LOT number
q = request.GET.get('q')
if is_valid_queryparam(q):
queryset = Vehicle.objects.filter(Q(vin__icontains=q) | Q(lot_number__icontains=q))
else:
request_filter = {}
q_list = Q()
for key, value in request.GET.items():
if is_valid_name(key) and is_valid_queryparam(value):
valid_params = True
request_filter[get_filter(key)] = value
if valid_params:
for k, v in request_filter.items():
q_list.add(Q(**{k: v}), Q.AND)
queryset = Vehicle.objects.filter(q_list)
# Year field for search form
today = datetime.now()
years_from = reversed(range(1920, today.year + 1))
years_to = reversed(range(1920, today.year + 1))
context = {
'queryset': queryset,
'years_from': years_from,
'years_to': years_to
}
return render(request, 'search.html', context)

Related

django - how do i use an input from a select form to compare data in my database and output it on another page?

<form method = "POST">
{% csrf_token %}
<div class = "lookback"
<label for = "time"></label>
<select name = "time" id = "time">
<option value = "today">Today</option>
<option value = "yesterday">Yesterday</option>
<option value = "lastweek">Last Week</option>
<option value = "lastmonth">Last Month</option>
<option value = "lastyear">Last Year</option>
<option value = "forever">Forever</option>
</select>
<button><a type= "button" class = "Look" id = "look" href = "">Look Back?!</a></button>
</form>
** Above is the portion of HTML page i am using to get the select value so that I can use it in my views.py to filter out the data and output it on another page. **
def retro(request):
if request.method == "POST":
time = ThoughtForm(request.POST)
today = timezone.now().date()
if time == "Yesterday":
yesterday = timezone.now().date() - timedelta(days=1)
data = Thought.objects.filter(date__gte=yesterday, date__lt=today)
elif time == "Last Week":
week = timezone.now().date() - timedelta(days=7)
data = Thought.objects.filter(date__gte=week, date__lt=today)
elif time == "Last Month":
month = timezone.now().date() - timedelta(days=30)
data = Thought.objects.filter(date__gte=month, date__lt=today)
elif time == "Last Year":
year = timezone.now().date() - timedelta(days=365)
data = Thought.objects.filter(date__gte=year, date__lt=today)
elif time == "Forever":
data = Thought.objects.all
else:
data = Thought.objects.filter(date__gte=today, date__lt=today)
return render(request,'look.html', {'data' : data})
else:
return render(request, 'retro.html')
When I use the submit button of the retro.html (the one with the select input), it does direct me to the page I want to output my data to. However, it does not print the data in the page.
<div class = "results">
<form method = "GET" >
<h1>Till now, you thought of writing- </h1>
<table class="table">
<thead class = "thead-dark">
<tr>
<td>Thought</td>
<td>Date</td>
</tr>
</thead>
<tbody>
{% for obj in data%}
<tr>
<td scope="row">{{ obj.thought }}</td>
<td>{{ obj.date.date}}</td>
</tr>
{% endfor %}
Directly above is the html for the page I am trying to output my data in.
from django.db import models
from django.utils import timezone
# Create your models here.
class Thought(models.Model):
thought = models.CharField( max_length=300)
done = models.BooleanField(default = False)
#date = models.models.DateField()
date = models.DateTimeField(default=timezone.now)
def __str__(self):
return str(self.thought) + "- " + str(self.done)
Directly above is my models.py file.
from django import forms
from retrospection.models import Thought
class ThoughtForm(forms.ModelForm):
class Meta:
model = Thought
fields = ['thought', 'done', 'date']
Directly above is my form.py file.
After trying what Blackeagle52 suggested and by printing(form.is_valid()), I found out that my form is failing the is_valid test with an error -
<ul class="errorlist"><li>thought<ul class="errorlist"><li>This field is required.</li></ul></li><li>date<ul class="errorlist"><li>This field is required.</li></ul></li></ul>
My form contains a select item with a few options and a submit button. I am not sure how the field can be empty. Please help me.
def retro(request):
if request.method == "POST":
form = ThoughtForm(request.POST)
if form.is_valid():
time = form.cleaned_data['time']
today = timezone.now().date()
if time == "Yesterday":
yesterday = timezone.now().date() - timedelta(days=1)
data = Thought.objects.filter(date__gte=yesterday, date__lt=today)
elif time == "Last Week":
week = timezone.now().date() - timedelta(days=7)
data = Thought.objects.filter(date__gte=week, date__lt=today)
elif time == "Last Month":
month = timezone.now().date() - timedelta(days=30)
data = Thought.objects.filter(date__gte=month, date__lt=today)
elif time == "Last Year":
year = timezone.now().date() - timedelta(days=365)
data = Thought.objects.filter(date__gte=year, date__lt=today)
elif time == "Forever":
data = Thought.objects.all
else:
data = Thought.objects.filter(date__gte=today, date__lt=today)
return render(request,'look.html', {'data' : data})
# TODO Do something when form is invalid.
# Maybe just removing the else below this, so you'll get retro.html
else:
return render(request, 'retro.html')
To explain my solution, in your code time was not a value, but a Form.
To retrieve the data from the form, you first need to check whether the form is valid (is_valid()) and than retrieve the value from form.cleaned_data.
There are some other minor things you could improve. After a POST, redirect to another view, as now this look.html is only visible on a POST. If you want to refresh that page or something, you'll be back at retro.html.
With the Forever-case, you are also missing () on your .all() call.

Django ordering search results from get_queryset(self)

I am using django 2.2.10. I have a searchbar which returns search results to the showpage, using get_queryset(self) in searchresultsview(listview) class. I have set paginate_by=10. In the front-end I made links to order the table: `
<th>Title original </th>
At the start of the get_queryset(self) function I have the following code:
order_by = self.request.GET.get('order_by')
direction = self.request.GET.get('direction')
if order_by is not None and order_by != "" and direction is not None and direction != "":
ordering = Lower(order_by)
if direction == 'desc':
ordering = '-{}'.format(ordering)
publications = Publication.objects.filter(is_deleted=False).order_by(ordering)
'''
paginator = Paginator(publications, 10)
page = self.request.GET.get('page')
try:
all_publications = paginator.page(page)
except PageNotAnInteger:
all_publications = paginator.page(1)
except EmptyPage:
all_publications = paginator.page(paginator.num_pages)
'''
return publications
The main problem is that the publications variable contain all publications, I want to restrict it to the publications from the previous get_queryset(self) call. Also the showpage is paginated (paginate_by = 10 in template).The ordering for descending does not work I get: invalid order_by arguments: ['-Lower(F(title_original))'] . If I order ascending it logically does not keep my search results.
I tried finding a stackoverflow solution but the explanation is minimal. Any help would be appreciated.
It might be easier to use django-tables, if so I am open for suggestions.
view codes:
class SearchResultsView(ListView):
'''
ListView of the initial search page.
The function get_queryset works for the search bar and the search form home page.
The search bar typically uses q for query otherwise a id for list search.
Use a countries_dict to convert for example Netherlands to NL so that search succeeds.
If a normal field is searched use __icontains if a list element is searched use: __in.
'''
model = Publication
template_name = 'publications/show.html'
context_object_name = 'publications'
publications = Publication.objects.filter(is_deleted=False)
#paginator = Paginator(publications, 10)
#paginator = Paginator(publications, 25)
paginate_by = 10
def get_ordering(self):
order_by = self.request.GET.get('order_by')
direction = self.request.GET.get('direction')
if order_by is not None and order_by != "" and direction is not None and direction != "":
ordering = Lower(order_by)
if direction == 'desc':
ordering = '-{}'.format(ordering)
return ordering
def get_queryset(self):
#form = PublicationForm(self.request.GET)
authors = self.request.GET.getlist('author')
translators = self.request.GET.getlist('translator')
authors = Author.objects.filter(pk__in=authors).all()
translators = Translator.objects.filter(pk__in=translators).all()
form_of_publications = self.request.GET.getlist('form_of_publication')
form_of_publications = FormOfPublication.objects.filter(pk__in=form_of_publications).all()
languages = self.request.GET.getlist('language')
languages = Language.objects.filter(pk__in=languages).all()
affiliated_churches = self.request.GET.getlist('affiliated_church')
affiliated_churches = Church.objects.filter(pk__in=affiliated_churches).all()
content_genres = self.request.GET.getlist('content_genre')
content_genres = Genre.objects.filter(pk__in=content_genres).all()
connected_to_special_occasions = self.request.GET.getlist('connected_to_special_occasion')
connected_to_special_occasions = SpecialOccasion.objects.filter(pk__in=connected_to_special_occasions).all()
currently_owned_by = self.request.GET.getlist('currently_owned_by')
currently_owned_by = Owner.objects.filter(pk__in=currently_owned_by).all()
copyrights = self.request.GET.get('copyrights')
is_a_translation = self.request.GET.get('is_a_translation')
publications = Publication.objects.filter(is_deleted=False)
uploadedfiles = self.request.GET.getlist('uploadedfiles')
uploadedfiles = UploadedFile.objects.filter(pk__in=uploadedfiles).all()
keywords = self.request.GET.getlist('keywords')
keywords = Keyword.objects.filter(pk__in=keywords).all()
translated_from = self.request.GET.getlist('translated_From')
translated_from = Language.objects.filter(pk__in=translated_from).all()
city = self.request.GET.getlist('publication_city')
country = self.request.GET.getlist('publication_country')
collection_country = self.request.GET.getlist('collection_country')
if list(collection_country) != ['']:
collection_country = Country.objects.filter(pk__in=city).all()
if list(country) != ['']:
country = Country.objects.filter(pk__in=city).all()
print('....', city)
if list(city) != ['']:
city = City.objects.filter(pk__in=city).all()
print(publications)
exclude = ['csrfmiddlewaretoken','search']
in_variables = [('author', authors), ('translator', translators), ('form_of_publication', form_of_publications), ('language',languages), ('affiliated_church', affiliated_churches) \
, ('content_genre', content_genres), ('connected_to_special_occasion', connected_to_special_occasions), ('currently_owned_by', currently_owned_by),\
('uploadedfiles', uploadedfiles), ('publication_country', country), ('publication_city', city), ('collection_country', collection_country), ('keywords', keywords), ('translated_from',translated_from)]
special_case = ['copyrights', 'page', 'is_a_translation']
if ('q' in self.request.GET) and self.request.GET['q'].strip():
query_string = self.request.GET['q']
if query_string.lower() in countries_dict.keys():
query_string = countries_dict[query_string.lower()]
search_fields = ['title_original', 'title_subtitle_transcription', 'title_subtitle_European', 'title_translation', 'author__name', 'author__name_original_language', 'author__extra_info', \
'form_of_publication__name', 'editor', 'printed_by', 'published_by', 'publication_date', 'publication_country__name', 'publication_city__name', 'publishing_organisation', 'translator__name', 'translator__name_original_language', 'translator__extra_info', \
'language__name', 'language__direction', 'affiliated_church__name', 'extra_info', 'content_genre__name', 'connected_to_special_occasion__name', 'donor', 'content_description', 'description_of_illustration', \
'nr_of_pages', 'collection_date', 'collection_country__name', 'collection_venue_and_city', 'contact_telephone_number', 'contact_email', 'contact_website', \
'currently_owned_by__name', 'uploadedfiles__description', 'uploadedfiles__uploaded_at', 'general_comments', 'team_comments', 'other_comments', 'keywords__name', 'is_a_translation', 'ISBN_number', 'translated_from__name', 'translated_from__direction']
arabic_query = translator.translate(query_string, dest='ar').text
query_string = to_searchable(query_string)
#arabic_query = to_searchable(arabic_query)
entry_query = get_query(query_string, search_fields)
arabic_query = get_query(arabic_query, search_fields)
print('&&&&&&', query_string)
#publications = publications.filter(entry_query)
publications = publications.filter(Q(entry_query) | Q(arabic_query))
print(publications)
publications = publications.distinct()
return publications
for field_name in self.request.GET:
get_value = self.request.GET.get(field_name)
if get_value != "" and not field_name in exclude and not field_name in [i[0] for i in in_variables] and\
not field_name in special_case:
print('******', field_name)
arabic_query = translator.translate(get_value, dest='ar').text
get_value = to_searchable(get_value)
get_value = get_query(get_value, [field_name])
arabic_query = get_query(arabic_query, [field_name])
print('444444444', get_value)
publications = publications.filter(Q(get_value) | Q(arabic_query))
print('55555555555', publications)
#publications = publications.filter(Q(**{field_name+'__regex':get_value}) | Q(**{field_name+'__icontains':arabic_query}) )
for field_name, list_object in in_variables:
print('****', list_object)
if list_object:
print('------', field_name)
if list(list_object) != ['']:
publications = publications.filter(**{field_name+'__in': list_object})
if str(copyrights) != "unknown" and str(copyrights) != "None":
val = False
if str(copyrights) == "yes":
val = True
print('11111', str(copyrights))
publications = publications.filter(copyrights=val)
print('666666', publications)
if str(is_a_translation) != "unknown" and str(is_a_translation) != "None":
val = False
if str(is_a_translation) == "yes":
val = True
print('11111', str(is_a_translation))
publications = publications.filter(is_a_translation=val)
publications = publications.distinct()
return publications
You can use get_ordering method
def get_ordering(self):
ordering = self.request.GET.get('ordering', ''#default order param)
return ordering
I solved this. Basically if you have a get_queryset method you need to call get_ordering from there. Also for pagination you need to have the sorting variables in context so that if you go to page 2 for example, the ordering is maintained. Below is the solution code:
ordering = self.get_ordering()
if ordering is not None and ordering != "":
publications = publications.order_by(ordering)
return publications
def get_context_data(self, **kwargs):
context = super(SearchResultsView, self).get_context_data(**kwargs)
order_by = self.request.GET.get('order_by')
if order_by is not None and order_by != "":
context['order_by'] = order_by
context['direction'] = self.request.GET.get('direction')
else:
context['order_by'] = ''
context['direction'] = ''
q = self.request.GET.get('q')
if q is not None and q != "":
context['q'] = q
else:
context['q'] = ''
return context
And the html code:
{% extends "base.html" %}
{% block content %}
<table class="table table-striped table-bordered table-sm">
<thead class="thead-light">
<tr>
<th>Title original </th>
<th>Title subtitle transcription </th>
<th>Title translation </th></th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<br />
{% for publication in publications %}
<tr id="publications">
<td style="text-align: start;unicode-bidi: plaintext;">{{ publication.title_original }}</td>
<td>{{ publication.title_subtitle_transcription}}</td>
<td>{{ publication.title_translation }}</td>
<td>
View
<span class="glyphicon glyphicon-pencil" >Edit</span>
<a class="confirm-delete-pub" href="/publication/{{ publication.id }}/delete">Delete</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="pagination">
<span class="step-links">
{% if page_obj.has_previous %}
« first
previous
{% endif %}
<span class="current">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
</span>
{% if page_obj.has_next %}
next
last »
{% endif %}
</span>
</div>
{% endblock %}

Tell what model a queryset is from in the template

I am creating a list containing items from two different models and passing it to my template. Here is my view function:
def newsfeed(request):
Text = Post.objects.all().order_by('-Timestamp')
Images = ImagePost.objects.all().order_by('-Timestamp')
Posts = []
while True:
if Text[0].Timestamp >= Images[0].Timestamp:
Posts.append(Post.objects.get(id=Text[0].id))
Text = Text.exclude(id=Text[0].id)
else:
Posts.append(ImagePost.objects.get(id=Images[0].id))
Images = Images.exclude(id=Images[0].id)
if len(Text) == 0:
for i in Images:
Posts.append(i)
break
elif len(Images) == 0:
for i in Text:
Posts.append(i)
break
print(Posts[:6])
return render(request, 'campaign/newsfeed.html', {
"posts": Posts,
})
I need a way to find out which model each item in the list was from in the template so that I know how to render the item. Is there a way to tell without sending further data to the template?
You can give both models (or their common super class) a method:
def model_name(self):
return self.__class__.__name__
And in the template, you can check:
{% for p in posts %}
{% if p.model_name == 'ImagePost'%}
# ...
{% endif%}
{% endfor %}
If these are models from third-party packages, you can always just set attributes in the view:
for i in Images:
i.model_name = 'ImagePost'
Posts.append(i)

Django form: Argument must be a string or a number, not 'method'

When trying to add validation to my form self.cleaned_data['field'] and cleaned_data = super(MyForm, self).clean() both seem to return 'method' variables.
When trying the following validation I encountered TypeError: float() argument must be a string or a number, not 'method'.
Similar errors also appear with no custom validation.
forms.py:
class EntryForm(forms.ModelForm):
class Meta:
model = Entry
fields = ['row_control', 'date', 'hours']
def clean(self):
clean_data = super(EntryForm, self).clean()
hours = clean_data.get("hours")
if float(hours) <= 0.00:
raise forms.ValidationError("Hours worked must be more than 0.")
# Always return cleaned data
return clean_data
The DEBUG page shows the local variables on if float(hours) <= 0.00: line to be:
__class__ <class 'timesheet.forms.EntryForm'>
hours <bound method Field.clean of <django.forms.fields.DecimalField object at 0x1066ca668>>
self <EntryForm bound=True, valid=True, fields=(row_control;date;hours)>
clean_data {'date': <bound method Field.clean of <django.forms.fields.DateField object at 0x106649fd0>>,'hours': <bound method Field.clean of <django.forms.fields.DecimalField object at 0x1066ca668>>,'row_control': <bound method Field.clean of <django.forms.models.ModelChoiceField object at 0x106804668>>}
This is the context it is being used in.
views.py:
#login_required
def monthview(request, year, month):
# Initialise forms
row_control_form = RowControlForm(initial={'month_control_record': month_control_record})
entry_form = EntryForm()
# Making form fields hidden
entry_form.fields['row_control'].widget = forms.HiddenInput()
entry_form.fields['date'].widget = forms.HiddenInput()
row_control_form.fields['month_control_record'].widget = forms.HiddenInput()
# If user has submitted a form
if request.method == 'POST':
# If user submits row_control form
if 'row_control_submit' in request.POST:
instance_pk = request.POST["instance"]
try:
row_control_form = RowControlForm(request.POST, instance=RowControl.objects.get(pk=instance_pk))
except ValueError:
row_control_form = RowControlForm(request.POST)
if row_control_form.is_valid():
row_control_form.save()
elif 'entry_submit' in request.POST:
instance_pk = request.POST["instance"]
try:
entry_form = EntryForm(request.POST, instance=Entry.objects.get(pk=instance_pk))
except ValueError:
entry_form = EntryForm(request.POST)
if entry_form.is_valid():
entry_form.save()
return redirect('/' + year + '/' + month + '/')
if request.is_ajax():
rawrow = request.GET['row']
rawday = request.GET['day']
# Get the employee model for the user signed in
employee = Employee.objects.get(user=request.user)
# Get the first day of the month from URL
first_day_of_month = datetime.date(int(year), int(month), 1)
# Get the month_control_record for the user logged in and for the month
month_control_record = MonthControlRecord.objects.get(employee=employee, first_day_of_month=first_day_of_month)
the_row_control = RowControl.objects.filter(month_control_record=month_control_record);
if int(rawday) > 0:
the_row_control = the_row_control[int(rawrow)]
date = str(year) + '-' + str(month) + '-' + str(rawday)
try:
the_entry = Entry.objects.get(row_control=the_row_control, date=date)
instance = the_entry.pk
hours = str(the_entry.hours)
except Entry.DoesNotExist:
instance = None
hours = None
the_row_control = the_row_control.pk
data = {
'form': "entry",
'row_control': the_row_control,
'date': date,
'hours': hours,
'instance': instance,
}
data = json.dumps(data)
else:
instance = the_row_control[int(rawrow)]
departments = Department.objects.all()
departmentno = index_number_of_object(departments, instance.department) + 1
activites = Activity.objects.all()
activityno = index_number_of_object(activites, instance.activity) + 1
notes = instance.notes
data = {
'form': "row_control",
'department': departmentno,
'activity': activityno,
'instance': instance.pk,
'notes': notes,
}
print(data)
data = json.dumps(data)
return HttpResponse(data)
context = {
'row_control_form': row_control_form,
'entry_form': entry_form,
'year': year,
'month': month,
}
return render(request, "timesheet/monthview.html", context)
template.html:
<div class="" id="entry-form-container">
<form action="{{ request.path }}" class="form-inline" method=
"post">
{% csrf_token %}
{{ entry_form|crispy }}
<input id="entry_instance" name="instance" type="hidden">
<button class="btn btn-primary" name="entry_submit" type="submit" value="Submit">
<i class="fa fa-floppy-o"></i> Save
</button>
</form>
</div>
EDIT: Removed custom validation and the form is completely failing to validate, removed validation from title.
Not quite sure what / where I went wrong but this works:
forms.py:
class EntryForm(forms.ModelForm):
class Meta:
model = Entry
fields = ['row_control', 'date', 'hours']
def clean(self):
cleaned_data = self.cleaned_data
if cleaned_data['hours'] <= 0:
raise forms.ValidationError("Hours worked must be more than 0.")
# Always return cleaned data
return cleaned_data

Django form search

I am making a search form in django, and I am struggling with processing the form in my view.
My code:
class SearchForm(forms.Form):
name = forms.CharField(label="Name", max_length=64, required=False)
...
<a few other fields>
def search(request):
if request.method == 'POST':
form = SearchForm(request.POST)
if form.is_valid():
name = form.cleaned_data['name']
qdict = { 'name': name}
q_objs = [Q(**{qdict[k]: form.cleaned_data[k]}) for k in qdict.keys() if form.cleaned_data.get(k, None)]
search_results = Group.objects.select_related().filter(*q_objs)
response = {'success' : search_results}
return HttpResponse(simplejson.dumps(response, ensure_ascii=False), mimetype='application/javascript')
else:
form = SearchForm()
return render_to_response("main/search.html", {'form': form},
context_instance=RequestContext(request))
I get this error:
Cannot resolve keyword u'NAME' into field. Choices are: date_submitted, id, name, parameters.
I realized that this field is in unicode and tried converting it with str(...) or with encode('ascii',...), but it still gives me the same error. I am new to django, so any help would be appreciated.
Thanks
To find your error code replace this code:
name = form.cleaned_data['name']
qdict = { 'name': name}
q_objs = [Q(**{qdict[k]: form.cleaned_data[k]}) for k in qdict.keys() if form.cleaned_data.get(k, None)]
search_results = Group.objects.select_related().filter(*q_objs)
By this one:
q=None
for k,v in form.cleaned_data.items():
if q:
q &= Q( k = v )
else:
q = Q( k = v )
search_results = Group.objects.select_related().filter( q )
But, to have really control over your query, you need to write condition by condition:
qs = []
name = form.cleaned_data['name']
if name:
q_name = Q( name__contains = name )
qs.append(q_name)
fromDate = form.cleaned_data['fromDate']
if fromDate:
q_from = Q( date__gte = fromDate )
qs.append(q_from)
toDate = form.cleaned_data['toDate']
if toDate:
q_toDate = Q( date__gte = toDate )
qs.append(q_toDate)
q=None
for x in qs:
if q:
q &= x
else:
q = x
search_results = Group.objects.select_related().filter(q)
It complains about the (uppercase) NAME field, and judging by the error message's format, it is the query that triggers it. I can't really tell from your code, but at some point I think you execute the equivalent of the following:
Group.objects.filter(NAME='some_value')
If the Group model (which you didn't post, so this is an educated guess) contains a lowercase name field, the above query will generate the error you posted as it tries to access the uppercase NAME field.
So I guess it boils down to: what does the final query look like? For getting information on that, danihp's comment already provided a good breakdown for how to determine this.

Categories

Resources