Can make a Search with a template form work - python

I use crispy-forms in all of my search,but in this one I need to do it with a template form, I don't know what's wrong with my code 'cause I have the same code in other project and it works fine, I don't know if is the Django version, currently I'm using 1.8. The error that I get is Page not found (404), I doesn't find the url.Here's my code hope you can help me. I use q and param in the url but none works.
urls.py
url(r'^search/(?P<param>\S+)$', permission_required('agenda.change_agenda', login_url='/no_access')(SearchContact.as_view()), name='searchcontact'),
template_form.html
<form class="well form-search" action="/search/" method="get">
<input type="text" class="input-medium search-query" name="param">
<button type="submit" class="btn">Search</button>
</form>
views.py
class SearchContact(ListView):
template_name = 'agenda_contacts.html'
def get_queryset(self):
query = self.request.GET.get('param')
return Agenda.objects.filter(name=param)

Your regex
r'^search/(?P<param>\S+)$
matches urls like /search/hello or /search/my-search.
However, your search form is sending the search terms in the GET paramters, for example /search/?param=hello or /search/?param=my-search.
GET parameters are not captured in urls.py. You can access them with request.GET in the view as you are already doing.
Therefore, you should remove param from the regex, and change your url pattern to the following.
url(r'^search/$', permission_required('agenda.change_agenda', login_url='/no_access')(SearchContact.as_view()), name='searchcontact'),

Related

Using flask form result to generate a URL?

I am creating an app that does some analysis, given a user enters in some IDs into the form. For example, if a user types 12345, 23456 into the TextField form, the app will run some analysis on these IDs and then display the results. My problem is that currently, when the user clicks "Submit" and the data analysis completes, it always redirects the user to www.website.com/results. I need to create unique url's like www.website.com/results/12345+23456 so that 1) I can have multiple users and 2) users can send this link to people to re-generate the analysis.
Now, there are some questions on StackOverflow that are similar to my question but they are not the same and did not help me. So first, let me show some code before discussing that.
I have a home page which contains the the form:
<div>
<form action="https://website.com/results/" class="form-inline" method="post">
<div class="form-group">
<label for="PubmedID">Pubmed ID(s)</label>
<input type="text" class="form-control" id="PubmedID" name="pmid" value="{{request.form.pmid}}">
</div>
<button type="submit" id= "myButton" class="btn btn-default" data-toggle="modal" data-target="#myModal">Submit</button>
</form>
</div>
As you can see, the value for the form is request.form.pmid. My Flask-Wtform for this is here:
class pmidForm(Form):
pmid = TextField('PubmedID')
Since the action of this form points towards website.com/results that triggers my Flask function to be called:
#app.route('/results/', methods=["POST"])
def results():
form = pmidForm()
try:
if request.method == 'POST':
#entry = request.form or request.data doesn't help me...
entry = form.pmid.data #This is the user input from the form!
# DO LOTS OF STUFF WITH THE ENTRY
return render_template('results.html')
except Exception as e:
return(str(e))
As you can see I am using POST and form.pmid.data to get the data from the textfield form.
Again, I don't want to just redirect to /results, I'd like to expand on that. I tried to modify my form so that the form action pointed to https://website.com/results/{{request.form.pmid}}/ and then update the results function to be
#app.route('/results/<form_stuff>', methods=["POST"])
def results(form_stuff):
But this never worked and would re-direct me to a 404 not found page. Which I believe makes sense because there is no form data in the action when the HTML is first rendered anyway.
Now, the other post that mine is similar to is: Keeping forms data in url with flask, but it quite doesn't answer or solve my problem. For tthis post, the key point that people made was to use POST (which I already do), and to obtain and return the data with return request.args['query']. For me, I'm already processing the form data as I need to, and I have my return render_template() exactly how I want it. I just need to add something to the results URL so that it can be unique for whatever the user put into the form.
What do I need to add to my form in the html and to my Flask /results function in order to have the form data added into the URL? Please let me know if there's any other information I can provide to make my problem more clear. I appreciate the help! Thanks
This isn't really a question about Flask.
If you want the data to show in the URL when you submit the form, you should use method="get" rather than "post". Then the URL will be in the form https://website.com/results/?pmid=12345.

Pass <input> value to Django view

Let's say I have the following pointless example view:
def foo(request, input):
return HttpResponse()
and in a template I have a form:
<form method="get" action="{% url 'foo' ??? %}">
<input id="myinput" type="text" name="myinput">
...
</form>
Finally, I have the following url in my URLconf:
urlpatterns = [
url(r'^foo/(.+)/', views.foo, name='foo'),
]
What I would like to do, is pass the value entered by the user into the input with the id of #myinput to the foo() view function. To put it another way, you should be able to enter bar in the html input, and when you submit the form it will take you to foo/bar/.
I know that within the foo view I could access the value of the input easily with request.GET['myinput'], but I want it to show up in the url as well.
This seems like it should be a fairly common task, but I have not been able to come up with a solution yet. Any suggestions would be appreciated. My Frankenstein's Monster of a first Django site is almost complete, and this is one of last pieces I am missing.
The source of my misunderstanding
Although I did not make this clear in an attempt to simplify my example and avoid using app-specific code, my use case is a simple search view. The view was actually one of the first views I wrote in the start of my Django journey, and I mistakenly was POSTing my data instead of GETing it. This was making it so that if I was searching for the item foo, it would take me to the detail page for foo, but the url would be mysite/search/ (i.e., the search query is not included in the url though it is included in the request), and I can't return to those search results by visiting the url mysite/search/.
While I was using a GET request in my toy example in this question, I didn't realize that I had been using a POST in my app, and that with some minor tweaking I can get the functionality I want for free very easily. I know that all of this is extremely obvious to veteran and even intermediate web developers, but for someone starting from scratch without web or cs experience, things like HTTP can be a little confusing. At least for me it is. Thanks so much to #Two-Bit Alchemist for explaining this in a way that I can understand.
Applying all this to my toy example
I would get rid of the passed parameter in my view:
def foo(request):
# If I want to do something with the search query, I can access it with
# request.GET['search_query']
return HttpResponse()
change my form in my template to:
<form method="get" action="{% url 'foo' %}">
<input id="myinput" type="text" name="search_query">
...
</form>
and change my url to:
urlpatterns = [
url(r'^foo/search/', views.foo, name='foo'),
]
As #Two-Bit Alchemist said: "The rest will happen like magic". If a user enters bar in the input and submits the form, they will be taken to foo/search/?search_query=bar. This is what I was looking for.

Django csrf_token in ModelAdmin

I want to add a form to the list display of my ModelAdmin, but can't get the csrf_token to render properly. I'm using django 1.6. My code looks like this:
class ApplicationAdmin(admin.ModelAdmin):
model = Application
list_display = ('applicant', 'approve_or_reject')
def approve_or_reject(self, obj):
return '<form method="post" action="/applications/approvals">{% csrf_token %}<input type="submit" class="btn-approve" name="approve" value="Approve"/></form>'
approve_or_reject.short_description = 'Approve/Reject'
approve_or_reject.allow_tags = True
admin.site.register(Application, ApplicationAdmin)
I keep getting the error:
KeyError at /management/application/ '% csrf_token %'
How can I properly pass the csrf_token?
Model admin methods used in list_display like approve_or_reject should return text. If you mark the output as safe, you can return HTML. However, the return value is not treated like Django template language, so using the csrf token tag won't work.
It wouldn't be easy to get the csrf token inside the approve_or_reject method, because you do not have access to the request object. Another issue is that the entire changelist table is already wrapped in a form tag (id="changelist-form"), and form tags should not be nested.
An alternative would be to implement your 'approve or reject' functionality as an admin action. The UI would be different, but it might be good enough.

How to use hidden input in an html form with Python+Jinja2

When I put this line in my html template, I can successfully pass the input string via a jinja2 variable into my Python code...
<label for="firstName">First name*</label>
<input type="text" name="fname" id="firstName" value="{{ fname }}">
However, when I attempt to pass a hidden input with the following line...
<input type="hidden" name ="contact_form" value="{{ active_form }}">
... I'm not seeing the value pass back to my Python code. I've not learned Javascript yet. Is there some Javascript required to pass hidden input values? What am I missing?
I recommend using WTForms.
Example
from wtforms import TextField, validators, PasswordField, TextAreaField, HiddenField
class ArticleCreateForm(Form):
title = TextField('Title', [validators.Required("Please enter title.")],
filters=[strip_filter] )
body = TextAreaField('Body', [validators.Required("Please enter body.")],
filters=[strip_filter])
category = QuerySelectField('Category', query_factory=category_choice )
person_name = HiddenField()
views.py
#app.route('/create', methods=['GET', 'POST'])
def article_create():
if 'email' not in session:
return redirect(url_for('signin'))
person = Person.query.filter_by(email=session['email']).first()
name = person.firstname
article = Article()
form = ArticleCreateForm()
form.person_name.data = person.firstname
if form.validate_on_submit():
form.populate_obj(article)
db.session.add(article)
db.session.commit()
return redirect(url_for('index'))
return render_template('create.html', form=form, person=person, name=name)
I know this is an old post but I was fooling around with a Jinja template and I wanted solve this particular issue since I was dealing with it myself. I was planning on fooling Jinja by passing in my value and adding the quote symbols (") in a concatenated string along with my Jinja variable (named "ticket_number") like so:
<input class="hidden" name="ticket_number" value={{ ticket.ticket_number + '"' }}>
That will NOT work. So I removed the concatenation and passed the variable in directly. This seemed promising. Was expecting to find the HTML code would contain the variable value without the quote symbols surrounding up but was presently surprised to find that either Jinja or Flask quoted the variable correctly with no extra add on's using the straight variable value:
<input class="hidden" name="ticket_number" value={{ ticket.ticket_number }}>
The variable itself is an integer so I confirmed if this also happens with regular alphanumerical string variables. Let me know if it works for you all-
If you are using Flask along with Jinja2 (which I would recommend), you can run code like this in the view function:
from flask import request
#app.route('/path/to/submit/page', methods=["GET","POST"])
def viewfunctionforsubmitpage():
request.form['contact_form']
Flask is a nice, lightweight, and built using Jinja2, so that is good.

django - urlconf request mapping and views not reached

i have a form in a template, but it can't reach the correspondant view. the method is GET. i've tried also to pass it an argument just to populate the query string, but the request doesnt reach the mapped view. here'sthe views.py, urls.py and the template:
template.html
<div id="search-new-btn">
<form action="/anagrafica/new/" method="get">
<input type="submit" title="Crea nuovo soggetto anagrafica" value="Nuovo" />
</form>
</div>
views.py
def anagrafica_new(request):
if request.method == 'GET':
form = AnagraficaForm()
sub = 'Nuovo soggetto anagrafica'
dict = {'sub':sub,'form':form}
return render_to_response('anagrafica_form.html', dict, context_instance=RequestContext(request))
urls.py
...
url(r'^anagrafica/new/',('gpf1.views.anagrafica_new')),
...
(http://openpaste.org/05b157c1)
Anyway, i've also tried to remove the () from the callback url.py mapping, but it didnt change nothing.
the request seems to be mapped cause my debug server print this:
"GET /anagrafica/new/? HTTP/1.1" 200 17310
but nothing more. the browser remain on the same page; i also put a print statement just inside the view but it never has been reached. any idea?
thanks,
Luke
As Willian suggested don't put the view in a tuple. Another thing you are missing is the $ at the end of regular expression i.e.:
urls.py
...
url(r'^anagrafica/$','gpf1.views.anagrafica'),
...
url(r'^anagrafica/new/$','gpf1.views.anagrafica_new'),
...
Make sure that the folder containing gpf1 package is within Pythonpath variable (reachable by python).
Edit:
Subsequently I noticed you have a root url map for
url(r'^anagrafica/','gpf1.views.anagrafica')
Since you are missing $ at the end Django will try to map anagrafica/anything here to gpf1.views.anagrafica which is probably not what you want. Consider rereading regular expressions and Django's url mapping documentation as it will make things a bit clearer.

Categories

Resources