How to Prefill Form with URL Parameters (Django) - python

I would like to prefill a form with URL parameters, but I am unsure as to how I should configure my URLs. I need to fill multiple fields, so is using URL parameters still the best method? In the tutorials I have been reviewing, most cases only use 1 or 2 parameters from the GET request. In my view, I am only handling one field currently as I am having trouble with just one parameter. You can see in the form model the other fields I would like to fill. Any help is greatly appreciated!
views.py
def new_opportunity_confirm(request):
form_class = OpportunityForm
account_manager = request.GET.get('account_manager')
form = form_class(initial={'account_manager': account_manager})
return render(request, 'website/new_opportunity_confirm.html', {'form': form})
urls.py
re_path(r'new_opportunity/new_opportunity_confirm/(?P<account_manager>\w+)/$', view=views.new_opportunity_confirm,
name='new_opportunity_confirm'),
new_opportunity_confirm.html
<form action="" method="post" name="newOpportunityForm" id="newOpportunityForm">
{% csrf_token %}
<div class="field">
<label class="label">Account Manager:</label>
<div class="select">
<select name="account_manager" id="account_manager" required>
<option value="{{ form }}">{{ form }}</option>
</select>
</div>
</div>

It depend if you want your parameters to be part of the url or not, and in your case I would suggest not, but let's see both method.
For GET parameters (url?var1=poney&var2=unicorn):
You do not need to configure your url. Django will do the work for you, you just have to configure what is before the interrogation point.
You can then access those with request.GET.get("var1"), or request.GET.get("var1", "default") if you want a default value in case it's not found.
In your template, you can access it with {{ request.GET.var1 }}.
For parameters in the url (url/poney/unicorn):
You need to configure the url to capture the part you want, and you need to have a parameter in the receiving view to get the one in the URL:
def new_opportunity_confirm(request, account_manager):
You can then access it like any other variable, and send it to your template if you want to have access to it there.
Again, that second way does not seem fitting to what you want to achieve.
You were halfway there, you just mixed a little bit of both methods.

Related

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.

Django not passing data to views on POST request

I've created a drop-down menu that is supposed to pass data to a view that'll help filter a queryset. However, it doesn't seem like the data is actually being passed to the view. Below is the relevant code I've written.
template.html
<!-- Query based content for dropdown menu -->
<form method="POST" action="{% url 'property-selected' %}" id="property-select">
{% csrf_token %}
<select class="dropdown-content" onchange="this.form.submit()" name="property-select">
{% if current_user_meters %}
<option disabled selected> -- select an option -- </option>
{% for meter in current_user_meters %}
<option class="dropdown-menu-option" value="{{meter.id}}">{{meter.name}}</option>
{% endfor %}
{% else %}
<option>You don't have any meters</option>
{% endif %}
</select>
</form>
views.py
def property_selected(request):
if request.method == 'POST':
selection = request.POST.get('property-select')
current_user_groups = Group.objects.filter(
id__in=request.user.groups.all()
)
current_user_properties = Property.objects.filter(
groups__in=current_user_groups
)
current_user_meters = Meter.objects.filter(
meter_id__in=current_user_properties
)
selected_meters = Meter.objects.filter(name=selection)
selected_meter_data = MeterData.objects.filter(
name=selection
).order_by('date')
return render(request, 'properties/property-selected.html', {
'current_user_meters': current_user_meters,
'selection': selection,
'selectected_meters': selected_meters,
'selected_meter_data': selected_meter_data,
})
For the querysets in the views file, the selection variable doesn't seem to be getting anything, which is where I want the data from the POST request to go. I want the data from the POST request to go there so my selected_meters and selected_meter_data queries will work as intended.
The values in the property-select options are IDs, but you are trying to filter MeterData by name with those values. Either filter by id, or use the name attribute as the option values.
You need to either use a form to ingest your data (thereby providing cleaning and validation) or access request.body instead of request.post, and then parse it for yourself.
From the documentation, emphasis mine (https://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpRequest.POST):
HttpRequest.POST¶ A dictionary-like object containing all given HTTP
POST parameters, providing that the request contains form data. See
the QueryDict documentation below. If you need to access raw or
non-form data posted in the request, access this through the
HttpRequest.body attribute instead.
It’s possible that a request can come in via POST with an empty POST
dictionary – if, say, a form is requested via the POST HTTP method but
does not include form data. Therefore, you shouldn’t use if
request.POST to check for use of the POST method; instead, use if
request.method == "POST" (see HttpRequest.method).
I'd recommend passing the request into a form. It gives you some nice functionality down the line, and lets you avoid parsing request.body for yourself, even if it's an extra step.

what is the best way to use less Django template syntax as possible with Django Form?

I am just beginner of Django.
At first, It seemed very convenient to use Django Form. I can get all which i already I defined in Model with ModelForm class. I can just put { form } in template. There are already pre-defined Field type and I can use it conveniently.
But it is tricky if you need to work with one who doesn't know Django or Python and are charge of making front-end part.
For example, I make template like this.
example.html
<form action="." method="post"> {% csrf_token %}
{{ form }}
<input type="submit" value="ok">
views.py
class TestView(FormView):
template_name = 'example.html'
form_class = TestForm
success_url = '/success/'
def form_valid(self, form):
print('data is validated! you can do work with cleaned data!')
return super(TestView, self).form_valid(form)
Q1 : A front-developer can't work with {{ form }}. right?
So I can change just example.html because it works properly if you set name attribute and type attribute correctly.
example.html
<form action="." method="post"> {% csrf_token %}
<input type="text" name="name">
<input type="text" name="calorie">
<input type="submit" value="Ok">
</form>
models.py
class Cereal(models.Model):
name = models.CharField(max_length=50)
calorie = models.CharField(max_length=50)
Q2 : I think it would be fine for a front developer to work with it if I change example.html above? right?
Well, if my questions are all fine, It seems fine to use ModelForm and write html code instead of {{ form }} django template syntax. But if you use ModelChoiceField, it seems nasty. You set queryset argument and it shows with select widget on template. for example queryset reqsult is { A, B, C }. it will turn to like below
<select id="id_something" name="name of something">
<option>A</option>
<option>B</option>
<option>C</option>
</select>
As i told you earlier, I don't want to use Django template syntax like {{ form }} as much as I can. so I am going to write like below instead.
views.py
render(request, "example.html", {queryset : something.objects.all()})
example.html
<select id="id_something" name="name of something">
{% for element in queryset %}
<option>{{ element }}</option>
{% endfor %}
</select>
Q3: does this approach seem alright? Isn't it better way to use less Django template syntax when you use Django Form?
well, I concluded that using DRF(Django RestFramework) is the best way to separate tasks for front-end and back-end developers independently. But In current situation I am facing, Template(html, css, js) is already made. I need to change it to use with Django framework. Front end developer will change little bit with the Template which is already made.
When I watched some pycon video in Youtube, some people said that Djang framework is kind of too much coupled.
I hope I can get Idea more efficiently to use Django Model form with front-end developer.
Thanks for reading. My question could be ridiculous for an expert. Please ask me again if it is not clear.

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.

Categories