How to use <select> information in django form - python

So I have my django project which includes a HTML page that shows a list and a submit button.
I want to use the submit button to send the selected item ID to the server and than use it.
That`s my code :
<form>
<select>
{% for item in list %}
<option value={{item.name}}>{{ item.name }}</option>
{% endfor %}
</select>
<input type="submit"/>
</form>
The things I want to know are :
What to write in the action of the form so it will only reload the page.
How to enter the form data into a view.

As i understand, you want to take the value on your select and do something with it in the server.
I would advise you to read the documentation, as it is pretty detailed about what you need to know to work with forms. You should also read a little about forms, as you are missing a couple details.
Now, the action must point to one of your urls. Your url must be pointing to a view and in your view, if everything is ok, you should be getting a request object.
Depending on your post method, you have a python dictionary in request.GET or request.POST, filled with the values in your form.
That is assuming you are using your form created from scratch. In django you can use the Form class, which creates the html (or lets you create it, but giving you some constraints), validates the form, saves the form to a model (in the case it is a ModelForm). It is a valuable class for me and prefer it over working with raw html.
Also, assuming you haven't, i strongly advice you to go through the getting started. Even if it keeps things basic, it does a good job at introducing core django modules.

Related

Variable URLs and passing non-input value from html to Python (Flask)

According to this question you can only send data from input forms from html to Python with POST. I'm trying to figure out how to pass a value (that's actually originally contained in a dictionary that I passed in from Python) from html to Python.
My two approaches I considered (and have not figured out how to do successfully) are:
Taking a look at the Flask quickstart, this should be quite simple. I'm just not sure what the syntax should look like on the html side to pass in this parkCode.
#app.route('/park/<parkCode>', methods =['GET', 'POST'])
def park(parkCode):
return render_template('park.html', parkCode = parkCode)
Alternatively, is there some way to simply send a string from html to Python without using an input form? I have yet to find a way to do this.
For reference, this is the line where I'm sending over the ```parks`` dictionary:
return render_template('search_results.html', parks=parks)
Then, in my search_results.html file:
{% for park in parks %}
<div method = "POST" action = "/park">{{park["fullName"]}}</div>
{% endfor %}
But I want the to send the park["fullName"] to my Python code.
.route decorator always handles only URL paths. Since form action is a static value in HTML, the only way to change it is to use JavaScript (for example, by changing the action attribute at submit time). If you're going to use JavaScript, you might as well then just use JavaScript to submit the request itself, which leads us to
Yes, you can use AJAX to send a request. Since ES6, the easiest way to do this is fetch. The choice of whether to use a form or whether to use AJAX depends on what you want to happen after the request: a submitted form results in a new page being rendered, while an AJAX request cannot change the current page, only trigger JavaScript code (although obviously you can change the page in JavaScript should you so wish).
Basically, you can't do what you want without JavaScript. The third option that does work without JavaScript is using the form as it was meant to be used. On flask side, it involves not naming the parameter inside the route, but using request.args (for GET forms) or request.form (for POST forms):
#app.route('/park', methods =['POST'])
def park():
parkCode = request.form.get('parkCode')
return render_template('park.html', parkCode = parkCode)
with the accompanying HTML:
<form action="/park" method="POST">
<input name="parkCode"/>
<input type="submit" value="Submit"/>
</form>

Django: 1 view for different users?

In my project, I'd like to split pages between a side menu and a content page.
I'd like to show a sidemenu which is different for user types (there are 5 user types, so there will be 5 sidemenus). But sometimes, the content page to display can be the same for these 5 user types.
I was looking for a "pattern" to handle this, I thought about one, but never seen it in another project. I'd like you to tell me if it's a good or bad practice:
1 URI for all user types (eg. /myapp/display_home)
In views.py, 1 view for all user types. Into the view, I try to know if the user is logged in, and then which type of user we are dealing with. Then, redirect to the HTML, passing in context a variable containing the user type.
In the end, in the template, something like this:
Example of template:
{% if user_type == "anonymous" %}
<!-- display anonymous sidemenu here -->
{% elif user_type == "landlord" %}
<!-- display landlord sidemenu here -->
{% endif %}
<-- Here is the same content for all user types -->
Do you have any suggestion? another pattern to propose?
Check this answer for discussion on user.is_authenticated. You can also check within the view to see who the user is (see here) and modify the context being sent to the template accordingly. Another option would be to modify your view to simply show different types of users different templates.
Lots of ways to accomplish this, not sure if there's a "correct" one.
Your comment made me realize that this is exactly what the Groups feature of the auth package is for. You can assign users to groups, query whether they're a member of the group, and then show content based on that. I apologize that I don't have time to write out sample code, but there's tons of stuff here on SO about it; hopefully that's a good starting point for you.
I don't know if it is good style. But you could use
{% include user_type_sidemenu_template with arg1=... %}
in your template and provide different templates for the sidemenu for each user_type. You can then set the template variable user_type_sidemenu_template to the corresponding template name in your view.

Personalized/random URLs in Python/Django

I'm a Python beginner (and English language beginner too, by the way).
I just created a simple form in Python/Django that creates, edit and remove items.
I have HTML links that refers to my URLs like:
FILE.HTML:
<INPUT Type="BUTTON" VALUE="Edit" ONCLICK="window.location.href='/edit/{{ object.id }}/'">
URLS.PY:
url(r'^edit/(?P<id>\d+)/$', 'app.views.editobj'),
VIEWS.PY:
def editobj(request, id):
But of course, there's a problem, I wouldn't like people go direct on URL (only if the button was clicked) because somebody could just type on URL: /removeobj/1 and remove the object ID=1. What I would like to do is create differente URLs, maybe random, so the user would never guess what is the URL that the button will open, and of course, that it does work with the ID argument, so when it's goind to edit/remove, opens the right object.
I'm Hoping I was clear on my needs. Thanks.
Generating random URL's would be highly inefficient, not to mention unnecessarily difficult to implement. The common way to do what you are asking is to POST to a URL. I think you should do a little more reading on Django POSTing, as it will help you get a better understanding of what it does. In any case, here is an example of using this:
urls.py
url(r'^delete/$', 'app.views.delete_object', name="delete_obj"),
views.py
def delete_object(request):
""" Get the ID of an object via POST, then delete it. """
if request.method == 'POST' # This makes sure the request is a POST
obj_id = request.POST['obj_id']
obj = MODELNAME.objects.get(id=obj_id) # Use your model name here
# You can use if conditions here to make sure the object you just
# retrieved is allowed to be deleted by this user, or in general.
obj.delete()
messages.success(request, 'Object successfully deleted!')
return redirect(reverse('index')) # Make sure you use a name that exists
.html
<form method="POST" action="{% url 'delete_obj' %}">
{% CSRF_TOKEN %}
<input type="hidden" value="{{ obj.id }}" name="obj_id" />
<button type="submit">Submit</submit>
</form>
You can use more logic in the views.py to make sure that the object is allowed to be deletable, but for the most part, the code I wrote should give you somewhat of an understanding of the way to create a POST -> Delete Object workflow. Feel free to ask questions in the comment section below my answer.
The simplest way I see to do a "random" url would be to add a UUIDField (https://docs.djangoproject.com/en/1.8/ref/models/fields/#uuidfield or https://github.com/dcramer/django-uuidfield for Django <1.8) with a default to your model.
Your url can then become
url(r'^delete/(?P<uuid>[\da-f-]+)', 'app.views.delete_object', name='delete_obj')
uuid's are virtually impossible to guess.
Now if you don't add extra security to check that the user has the right to delete the object, anyone could still run a robot that would go through every single possible uuid and flush your database.
And if it is just a matter of not "guessing" #Hybrid's solution is probably a better starting point.

Using a python list in a Check Box Selection Form in Flask WTF

I want to use a python list as the options for a check box selection form.
So you can select the items in the list that you want and submit the form to use those values.
Which form field do I use in my form?
What would my html file look like?
I think the .html page should look like this.
<form>
{% for item in list %}
<input type="checkbox" name="modList" value={{item}}>{{item}}<br>
{% endfor %}
</form>
But I can't figure out what to make the form field in forms.py.
http://packages.python.org/Flask-WTF/
There is no Checkbox form on that page.
I can use
{{form.modList(formdata = list)}}
But it just displays an emtpy checkbox with no text
I'm not sure why you'd want to do this. If you're using checkboxes, I assume you'll want to return the value of each one. If so, then each one should be a distinct property of the WTForm instance you're using.
If you're only wanting to return the values checked, WTForms offers the wtforms.fields.SelectMultipleField. That would print a dropbox wherein the user could select 0, 1 or more options.
If you must have checkboxes, and you must use a list in the form definition, then it seems your only option is to create a custom field. You can find documentation on how to do that here.
In fact - this use case is the example in the Custom Widget portion of the WTForms documentation.

How to generate lots of redundant ajax elements like checkboxes and pulldowns in Django?

I've been getting lots of answers from stackoverflow now that I'm in Django just by searching. Now I hope my question will also create some value for everybody.
In choosing Django, I was hoping there was some similar mechanism to the way you can do partials in ROR. This was going to help me in two ways. One was in generating repeating indexed forms or form elements, and also in rendering only a piece of the page on the round trip.
I've done a little bit of that by using taconite with a simple URL click but now I'm trying to get more advanced. This will focus on the form issue which boils down to how to iterate over a secondary object.
If I have a list of photo instances, each of which has a couple of parameters, let's say a size and a quantity. I want to generate form elements for each photo instance separately. But then I have two lists I want to iterate on at the same time.
Context:
photos : Photo.objects.all()
and
forms = {}
for photo in photos:
forms[photo.id] = PhotoForm()
In other words we've got a list of photo objects and a dict of forms based on the photo.id.
Here's an abstraction of the template:
{% for photo in photos %}
{% include "photoview.html" %}
{% comment %}
So here I want to use the photo.id as an index to get the correct form. So that each photo has its own form. I would want to have a different action and each form field would be unique. Is that possible? How can I iterate on that? Thanks!
Would it be a with? In Python of course it's form = forms[photo.id] but here?
{% endcomment %}
Quantity: {{ oi.quantity }} {{ form.quantity }}
Dimensions: {{ oi.size }} {{ form.size }}
{% endfor %}
What can I do about this simple case. And how can I make it where every control is automatically updating the server instead of using a form at all?
Thanks!
James
I'm not sure I understand your question, but here's what I think you want, expressed in pseudo-code:
for photo in photos:
form = forms[photo.id]
generate_some_html(photo, form)
Probably the best way to achieve this is with inclusion tags: http://docs.djangoproject.com/en/dev/howto/custom-template-tags/#inclusion-tags . Basically, it's a custom tag that relies on another template, similar to an RoR partial. The details can be found in the link I provided, but what you basically need to do is
create a package names "templatetags" in one of your app directories
create a module in that package. Let's take foo_tags.py for example.
Add the following boilerplate to foo_tags.py:
from django import template
register = template.Library()
Write your custom tag, which implements generate_some_html. Make it take the caller's context:
#register.inclusion_tag('relative/path/to/some/template.html', takes_context=True)
def foo_tag(context):
photo = context['photo'] # loop variable in parent template
form = context['forms'][photo.id]
# further computation that you need in order to setup the
# context for relative/path/to/some/template.html can be
# done here...
return locals()
Use the context returned by foo_tag in relative/path/to/some/template.html.
Add {% load foo_tags %} to the parent template. You should probably put this near the top, the same way you put imports near the top of a .py file.
Use your new custom tag in the parent template:
{% for photo in photos %}
{% foo_tag %}
{% endfor %}
Django doesn't comme with backed AJAX like RAIL, but it let you choose any lib you want to use from the start.
You can do what you want by creating custom widgets and using form media.

Categories