In Django1.6, is there a way to pass a dynamic parameter to my view or URL without parsing the URL?
Ideally I would want a urls.py that looks like:
url(r'^dash/$',
dash_view.account_modify,
{'account': **dynamic_account_identifier_here**}
name='dash_account_modiy')
And in views.py:
def account_modify(request, account,
template_name='profile.html,
change_form=AccountModifyForm):
...
:param account:
comes from model:
class Dash(models.Model):
name = models.Charfield()
account = models.IntegerField()
....
Basically, I would really like to avoid a urls.py with the account identifier as part of the string, like:
url(r'^dash/(?P<account>\w+)/$',
dash_view.account_modify,
name='dash_account_modiy')
Any suggestions on how I can pass these values from the a template to the processing view for use in the AccountModifyForm (which expects that 'account' parameter)?
url(r'^dash/$',
dash_view.account_modify,
{'account': **dynamic_account_identifier_here**}
name='dash_account_modify')
You can't dynamically evaluate anything there, because the dictionary is evaluated only once, when the URL conf is loaded.
If you want to pass information from one view to another your three options are:
in the URL, which you don't seem to want to do
as GET or POST data
store it in the session in one view and retrieve it from the session in the next
If anyone cares...figured it out...
In the template:
{% for dash in dashes %}
blah blah blah
<form action="..." method="POST">
<input type="hidden" name="id" value="{{ dash.account }}">
{{ form.as_ul }}
<input type="submit" value="Do stuff">
</form>
{% endfor %}
In the views:
if request.method == 'POST'
account = request.POST['id']
# be sure to include checks for the validity of the POST information
# e.g. confirm that the account does indeed belong to whats-his-face
form = AccountModifyForm(request.POST, account,
user=request.user)
....
Related
i am trying to build a django search functionality for my app but the input form keeps returning a none
views.py
def search(request):
if request.method == 'POST':
query = request.POST.get('text')
houses = Product.objects.filter(name__contains='query')
context = {
'houses':houses,
}
return render (request, 'searchresult.html', context)
search.html
<form>
<input type='text' placeholder='search houses>
<button type='submit'>Search</button>
</form>
First off, your python indentation is invalid, and your HTML is also invalid on the input line. I will assume this is a typo in the question, but if not, you have issues there.
Your main problem is the filter for houses:
houses = Product.objects.filter(name__contains='query')
is looking for a name containing the string "query". You need the variable you've just defined.
houses = Product.objects.filter(name__contains=query)
You have an indentation issue in the code you have posted.
You need to add action and method in your Form.
<form action="/url_of_search/" method="post">
Missing quote in input line.
<input type='text' placeholder='search houses'>
You need to use query instead of 'query' in the filter.
Product.objects.filter(name__contains=query)
Things missing in html code:
form action attribute
form method attribute
input field name attribute
<!-- add form attributes method and action -->
<form method="POST" action="{% url '<url_name>' %}">
<!-- add input attribute name to identify the field and pass the value in request body -->
<input type='text' placeholder='search houses' name='search_text'>
<button type='submit'>Search</button>
</form>
update views for search
def search(request):
if request.method == 'POST':
# use input field name to get the search text
query = request.POST.get('search_text')
houses = Product.objects.filter(name__contains=query)
context = {
'houses':houses,
}
return render (request, 'searchresult.html', context)
I am trying to create a simple search form(search by zip code), but am struggling to pass the user's input to a view:
<form action="{% url 'search_results' query %}" method="post">
<div>
{% csrf_token %}
<input type = 'text' name = 'query' placeholder="Zip Code" />
<button type="submit" name="button">Find Jobs</button>
</div>
</form>
urls.py:
path('search_results/<str:query>', job_views.search_results, name = 'search_results'),
views.py:
def search_results(request, query):
query = request.GET['query']
return HttpResponse(query) # just trying to see if this view has access to 'query'
I'm not sure what is going on here. This returns
raise NoReverseMatch(msg)
django.urls.exceptions.NoReverseMatch: Reverse for 'search_results' with a
rguments '('',)' not found. 1 pattern(s) tried: ['search_results\\/(?P<que
ry>[^/]+)$']
Thanks for any help!
In your form, at the line: action="{% url 'search_results' query %}", you are trying to pass query to the url tag, which would be fine if query had a value, but in your case query isn't defined.
Instead, you're form should look like this:
<form action="{% url 'search_results' %}" method="GET">
<div>
<input type = "text" name = "zip_code" placeholder="Zip Code" />
<button type="submit" name="button">Find Jobs</button>
</div>
</form>
Notice that I removed query from your url tag, and changed the method to GET, see this question for details.
Now change your path:
path('search_results', job_views.search_results, name = 'search_results')
You don't need to add query to the path, because Django will do it for you in your view:
def search_results(request):
zip_code = request.GET.get('zip_code')
print(zip_code)
...
That's not how templates work.
Templates are used to produce a response, which gets returned to the requester. In this case, your main view produces an HTML document which will be passed to a browser. That document contains results of the url template tag, which is determined before the user even sees it. Template tags are not a way to refer to the state of DOM objects!
Instead, you should usually have a view with a stable URL, not varying with the query. Typically you'll then extract the query text from the form data representation - here, it'd be the request.POST dictionary-like object or (usually better) a Django form that you bind to the POST data, because your form uses method="post".
It would be possible to use Javascript to edit the DOM and change your form action prior to submitting it to include the query text, but that's not the usual pattern for working with forms. And template tags will never do that - they're only used to generate the response.
Summary: I am trying to build a job site. On index.html the user enters a zip code into a form to see jobs in that zip code, this form is handled with the job_query view. This brings them to another page(search.html) where at first you only see jobs in that specific zip code but I am trying to add a filter that lets the user see jobs within X miles. How can I pass the zip code value entered in the from on index.html to the next page?
index.html:
<h2>Find a Job</h2>
<!--Search Bar-->
<form method = "GET" action = "{% url 'search' %}" >
<div id = "form_grid">
<input name="query" type="text" placeholder="Zip Code">
<button type="submit">Search</button>
</div>
</form>
search.html:
<form method = "GET" action = "{% url 'search' %}" >
<input class="search_bar" name="query" type="text" placeholder="Zip Code">
<button class="search_btn btn btn-outline-success " type="submit">Find Jobs</button>
</form>
<form id="within_miles_form" method = "GET" action = "{% url 'within_miles' %}" >
<input class="search_bar" name="miles" type="text" placeholder="Within X miles of Zip Code">
<button type="submit">Filter</button>
</form>
<!--code to display jobs-->
views.py:
def job_query(request):
if request.method == "GET":
query = request.GET.get('query')
jobs_matching_query = Job.objects.filter(zip_code__iexact = query) | Job.objects.filter(city__iexact=query) | Job.objects.filter(state__iexact=query)
number_of_results = 0
for job in jobs_matching_query:
number_of_results = number_of_results + 1
return render(request, 'core/search.html', {'query': query ,'jobs_matching_query': jobs_matching_query, 'number_of_results': number_of_results})
def within_miles(request):
miles = request.GET['miles']
#how can i use value of the zip code entered?
urls.py:
url(r'^search$', views.job_query, name="search"),
url(r'within_miles', views.within_miles, name="within_miles"),
I think I included all the relevant info but if I am missing something please let me know, thanks in advance for any help.
You can encode the entered ZIP in a URL, pass it through cookies, store it in the session variables, or use a (hidden) input element that forces the browser to pass it through a GET and POST request.
Encode it in the URL
In that case we can rewrite the URL to:
url(r'^within_miles/(?P<zip>[0-9]{5})/$', views.within_miles, name="within_miles"),
So now one can no longer fetch your.domain.com/within_miles, but your.domain.com/within_miles/12345. It makes it easy for a user to "manipulate" the URL, but since the user can probably provide any ZIP, there is probably not much gain to protect that.
In the form, the URL that is generated is thus:
{% url 'within_miles' zip=query %}
(you can use another variable that is more strictly a ZIP code)
You should thus ensure that query is here a five digit string (or otherwise change the expression in the url(..) part such that it allows all possible queries).
Using hidden form elements
We can also encode content in hidden form elements, for example here we can create an element in the form:
<form id="within_miles_form" method = "GET" action = "{% url 'within_miles' %}" >
<input class="search_bar" name="miles" type="text" placeholder="Within X miles of Zip Code">
<input type="hidden" name="zip_code" value="{{ query }}">
<button type="submit">Filter</button>
</form>
We thus add a form element, fill it with some data, and let the browser submit the value again to the next view. Note that again it is the browser that does this, so a user can inspect the DOM (most browsers allow that, and subsequently edit it).
Using session variables and/or cookies
You can also decide to use session variables (stored at server side, so "secure") or cookies (stored at client side, can be tampered with). A potential problem however is that these are stored in the browser, and changes to the cookies in one tab page, thus can have effect in the other tab page. Furthermore cookies and sessions will "die" after the request, and thus can create a lot of trouble in future views.
You can set a session variable in the view with:
request.session['zip_code'] = query
This will thus store an entry at the server side such that another call can retrieve that value again. The request.session acts like a dictionary that keeps some sort of state per session.
setting and obtaining session variables
In another view, you can thus query the request.session, like:
zip_code = request.session.get('zip_code')
setting and obtaining cookies
We can use a similar approach with cookies. A browser however might reject cookies, or manipulate them, so there are not that much guarantees that there is no tampering with the data (in fact there are none). You can set a cookie with:
response = render(request, 'core/search.html', {'query': query ,'jobs_matching_query': jobs_matching_query, 'number_of_results': number_of_results})
response.set_cookie('zip_code', query)
return response
Before we thus return the result of render(..), we call .set_cookie(..) on the result.
We can - for example in a later view - retrieve the content with:
zip_code = request.COOKIES.get('zip_code')
Improving the job_query view
The job_query view however looks a bit strange: it uses all kinds of "uncommon" code practices. For example the number of elements is calculated by iterating over it, instead of taking the len(..). This also looks basically like a ListView [Django-doc] and we can make the query more elengant by using Q-objects [Django-doc]. The listview then looks like:
def JobListView(ListView):
model = Job
context_object_name = 'jobs_matching_query'
template_name = 'core/search.html'
def get_context_data(self, **kwargs):
kwargs = super(JobListView, self).get_context_data(**kwargs)
kwargs.update(
number_of_results=len(kwargs['object_list'],
query = self.request.GET.get('query')
)
return kwargs
In the view, you then not pass the JobListView, but JobListView.as_view() result as a reference.
in a movie rating app,I would like to generate a WTF form in flask with dynamic number of fields. i.e, if there are three movies, there will be three fields.
I thought about a few options, but none of them worked:
class RatingForm(Form):
rating = TextField("rating",[validators.Length(min=1, max=1)])
movie_order=TextField("movie",[validators.Length(min=1, max=1)])
submit = SubmitField("submit rating")
pass a parameter to the form object - I don't see how can I pass a parameter to this kind of class
make a loop inside the template, thus generate and return multiple forms, and choose the correct one. this also doesnt work, since the request.form is immutableDict, and I end up having multiple fields with the same key, which I cant access.
{% for movie in movies_to_rate %}
<p>
<form method="POST" enctype="multipart/form-data" action="/rate">
{{ movie}}
{{ forms[movie].rating}}
{{ forms[movie].submit }}
<input type="submit" value="Go">
</p> {% endfor %}
any ideas about what can I do?
I think you can generate a list of TextField's as a class member instead of using one field object. (Though it looks a bit weird, I assume your validators are what you meant.)
class RatingForm(Form):
def __init__(self, count):
self.ratings = [TextField("rating_" + str(i), [validators.Length(min=1, max=1)])
for i in range(count)]
...
I would like to have a custom snippet of html form code that takes allows the user to select a 'training' that is then used as a query parameter to a django-admin model filter for 'participants'.
I've successfully created the filter on the modeladmin:
class ParticipantAdmin(RestrictedModelAdmin):
list_filter = ('training__name',)
It's probably worth noting that RestrictedModleAdmin is a subclass of ModelAdmin that provides row-level security for the model; logged in users should only see rows they own.
Thus, urls using this filter look something like this when just using that admin interface:
/admin/core/participant/?training__name=Menno+Ropes
All that works great. Now I think I should be able to create a very simple form that allows selecting a valid 'training' and submitting that to /admin/core/participant/ as a GET.
<form method="GET" action="/admin/core/participant/">{% csrf_token %}
<ol>
<li>Select your training:
<select name='training__name'>
<option value=''>—</option>
{% for training in trainings %}
<option value='{{ training.name }}'>{{ training }}</option>
{% endfor %}
</select>
</li>
<li>See participants for that training.
<input type='submit' name='submit' value='Submit' /></li>
</ol>
</form>
This last bit doesn't see to work. Some magic foo in the django innards seems to always mangle the submission to be:
/admin/core/participant/?e=1
This obviously doesn't select the appropriate filter value and thus shows an unfiltered list of 'participants'.
What's going on? What can I do to get it to allow my GET parameter to pass through to the admin model?
Thanks in advance.
PS) Django 1.3+
The problem is that you have a name attribute in your <input type="submit">, causing an extra GET parameter: submit which is throwing the invalid lookup error and thus e=1
Remove the name attribute and you're good to go.
I did a little experiment to confirm since I thought it odd that the server might somehow treat a browser GET differently.
It's a little bit tricky, but it works for me:
def changelist_view(self, request, bill_id, extra_context=None):
"""queryset is an extra parameter"""
req = request.GET.copy()
if 'queryset' in req:
queryset = req.pop('queryset')[0]
else:
queryset = request.META['HTTP_REFERER'].split('queryset=')[1]
url = "/admin/billing/invoice/%s/select_to_move/?%s&queryset=%s" % (bill_id, request.GET.urlencode(), queryset)
return HttpResponseRedirect(url)
request.GET = req
# Do stuff with queryset.
return super(MyAdminClass, self).changelist_view(request, context)