Set a variable through a drop down list in django - django

def scan(request):
scan = Stock.objects.all()
hammer = Stock.objects.filter(Hammer=100)
belthold = Stock.objects.filter(Belthold=100)
context = {'All':scan, 'Belthold':belthold, 'Hammer':hammer
}
return render(request, 'scanner/scan.html', context)
This is my views.py file. I want to add a dropdown list to my html page containing the context dictionary which changes the query filters according.
This is my current html page:
{% for i in Hammer %}
<tr>
<td>{{i.script}}</td>
<td>{{i.open}}</td>
<td>{{i.high}}</td>
<td>{{i.low}}</td>
<td>{{i.close}}</td>
<td>{{i.Volume}}</td>
<td>{{i.Change}}</td>
</tr>
{% endfor %}
The 'Hammer' need to be replaced by whatever selection is made from the dropdown list.
THANKS!!

You cannot dynamically change Hammer in a template for loop. You can use the approach below or change the approach as to how you want everything displayed.
You have to use Javascript for that. You first need to give id's to all the tags you have in the for loop.
<td id="{{i.script}}_myid"> ...
Then with Javascript access the change in the dropdown menu's value and then update the respective td's accordingly:
document.getElementbyId('dropdown').addEventListener('change', function(e) {
// Change td's here: document.getElementbyId(..._myid).innerHTML = "" })
To pass Hammer in your JS you can either do an inline script (which many dont recommend) or a separate JS file added as a script tag below. You can use serializers to pass on the objects from Python to JS.

Related

Hiding ModelMultipleChoiceField on template for custom input

I want the user to select a number of elements belonging to a certain model. I don't want to use the default 'ctrl+click' input of django forms, but create a table of checkboxes myself.
For that reason I hide the ModelMultipleChoiceField by defining the widget:
field = forms.ModelMultipleChoiceField(..., widget=forms.MultipleHiddenInput())
Then I add the form element into the template as follows:
<form method="POST" class="locklist-form" id="locklist-form">{% csrf_token %}
{{ form.field }}
</form>
At this step, I expect the select-option elements to be added to HTML page (as hidden), so that I can reach to element options and modify them with javascript. However, it doesn't add anything to the HTML page.
I use this approach with other type of form fieds. For a TextField HTML page have a hidden element as shown:
Why doesn't it work with ModelMultipleChoiceField? How can I modify the choices of this field with Javascript?
Edit:
MultipleHiddenInput renders only if with initial data is a similar question. But applying it doesn't lead to the expected solution. In this question, it is expected to render the following as hidden:
But following the MultipleHiddenInput renders only if with initial data, when I modify the form constructor as:
form = MyForm(initial={'field':MyModel.objects.all()})
Rendered element is as follows:
It maybe useful, but not exactly the expected one. I need to mark a few options as selected, among a list of objects.
I have done it using Javascript, instead of depending on Django's capabilities. I add the form with ModelMultipleChoiceField directly to the template (not hidden). Then I run a Javascript script, when the page is loaded:
var field = document.getElementById('id_field');
selecter.setAttribute('class', 'hidden');
CSS definition of hidden class is as follows:
.hidden{
display: none;
}
This gets me to the desired situation. ModelMultipleChoiceField is rendered hidden as follows:
At this point, I can modify certain items through Javascript:
document.getElementById('id_field').options[index].selected = boolValue;

Django: For Loop in Views.py?

I want to keep my templates free of any logic - just html. I'm using a "for" loop in index.html to cycle through a list of posts. Here is the loop:
{% for recent in latest %}
<h1>{{ recent.title }}</h1>
<h2>{{ recent.category }}</h2>
{% endfor %}
What I want to do is in my Posts class, grab all the posts, checking that they match certain criterion, then place them in variables which could be sent to the template.
Here is the view (the logic of which I want to eventually move to models.py):
def index(request):
# Get latest five posts
latest_posts = Post.objects.order_by('-published_date')[:5]
# Get a single "top" category post.
top_post = Post.objects.get(category = 1)[:1]
# set up some contexts
top = {'front_post': top_post}
context = {'latest': latest_posts}
return render(request, 'home/index.html', context, top)
Any suggestions?
You're taking the idea of keeping templates free of logic too far. There's a reason template languages provide things like for loops and boolean logic: without them you will wind up breaking the separation of concerns that an MVC framework is trying to enforce. Because what you will wind up with is embedding presentation information in your view logic and that's not what you want. As a simplistic example, consider adding the option of viewing your posts as a text file without adding a second view. If you keep the markup in the templates, it's easy. If you don't, it's not possible.

Submit Button Confusion and Request being sent Twice (Using Flask)

I'm pretty much trying to create a web app that takes 2 svn urls and does something with them.
The code for my form is simple, I'm also using WTForms
class SVN_Path(Form):
svn_url=StringField('SVN_Path',[validators.URL()])
I'm trying to create 2 forms with 2 submit buttons that submit the 2 urls individually so my test3.html looks like this:
<form action="" method="post" name="SVNPath1">
{{form1.hidden_tag()}}
<p>
SVN Directory:
{{form1.svn_url(size=50)}}
<input type="submit" value="Update">
<br>
{% for error in form1.svn_url.errors %}
<span style="color: red;">[{{error}}]</span>
{% endfor %}
</p>
</form>
<form action="" method="post" name="SVNPath2">
{{form2.hidden_tag()}}
<p>
SVN Directory:
{{form2.svn_url(size=50)}}
<input type="submit" value="Update">
<br>
{% for error in form2.svn_url.errors %}
<span style="color: red;">[{{error}}]</span>
{% endfor %}
</p>
</form>
MY FIRST QUESTION is how do I know which submit button was clicked so I can run the proper function on the corresponding svn url. I have tried doing something like
if request.form1['submit'] == 'Update':
if request.form2['submit'] == 'Update':
but that does not work at all. I'm new to web dev in general and flask so a detailed explanation would be helpful.
SECONDLY, since submits weren't working properly I also tried an alternative to keep my work moving so in my .py file I have
#app.route('/test3', methods=['GET','POST'])
def test3():
basepath=createDir()
form1=SVN_Path()
form2=SVN_Path()
if request.method=="POST":
if form1.validate_on_submit():
svn_url = form1.svn_url.data
prev_pdf=PDF_List(svn_url,basepath,'prev') #some function
if form2.validate_on_submit():
svn_url2 = form2.svn_url.data
new_pdf=PDF_List(svn_url,basepath,'new') #some function
return render_template('test3.html', form1=form1, form2=form2)
CreateDir is a function that creates a directory in the local /tmp using timestamps of the local time.
Whenever I go the webpage it creates a directory, lets call it dir1, since its calling CreateDir. Thats what I want, but when I click submit on the form it creates another directory dir2 in the tmp folder which is NOT what I want since I want everything to being the same dir1 directory.
In addition when I put a url in one of the forms and click submit, it automatically puts it the same value in the 2nd form as well.
Sorry if this is really long and possibly confusing, but any help is appreciated.
:) Let's see if we can clarify this a little.
To your first question:
As #dim suggested in his comment, You have a few options:
You can submit your form to separate unique urls. That way you know which form was submitted
You can create two similar but different Form classes (the fields will need different names like prev_svn_url and cur_svn_url). This way in your view function, you instantiate two different forms and you'll know which form was submitted based on form.validate_on_submit()
The third option would be to add a name attribute to your submit button and then change the value attributes to something like 'Update Previous' and 'Update Current'. This way in your view function you can check the value of request.data[<submit button name>] to determine if 'Update Previous' was pressed or 'Update Current'.
To your second question:
Multiple directories are being created because you're calling createDir() each time the page is loaded to show the forms and when the forms get posted. In order to create just once, you'll need some kind of logic to determine that the directory was not previously created before calling createDir()
In addition: Since both forms are from the same SVN_Path class, they read post data exactly the same way, that's why whatever you type in form 1 appears in form 2.
Now for my 2 cents:
I assume you're trying to write some kind of application that takes two SVN urls as input, creates a folder and does something with those URLs in that folder. If this is the case, the way you are currently going about it is inefficient and won't work well. You can achieve this with just one form class having 2 svn_url fields (with different names of course) and then handling all of that in one post.
EDIT: The job of the submit button is to tell the browser that you're ready to send the data on the form to the server. In this case you should only need one submit button (SubmitFiled => when rendered). Clicking that one submit button will send data from both input fields to your view function.
Your form should look something like:
class SVN_Path(Form):
prev_svn_url=StringField('Previous SVN_Path',[validators.URL()])
new_svn_url=StringField('New SVN_Path',[validators.URL()])
and your view function:
def test():
form = SVN_Path()
if request.method == "POST":
if form.validate_on_submit():
basepath = createDir() # Only create dir when everything validates
prev_svn_url = form.prev_svn_url.data
new_svn_url = form.new_svn_url.data
prev_pdf = PDF_List(prev_svn_url, basepath, 'prev')
new_pdf = PDF_List(new_svn_url, basepath, 'new')
...
return render_template('test3.html', form1=form1, form2=form2)

djangocms-snippet which contains {% %} doesnot show up as placeholder content

I am trying to make my footer a editable from frontend.. using placeholder and inserting footer snippet.
yet, my footer snippet contains django template language
e.g.
Terms and Conditions
as a result, the placeholder content is not showing up, if i remove the django specific things
Terms and Conditions
it is working.
how can I make it work with django reverse url?
I could have given hard coded path but i want the path translatable so i need to reverse by url's name.
If I've got you right, just create custom tag and store templates in database:
from django.template import RequestContext, Template
#register.simple_tag
def footer(request):
snippet = Snippet.object.get(name='footer')
template = Template(snippet.html)
return template.render(RequestContext(request))
{% footer request %}
use this syntax:
{% url 'terms_conditions' as the_url %}
Terms and Conditions
use smartsnippets
These has the capability of rendering django tags

django-taggit create tagcloud from queryset

I could not find an answer for this.. So here my question. For a new project i'd like to use django-taggit.
Does someone have a suggestion on how to create a tag-cloud based on the current queryset?
The desired behavior is to 'start' with an unfiltered list - then allow narrowing town the results with applying filters and tags. At the beginning the tag-cloud shows e.g. the 50 most common tags. After choosing a tag (or other criteria) the tag-cloud should only display the remaining possibilities.
I know that django-tagging offers Tag.objects.usage_for_queryset() for this situation. But I would prefer to use '-taggit' over '-tagging'.
django-taggit-templatetags appears to be the 'go-to' place for a tagcloud for django-taggit.
It doesn't appear to handle querysets though. :(
So, I've added:
#register.inclusion_tag('taggit_templatetags/tagcloud_include_qs.html')
def include_tagcloud_qs(queryset):
try:
queryset = queryset.annotate(num_times=Count('taggeditem_items'))
except FieldError:
queryset = queryset.annotate(num_times=Count('taggit_taggeditem_items'))
num_times = queryset.values_list('num_times', flat=True)
weight_fun = get_weight_fun(T_MIN, T_MAX, min(num_times), max(num_times))
queryset = queryset.order_by('name')
for tag in queryset:
tag.weight = weight_fun(tag.num_times)
return {"tags": queryset}
to
templatetags/taggit_extras.py
And this to a new file at taggit_templatetags/tagcloud_include_qs.html
<div>
{% for tag in tags %}
<font size={{tag.weight|floatformat:0}}>{{tag}}</font>
{% endfor %}
</div>
I'm using it like this in my templates:
{% include_tagcloud_qs my_queryset %}
I haven't spent much time looking at the django-taggit-templatetags code, so feel free to update this with a better solution!
PS:
I'm getting a queryset in my view like this:
my_queryset = Tag.objects.filter(foo__bar=baz).distinct()
This answer shows how to build a tag cloud. You'd create a queryset in your view according to your parameters, generate a dictionary, and render it in your templates as shown in that answer.
I would suggest using django-tagging. It is well documented. I have created tag clouds with it. You can access tag clouds via model, model instance, etc via template tags that are easy to load. This is a little hackish but using the .counts method you can hack up some css to increase the size of each font as you would see in a real tag cloud. Django-tagging actually excels in this area as it has a default template tag with formatting options for everything you have described.
I've added a TagBase.get_for() function in https://github.com/twig/django-taggit/commit/42cd4e04f00496103f295c0afd8297074be50dcf
This basically fetches the Tags used for a given queryset, and from there you can do what you need to do.