Django Submit Form and keep searchresults - python

I'm using Django for a page in which the user can search for images and add them to a list.
On the top, there is a dropdown with all available lists, and in the pages "body" there is a search form where the user can search for images by tag.
<form action="{% url 'qwe:search' %}" method="get">
{% csrf_token %}
<input type="text" name="q" placeholder="Search..." {% if query_string %} value="{{query_string}}" {% endif %}>
<input type="submit" value="Search">
</form>
On submit, the user gets the same page with a list of search results.
def search(request):
query_string = request.GET["q"]
if (query_string == None):
return HttpResponseBadRequest()
search_results_list = img_search(query_string, max_results=25)
list_list = helpers.get_lists()
context = {"search_results_list" : search_results_list, "query_string" : request.GET["q"], "lists " : list_list }
return render(request, 'qwe/index.html', context)
I want the user to be able to create other lists, so I added a button next to the dropdown. When the user clicks on it, it opens a dialog (div) with a form containing an input for the new lists name.
The Problem:
What is the best way, to submit the form for creating a new list, without losing the search results?
I do this mainly for learning purposes, so every hint is welcome.
Thank you.

The most obvious way that I can think of is to create an <input type="hidden" \> as part of your form, whose value is the query_string. This would allow the server to know, when it receives the form details, what the original search query was.
In fact, assuming search_results_list is serializable (I would guess it is, but your code gives no idea as to what is in it), you could serialize it and send that string as a hidden input - that way you are transmitting the actual search results, rather than just the query that led to them.

Related

How to get data from a form written directly in the template not in forms.py?

I have a page with images and I want to be able to delete some of them so I wrote this form:
<form method="post">
{% for img in images %}
<img src={{img.image.url}}>
<input type="checkbox" id={{img.id}} value={{img.id}}>
{% endfor %}
<button type="submit">DELETE</button>
</form>
and this the views.py:
def lemqes(request, iid):
images = IMAGE.objects.filter(id=iid)
if request.method == 'POST':
#how can I continue to delete multiple images
return render(request, 'del.html', {'images' : images})
EDIT: when I add the name inside the input in html like <input type="checkbox" id={{img.id}} value={{img.id}} name='dadata'> and in the views.py I added print(request.POST.get('dadata')) it only printed the first value, so my question how to to get all the values checked?
you cannot get values by name because every checkbox contains the same name.
you need to call script while any checkbox gets clicked.
get its value and store it in a list.
every time list gets updated then send this list into hidden input of the form.
you can get a list of all checkboxes while submitting the form
or you can refer to this link
get group of checkboxes
I found a better solution, I replaced the checkbox with a button, and when I click the button the image id gets stored in a hidden input attribute and then in the views.py I get the data of that input

Django input not showing

Im building a site using Django. I am trying to pass an input from index.html and display it in about.html using view.py.
My input seems to get passed as it is in the url at the top the browser.I am trying to store this value in a variable and display the variable in a html paragraph. However it does not show. Instead of seeing the input associated with the variable i just see the string of text with the variable name.
My index.html:
<form action="{% url 'theaboutpage' %}">
<input type="text" name="user_input">
<input type="submit" value="click here now">
</form>
My about.html:
<a href={% url 'thehomepage' %}>go back to the home page</a>
<p>{{'input_from_home_page'}}</p>
My views.py:
def about(request):
Hellothere = request.GET['user_input']
return render(request, 'about.html', {'input_from_home_page':Hellothere})
Just remove the quotation marks around the variable in your template at about.html. It should look like this:
<p>{{ input_from_home_page }}</p>
As side notes:
If the information entered in <input type="text" name="user_input"> is sensitive information, then you should consider passing it using "POST" HTTP method instead of "GET". In which case, remember to include the {% csrf_token %}. To get the passed info, you can use: request.POST.get('user_input') in your view.
By convention, you should name variables with lowercase. In your case, it's nice to have hello_there instead of Hellothere.

Additional action button doesn't work on flask-admin

I'm trying to add one more action to flask-admin forms.
It has to increment rating (+1) and it works with batch action, but not with single. Please help me find the bug, I've spent a lot of time trying to make this thing work properly.
Here's the code:
I made an html template in templates folder - custom_lists.html
{% extends 'admin/model/list.html' %}
{% block list_row_actions %}
{{ super() }}
<form class="icon" method="POST" action="/admin/user/action/">
<input id="action" name="action" value="approve" type="hidden">
<input name="rowid" value="{{ get_pk_value(row) }}" type="hidden">
<button onclick="return confirm('Are you sure you want to approve selected items?');" title="Approve">
<span class="fa fa-ok glyphicon glyphicon-ok"></span>
</button>
</form>
{% endblock %}
this succeeded with an icon on the list, but if i click to it - it says
Not Found
The requested URL was not found on the server. If you entered the URL
manually please check your spelling and try again.
added to templates folder and added to AdidasView class this:
list_template = 'custom_list.html'
#action('approve', 'Approve', 'Are you sure you want to approve selected items?')
def action_approve(self, ids):
try:
query = Adidas.query.filter(Adidas.id.in_(ids))
count = 0
for image in query.all():
image.rating += 1
count += 1
db.session.commit()
flash(ngettext('Item was successfully approved.',
'%s items were successfully approved.'%count,count))
except Exception as ex:
if not self.handle_view_exception(ex):
raise
flash(gettext('Failed to approve items. %(error)s', error=str(ex)), 'error')
I have not changed the template but I have done it differently as following by setting the column_extra_row_actions variable and defining the action_play function
column_extra_row_actions = [
EndpointLinkRowAction('glyphicon glyphicon-play', 'event.action_play')
]
#expose('/action/play', methods=('GET',))
def action_play(self, *args, **kwargs):
return self.handle_action()
This solution does not seem to apply to this example, but I also struggled with a case where I received a 404 when I using an action on one item via the button, while the batch action worked as expected.
After taking a look at the JS for the batch action I realized that the two HTML forms for individual actions and batch actions are practically identical. The only difference is that when using batch actions there may be more input fields in the form. That implies that if you get a 404 on one, but not the other, there must be an error in your HTML.
In my case I was not aware that Flask-Admin addresses models_with_underscores_in_their_name as modelswithunderscoresintheirname. Therefore instead of
<form class="icon" method="POST" action="/admin/mymodel/action/">
my erroneous code was
<form class="icon" method="POST" action="/admin/my_model/action/">
Note the difference in the action field.
With this change I was able to use the #action API as explained in the Flask-Admin docs.

Sending POST data from inside a Django template 'for loop'

With this HTML:
...
{% for thing in things %}
<form method="post">
{% csrf_token %}
{{ thing.name }}
{{ form.value }}
<input type="submit" value="Submit" />
</form>
{% endfor %}
...
My website lists multiple 'things' from my database, so there can be many forms generated on the one page. How can I somehow determine in my views.py, which 'thing's' form is being submitted?
More elaboration:
Imagine you have a page of objects listed one after the other, and each object has a like button associated with it, that adds a like to the object it is next to. That's essentially what I'm trying to do here.
The problem is, I have a form that can process the like, but how do I take that like and add it to the object that it's displayed next to on the page? (by the aforementioned 'for loop')
I'm completely confused on how to go about this, am I looking at the problem the wrong way, or is there a standard idiom around this problem that I don't know about?
Thank you :)
The most common design pattern for model instance updates is to provide the primary key of an object in the url where you are submitting your post data.
# urls.py
from django.conf.urls import *
from library.views import UpdateThing
urlpatterns = patterns('',
url('^update_thing/(?P<pk>[\w-]+)$', UpdateThing.as_view(), name='update_thing'),
# views.py
def my_view(request, pk=None):
if pk:
object = thing.objects.get(pk=pk)
form = MyModelForm(data=request.POST or None, instance=object)
if form.is_valid():
...
Now, let's specify (using Django's url template tag) that we want to submit post data for each object to the correct url.
{% for thing in things %}
<form method="post" action="{% url 'update_thing' thing.pk %}">
{% csrf_token %}
{{ thing.name }}
{{ form.value }}
<input type="submit" value="Submit" />
</form>
{% endfor %}
The url tag does a reverse lookup through your urls for the name kwarg supplied for a given url, and accepting positional arguments (such as, in this case, thing.pk) and, when needed, keyword arguments.
The standard way to handle multiple forms of the same kind on one page with Django is to use Formsets.
It handles the annoying details like displaying errors on one form while preserving the input on others etc.
However, in your specific case that might be overkill. If you just want to create a like for an object, there isn't really any user input that needs to be validated, so you don't really need a form. Just perform a POST to a specified URL, maybe with Javascript. If the user messes with the URL, you display a 404.

Pass variable with django form submission

I have a search box at the top of my sidemenu. This search bar searches across all views (tasks, lists, and information). The results are shown across these three categories, but lists and information are collapsed by default to make the view easier to read.
Instead, I would like to determine which side menu the user used to search, and collapse the other two categories when returning the results.
So if the user was looking at tasks, the search results would list the tasks, but return lists and information results collapsed. If the user used the search box in lists, the results would list the list items, but collapse tasks and information.
The same function is used to handle all of the search results:
def search(request):
query_string = ''
search_results = SortedDict([])
if ('q' in request.GET) and request.GET['q'].strip():
query_string = request.GET['q']
entry_query = get_query(query_string, ['name', 'notes',])
getquery() searches the database for the query_string
This function is called from the template:
<form method="get" action="{% url search %}" style="display:inline;" >
<input name="q" class="span9" value="{{ request.GET.q }}" id="appendedInputButton" size="16" type="text">
<button class="btn" type="submit">
<i class="icon-search" title="Search"></i>
</button>
</form>
How might I pass either the current url or some other template variable along with this form submission so that I have some template info available in the search function? This would then allow me to pass information to the search results that would tell the template which categories to collapse.
The easiest and most foolproof way is to use separate buttons. If you give each a name and only the appropriate one is shown when a particular view is active, you can tell which view was active from the existence of the button's name in the POST.
The only other route would be to create a hidden field, and set the value of the field appropriately, with JavaScript, when the view changes.

Categories