dynamic forms in django with ajax/dajax - python

I have this simple form with a queryset to display job objects and allow the user to select one. Now, i would like to have a group of two radio buttons that would allow the user to select a 'filtering option'. If the user selects a group filter with the radio buttons, i would a drop down to appear that allows them to select which group they would like to filter on. I want to do this without having to reload the page, so i'm attempting to use dajax.
I was able to find an example on the dajax website that does something similiar, however, i was not able to get it to work. The radio buttons appear and the drop down appears(empty). When i click on the "Group" radio button, the drop-down should populate with all my Group objects, but it doesnt.
I've been stuck on this for awhile, so any help would be greatly appreciated.
forms.py
filters = (('0', 'Group'),
('1', 'Host'),
)
class JobSelectForm(forms.Form):
def __init__(self, *args, **kwargs):
super(JobSelectForm, self).__init__(*args, **kwargs)
self.fields['jobs'].widget.attrs["size"] = 20
jobs = forms.ModelChoiceField(queryset=Job.objects.all().order_by('name'), empty_label=None,)
filter = forms.ChoiceField(choices=filters,
widget=forms.RadioSelect(attrs={'onchange': "Dajaxice.tdportal.updatefilter(Dajax.process,{'option':this.value})", 'name':'combo1', 'id':'combo1', },
renderer=HorizRadioRenderer),
ajax.py
def updatefilter(request, option):
dajax = Dajax()
options = [Group.objects.all(),
Host.objects.all(),
]
out = ""
for o in options[int(option)]:
out = "%s<option value='#'>%s" % (out,o,)
dajax.assign('#combo2','innerHTML',out)
return dajax.json()
dajaxice_functions.register(updatefilter)
template
{{selectForm.filter.label}}: {{selectForm.filter}}
<br>
<select name="combo2" id="combo2" onchange="" size="1"></select>
<br><br>
<form method="post" action="/tdportal/jobs/">{% csrf_token %}
{{selectForm.jobs}}
<br><br>
<input type="submit" value="Edit" /> <input type="button" name="new" value="New" />
</form>

You need to add your dajaxice function to the select onchange to reference your function in the template.
Something like:
<select name="combo2" id="combo2" onchange="Dajaxice.your_project.your_appname.updatefilter(Dajax.process,{'option':this.value}" size="1"></select>
(Replace your_project with your project name, your_app with your appname).
Also make sure in your template you have all the necessary headers (and that they actually are there; e.g., if you view the source that you can click to them).
Be sure to debug using google chrome inspector (Ctrl-Shift-I) or firebug (in firefox).
EDIT: I now noticed that you have something similar that's in your form. How does it render in the HTML when you view the source? Is it improperly escaped?

I think you forgot a % sign (value='#') and a closing </option> in here:
out = "%s<option value='%s'>%s</option>" % (out,o,o)

Related

Django: How do you use an image in your template and let your views.py know it was pressed like a button?

I want to show an image that the user can click on that will act like a button and return the data to my views.py.
For example,
<input type="submit" value="Add Selected Other Service to Included Service" class="button" name="Add Other Service"/>
will create a very long button which I can "grab" in my views.py with:
add_other_service = request.POST.get('Add Other Service')
I can then test add_other_service and term if that was the button pressed. Hence, I can have multiple buttons on the page and determine which one as pressed.
I know I can use the tag with the type="image" to click on the image, but I cannot find a way to get name of the button in the views.py.
After trying different variations to see if I could get:
<input type="image" src="{% static 'addAndReturn.svg' %}" width="48" height="48"
name="addAndReturn" class="btTxt submit" title="Add & Return to Edit"/>
to work and looking for:
add_and_return = request.POST.get('addAndReturn')
in my views.py, I finally printed out the request.POST and found:
'addAndReturn.x': ['36'], 'addAndReturn.y': ['30']
I do not know html enough to realize I'd get this type of data. When I searched for getting the data from the image, I found out about getting the actual image and not to determine if the image was clicked so I added this to help others look to use the image like a button that returns to the views.py post() and not just use another URL.

How can I create a submit form in Django with a dropping down list?

I am just starting to work with Django and I have some problems with forms and dropping lists.
I have a model with two attributes, and I want to display one of the attributes in a dropping down list (this one will be unchangeable) and another one in a text field (this one will be changeable). Also, I have a submit button, so I want to change a second attribute in a text field and by pressing on the button. How can I do this? What would some examples be?
As you are starting to work with Django, you might or might not know about how Django handle forms.
In Django, forms can be handled in two ways:
User-created and managed forms (without any form class)
Class-managed forms (connected to Django models)
Documentation form Django Forms
Now let’s talk about the first type of forms (where you create your HTML form and manage the request sent to server):
These forms are simple to make and when there are only a few and are only suggested when you have a very small amount of inputs (I would say four or fewer inputs).
Here is a simple example of subscription of a newsletter with an email example.
<form id='sub-form' method="POST">
{% csrf_token %}
<div>
<input type="email" name="sub_email">
</div>
<input class="button" value="Subscribe" type="submit" id="subbutton">
</form>
So a very important thing to look at here is {% csrf_token %}, about which you can read more about here and about how it works and prevents cross-site request forgery. This token will be required when you make a request to Django server with any post request and data.
In this subscription form you see one <input> with name="sub_email". Take note of this as we will use this to get this value on the server as this is the key to its value, and then a simple Submit Button.
When you press Submit on a page let’s say url = "http://BASE_URL/home" you will receive a POST request on the view that handles that URL.
So now coming to the view.py, let’s say you only allow registered users to subscribe then the view will go something like this (assuming you are not expecting any other request from the home URL).
def home(request):
user=request.user
if request.method == "POST":
if user.is_authenticated:
email = request.POST['sub_email'] #Using name of input
#Logic to save this email
return HttpResponse("You are Subscribed",status=200)
else:
return HttpReposnse("You are not Authenticated",status=401)
else:
return render(request,"home.html")
Now as you are the expert of simple forms, let’s work with Django class-based forms.
These views are a little work when you have very few inputs, but they are a great help in manageability and when you have to work with large number of inputs.
You will request these Class Based Forms as in your question you are trying to send an instance of a model from your Models.py to a form to user.
I have a model of Posts that can be used for this example:
class Post(models.Model):
postTitle = models.CharField(max_length = 90,null=True)
subTitle = models.CharField(max_length = 160,null=True)
location = models.CharField(max_length = 3,default = 'IN',null=True)
Now according to your question, you are trying to let the user change one attribute, let’s say postTitle and for location you are not letting the user select one of the countries which is preselected and for your post.
Now we have to create a form for this. Forms in class based are created in Forms.py. If you don't have forms.py then you can create one right along models.py and views.py.
Now for the form, I would like to edit some existing data as you are saying one of the attributes (Fields) is fixed and another editable, but you get the value from the model.
class PostEditForm(ModelForm):
location = forms.CharField(label='Country ',widget=forms.Select(attrs={'class': 'Classes_HERE','placeholder':' Select a Country','disabled':'disabled'} ,choices=country_list),required=True)
class Meta:
model = Post
fields= ['postTitle','subTitle','location']
labels = {
'postTitle':'Title',
'subTitle':'Sub-Title',
}
widgets = {
'postTitle': forms.TextInput(attrs={'class': 'mention_class_here','placeholder':' Add Title'}),
'subTitle': forms.TextInput(attrs={'class': 'mention_class_here','placeholder':' Add Sub-Title'})
}
Attributes can be mentioned in forms fields the way I have mentioned them in the above example. I used disabled="disabled" to disable (not editable) location field and used forms.Select to make it drop down.
You might also see that I gave the location field a list to choose from. This is how you can create a list of your items. It's been quite some time when I wrote this, so there might be errors or it may not work for you, so just make sure you are referring to the current documentation and searching Stack Overflow for answers.
country_list = [
('', 'Select a Country'),
("AF", "Afghanistan"),
("AX", "Aland Islands"),
("AL", "Albania"),
("DZ", "Algeria"),
("AS", "American Samoa"),
("AD", "Andorra"),
("AO", "Angola"),
("AI", "Anguilla"),
("AQ", "Antarctica"),
("AG", "Antigua And Barbuda"),
("AR", "Argentina"),
("AM", "Armenia"),
("AW", "Aruba"),
.
.
.
Now this form can be passed as context in a view to an HTML page.
def editPost(request,post_id):
user=request.user
post = get_object_or_404(Post,id=post_id) #Getting the instance of Post
if user.is_authenticated:
formPost = PostEditForm(request.POST or None,instance=post)
if request.method=='POST':
if formPost.is_valid():
savedPost=formPost.save()
else:
return render(request,'postEdit.html',{'formPost':formPost})
else:
return HttpResponse("Not Authorized",status:401)
Now your HTML file postEdit.html should look something like this:
<form id="post-form" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<div>
{{formPost}}
</div>
</form>
That is it and adding a submit button in the same form, you can now edit your instance of post that you passed along with this {{formPost}}. Combine your logic wherever you think needs a change to fit in what you want to do.
By no means I am saying all this code is in working condition, but it is shown only to illustrate the flow and working.

Create a Flask Search Bar that Inserts URI Variable with url_for()

I have a Flask site that has a 'search bar' where you type in the location ID of a particular location and then click Submit to be taken to the page for that location, if it exists. Here's the current form action:
<form id="locationinfo" action="{{ url_for('location') }}">
When you click Submit you are taken to /location?info=SITEID and that works just fine. What I want to do is change this behavior slightly so that when a user clicks Submit they are taken to /location/SITEID/ instead. I have the decorator set up in my main Flask routes file, but I'm struggling to put the pieces together to get this simple form together.
#app.route("/location/<locationid>/")
def locations(locationid):
...
return locationid
Any direction would be greatly appreciated!
[Edit with current full form code]
#app.route("/location")
def location():
location_id = request.args.get("info")
<form id="info" action="{{ url_for('location') }}">
<input type="text" name="info" id="locationfield">
<button type="submit">Go!</button>
</form>
You can't change how HTML forms submit their fields, they will always be in the query string or body (POST). One option is to use JavaScript to override the submit event to perform your own submit and re-render with the results.
A simpler solution is to redirect to the nice url after submit. This keeps the "search" action separate from the "show" action (even if they are handled by the same view).
#app.route('/location/')
#app.route('/location/<int:id>/')
def location(id=None):
# redirect to the second form if the id wasn't in the path
# raises 400 error if id wasn't in the query
if id is None:
return redirect(url_for('location', id=request.args['info']))
# id is in the path, continue
...
You can expand this later if you want to search by something besides id. Perform the search then redirect to the found id.

Add editable choices in django

I am trying to add a editable choicefield in django like the picture, already do some research on this. Unfortunately, the solution like django-autocomplete doesn't quite fulfill my needs. The autocomplete looks fine, but if do so, I need create a django modal to generate the choices through a url view request, but in my case, it doesn't necessary to do that, I just need put these 3 choices for ip address in the dropdown list, and choose one of them then edit it or submit.
The solutions I found, but they are not very well fit my need:
Django admin: Change selected box of related fields to autocomplete
Django editable dropdown field
If you want to use just those three entries the quickest way is to use a datalist, it just needs to be added into your HTML somewhere.
<div id="page-wrapper">
<label for="ip">Network address</label>
<input type="text" id="ip" list="ip-datalist">
<datalist id="ip-datalist">
<option>192.168.0.0/24</option>
<option>10.0.0.0/24</option>
<option>172.16.0.0/24</option>
</datalist>
</div>
If your options are likely to never change, you could hardcode them into your html like the answer above. If you're generating your dropdown using a form however it would be better to do something like this:
class MyForm(forms.Form):
ip_list = ((1, '192.168.0.0/24'), (2, '10.0.0.0/24'),
(3, '172.16.0.0/24'), )
network_address = forms.ChoiceField(label='Network Address',
choices=ip_list)
...
Once you render the form object in your template it ends up producing html like this:
<label for="id_network_address">Network Address:</label>
<select id="id_network_address" name="network_address">
<option value="1">192.168.0.0/24</option>
<option value="2">10.0.0.0/24</option>
<option value="3">172.16.0.0/24</option>
</select>
This way it is easier to change the ip_list in future if you need to, plus its keeps all your code in one place. This is explained in the docs here.

menu tab highlighting issue in Django

views.py
def edit_report(request, report_id):
"""Edit report navigation from action needed screen
"""
user = request.user
if 'report_id' in request.session:
del request.session['report_id']
try:
member = Members.objects.get(member=user)
account_user = member.user
except:
account_user = user.id
request.session['report_id'] = report_id
request.session['account_user'] = account_user
return redirect('incident.views.new_report')
template.html
<td class="irlist-num">{{list.report.incident_number}}{%if list.report.is_draft%} DRAFT{% endif %} </td>
Now,when a new report is created using New Report tab,that tab will be highlighted.
The above view is for editing a report.In template,if the user clicks the report name link({% url incident.views.edit_report list.report.id%}),it will takes the user to edit that particular report.Since this report is open under New Report Tab, New Report Tab is highlighted.I want to customize this to not highlight while open a report via this edit_report.
I am thinking to validate it using session in report_id,so if this report_id is in session the New report menu should not highlight,but i updated the tried code ,still it doesn't worked for me.Need help
Thanks
Without seeing the code for the new_report view, it looks like it must be loading the correct report info based on session.session['report_id']. I think rather than passing things like that around via the session, you should probably just pass it as an argument to the new_report view when you call redirect (see link for django docs on redirect). Note that you'd also have to edit your view definition doing this.
Better yet, combine edit_report and new_report into a single view, if you've got almost all of the edit functionality in edit_report already.
Anyway, back to the question being asked. You can check if the report_id is set in you session in the new_report view (I assume you're doing this already). Then based on this, you can pass a variable in a RequestContext to your template
Views.py
def new_report(request):
view_template = loader.get_template('template.html')
if 'report_id' in request.session:
highlight_new_report = True
else:
highlight_new_report = False
view_context = RequestContext(request,{
'highlight_new_report' : highlight_new_report
})
return HttpResponse(view_template.render(view_context))
Then wherever the menu is in your template (note that this could very likely be in a base template being extended by your_template.html), you can use this to decide what class to add to the tab/link. There is probably something there already adding a class to highlight it, you should be able to override this based on the highlight_new_report variable which is now available in your template
template.html (or a template template.html extends)
<!-- Menu tabs -->
<a href="/new_report"
{% if highlight_new_report %}
class="highlighted_tab">
{% endif %}
</a>
Edit for more info
Sorry should have been clearer. The above code is an example of how you can set the class based on your report_id, but I left it unspecific because I didn't know what your template would look like.
If you've used the above code to add a CSS class which removes the highlight, then you can add another class which will add a highlight:
template.html (or a template template.html extends)
<!-- Menu tabs -->
<a href="/new_report"
{% if highlight_new_report %}
class="highlighted_tab"
{% else %}
class="non_highlighted_tab">
{% endif %}
</a>
Where highlighted_tab is a class which adds a highlight, and non_highlighted_tab is one which doesn't, or which overrides a highlight styling already being applied.
The reason I didn't write the answer this way to begin with, is because you probably already had something like class="active" being added based on the current page. So I expected you to use a condition like that above, to restrict the addition of this active class to when highlight_report = True
It is possible to do using session.
By seeing this bit of code,i understand that you are creating a session for new report.But what you are trying to do is not possible to handle with the same session.
I think,for new report and edit report their are two different methods.If this is the case its easy to handle.
Let us see this,
1.You should create a session in edit report method.
2.Should validate,whether that session is in new report,if that newly created session is in new report should set new_report=False and pass to render.
3.You should delete that newly created session in new report method,if not then menu will always be not highlighted.
As per the above one,if the user clicks report from {% url incident.views.edit_report list.report.id%} or edit report menu,the newly created session gets started from edit report method and will be available.
Hope this gives you an idea.

Categories

Resources