I want to be able to change my comments queryset without page refresh. Here are the querysets:
comment_list = Comment.objects.filter().order_by('-score__upvotes')
new_comments_list = Comment.objects.filter().order_by('-timestamp')
Then my template is
{% for comment in comment_list %}
{{ comment }}
...
Is there any way to change {% for comment in comment_list %} to {% for comment in new_comments_list %} using AJAX (no page refresh)?
Or possibly changing the value of comment_list to equal Comment.objects.filter().order_by('-timestamp')?
EDIT
view:
def new_comments(request):
if request.is_ajax():
print('ajax') #prints ajax
comment_list = Comment.objects.filter().order_by('-timestamp')
html = render_to_string('article.html', {'comment_list': comment_list})
return HttpResponse(html)
ajax call:
$('.comments_new').on('click', function() {
$.ajax({
type: 'GET',
url: '/new_comments/',
data: {
csrfmiddlewaretoken: $("input[name='csrfmiddlewaretoken']").val(),
},
success: function (data) {
console.log(data.comment_list); // undefined
}
})
});
What I guess, you are trying to use comment_list when page renders and new_comment_list using ajax without modifying
{% for comment in comment_list %}
{{ comment }}
{% endfor %}
The problem with your code is comment_list is a queryset and it is evaluated on the server side, when the page is rendered (after passing through Django template engine ).Javascript doesn't understand queryset. It understands HTML or JSON. So, you have to modify your script so that it return HTML or JSON for ajax request.
I would suggest you re-write your view like:
from django.template.loader import render_to_string
if request.is_ajax():
new_comments_list = Comment.objects.filter().order_by('-timestamp')
# you can keep your_div_template as a included template in your main template
html = render_to_string('your_div_template', {'comment_list': new_comments_list})
return HttpResponse(html)
And write your frontend to generate this HTML code.
here is a link that gives more better explanation of rendering using ajax: Returning Rendered Html via Ajax
Related
I have comments on a product on the page. and there is a button to add a comment, which puts a new comment into the database. How can I automatically display a new comment on a page?
mytemplate.html
<div id="comments">
{% include 'comments.html' %}
</div>
comments.html
{% for comment in comments %}
<!-- some code for display comments -->
{% endfor %}
script.js
$("#addComment").on("click", function(e){
e.preventDefault()
if ($("#addCommentArea").val() != ""){
data = {
commentText: $("#addCommentArea").val(),
product_id: "{{ product.id }}"
}
$.ajax({
type: "GET",
url: "{% url 'newcomment' %}",
datatype: 'json',
data: data,
success: function(data){
$("#addCommentArea").val("")
}
})
}
})
views.py
class CommentView(View):
def get(self, request):
commentText = request.GET.get("commentText")
if (len(commentText) > 0):
newComment = Comment()
newComment.Author = request.user
product_id = request.GET.get("product_id")
product = Product.objects.get(id=product_id)
newComment.Product = product
newComment.Comment = commentText
newComment.save()
return JsonResponse({'ok': 'ok'})
Currently, you just render the template once and fetch the comments, further you are using Ajax to submit, which means your template doesn't get updated. To update the comments without a page refresh you can either make a javascript polling or use for example web sockets
I have a template which allows user to enter search parameter (search.html)
{% from "_formhelpers.html" import render_field %}
<form method=”post”>
<dl>
{{ render_field(form. notificationId) }}
{{ render_field(form. recordName) }}
</dl>
<div id="searchResults" > </div>
</form>
Macro
{% macro render_field(field) %}
<dt>{{ field.label }}
<dd>{{ field(**kwargs)|safe }}
{% if field.errors %}
<ul class=errors>
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</dd>
{% endmacro %}
And a template for search results(result.html)
{% for notification in content %}
Result:
content[notification]['type'] }}</td>
{% endfor %}
I am using the following ajax request to get search results and display in the above template.The ajax function is called on keyup of both the search fields
$.ajax(
{
url: ‘result’,
dataType: "html",
data:createQueryString(),// gets the value from the dataFields and creates a queryString
success: function(data)
{
$("# searchResults").html(data); } });
I also I have 2 views one for the searchcriteria section( the section containing the 2 search fields) and one for the search results section.
class NotificationSearchView(MethodView):
def get(self):
searchform = SearchForm()
return render_template("search.html”, searchform=searchform)
#classmethod
def registerSelf(cls, app):
NotificationSearchView.app = app
app.flaskApp.add_url_rule('/search ', view_func=NotificationSearchView.as_view(‘search’))
class NotificationResultView(MethodView):
def get(self):
searchform = SearchForm()
success, content=self.performSearch(searchform) //search method which takes the search parameters and performs the search
return render_template("result.html”, content=content)
#classmethod
def registerSelf(cls, app):
NotificationResultView.app = app
app.flaskApp.add_url_rule('/result', view_func= NotificationResultView.as_view(‘result’))
WTF form class
from wtforms import Form, TextField
class SearchForm(BaseForm):
notificationId = TextField(notificationId)
recordName = TextField(recordName)
The issue which I am facing is that the wtf form object isn’t populated when the ajax call is made to the NotificationResultView, which I believe is because there is no post request fired, but according to my design there is no need of a post request.
I have tried by making the ajax request as post request but even then the wtf form object comes back empty.
Now my only other option is if I pass the search criteria in the query string when making the ajax call, but not sure if that’s the best approach.Please suggest how to proceed in this case.
$.ajax(
{
url: ‘result’,
dataType: "html",
success: function(data)
{
$("# searchResults").html(data); } });
In your ajax function you aren't sending any data.
update : ok, so you are actually sending data and url is correct.
class NotificationResultView(MethodView):
def get(self):
searchform = SearchForm()
success, content=self.performSearch(searchform) //search method which takes the search parameters and performs the search
return render_template("result.html”, content=content)
from above your view function (which is routed to 'result'), your problem is that searchform = SearchForm() isn't filled with supplied GET queries.
To solve this you have to supply the values to searchform. there are many ways to do it(the most obvious one would be fiddling with form object creation, by searchform = SearchForm(formdata = request.args)), and it can be done easier by using flask extension flask-wtf.
here is one way to to do it(I'll provide my example since I don't know how you build your query string) :
in html:
query_obj = { foo : 'bar', bar : 'baz', answer : 42 };
$.params(query_obj); //foo=bar&bar=baz&answer=42
/* ajax using above params */
with assumption that parameters are successfully supplied to the view:
#app.route('/result', method=['GET'])
def fooview():
foo = request.args.get('foo', '')
bar = request.args.get('bar', '')
answer = request.args.get('answer', None, type=int)
..
hope that helps.
In my Django-template:
<div class="A">
{% url renders_data object.id %}
</div>
<div class="B">
{% render_data object.id %}
</div>
Div A is common way to call a method in views.py whereas Div B is for template tags.
User will open a link. Let's say: /myapp/test/ a page will open contain two template tag section at the page. Name of this tag is render_data I want to load the data into each template tag with Ajax. To work with it we need request.ajax:. That is why i thought to write views method. I thought to complete it with the following way:
I wrote the exact copy of template tag in views.py (renders_data with passing object_id parameter) and render it to the right template. When i open the maypp/test after removing the div A from template. It shows the URL (myapp/test/<object_id>) in each template tags section (each corner) except the data. Is their any possibility to show the context except this URL See the image when i choose this option
Second i also thought to import views method (renders_data) in template tag (render_data). So that data will display in each corner and request.Ajax: will also work. if this can be possible then how?
I am not able to solve this issue. please help me :(
See how the render_data looks like:
#register.simple_tag
def render_widget(object_id):
from myapp.plugins.model import Widgetsetting
widget_setting = Widetsetting.objects.get(id = object_id)
widget = widget_settings.get_widget()
template_name = widget.template_name
context = widget.context(widget=widget_settings)
t = get_template("widgets/%s" % template_name)
return t.render(Context(context))
From the code you've posted something like below should work...
in views.py:
from django.http import HttpResponse
from netadmin.plugins.templatetags.widgets import render_widget
def ajax_render_data(request, object_id):
return HttpResponse(render_widget(object_id))
in your django template:
(you said you want several of these on the page, so I'm going to use a loop in the django template, I don't know what your widget collection is called but I'm sure you can work it out for your particular case)
<div class="widgets-container">
{% for widget_settings in widgetsettings.objects.all %}
<div class="widget-content" id="widget-content-{{ widget_settings.pk }}">
not loaded yet
</div>
{% endfor %}
</div>
<script>
// here we use django to render the ajax urls into an object
// in javascript so we can use it on the client side
var ajax_urls = {
{% for widget_settings in widgetsettings.objects.all %}
"{{ widget_settings.pk }}: "{% url ajax_render_data widget_settings.pk %}"{% if not forloop.last %},{% endif %}
{% endfor %}
};
// (I'll assume you're using jQuery)
// start the ajax calls when the page is loaded:
$(document).ready(loadWidgets());
function loadWidgets() {
// loop over the urls we provided from django:
jQuery.each(ajax_urls, function(widget_id, url) {
// do the ajax call:
$.get(url, function(data) {
// put the content into the widget div:
$('#widget-content-'+widget_id).html(data);
});
});
}
</script>
in urls.py:
urlpatterns += patterns('netadmin.plugins.ajax_view',
url(r'^ajax/(?P<object_id>\d+)/$', 'ajax_render_data', name='ajax_render_data'),
)
In Django Views:-
if request.is_ajax():
t = get_template('bar-templates.html')
html = t.render(Context({'edit': True, 'user':'some-user' }))
return HttpResponse(html)
There is two templates:
Main template (foo-templates.html) which includes the template (bar-templates.html). In context edit and user is passed to the bar-templates.html But this variable is also used in foo-templates.html. In django we used to {{ edit }} to catch the variable. Since this variable comes in bar-templates.html. How can I use this to foo-templates.html.
foo-templates.html:
{% extends "base.html" %}
<div class="container">
{{ edit }} // Here I am not getting the edit value
{% if edit %} // I need this edit value. But this value is in context with `bar-templates.html`
do something
{% else %}
do something
{% endif %}
<div class="content">
{% include "bar-templates.html" %}
</div>
bar-templaes.html
{{ edit }} // Here It gives me the edit value
This is the templates which I am sending from views.
How to use the included template variable values to the template where it get included.
Using details from your other post, which you should edit to include into this one:
From what i can tell, you are trying to add a "selected" class to your sidebar menu. This won't work for you because as gcbirzan said, you aren't going to be able to get the context of your ajax response into your base template. On top of that you aren't going to re-render the base template so it wouldn't be changing anyways.
Using javascript you can extract the foo_id from your part.html. Since that code isn't shown, lets say you have your foo_id in a hidden div, <div id="foo_id" style="display:none;">foo_2</div>
Now you can change your ajax function to something like this:
$.ajax({
type:'GET',
cache: 'false',
url:"/foobar/",
success:function(data) {
$('#main-content').html(data);
var $foo_id = $('#foo_id').val();
$('#foo1>ul>li.selected').removeClass('selected');
$('#'+ foo_id).addClass('selected');
}
});
If you simply render foo:
t = get_template('foo-templates.html')
html = t.render(Context({'edit': True, 'user':'some-user' }))
then 'foo' and the included 'bar' both have the same value for 'edit'.
I don't completely understand your question, but have I answered it?
I would like share with you how I am doing my Ajax stuff with Django for the moment. I would like have your advices/comments to see if I am doing it right.
I will of course oversimplified the code, just to show the process.
Here is my template code:
<!-- I store the full url to access object details so I can use url feature.
If I just store the pk, I would have to hardcode the url to fetch the object
detail later. Isn't it? -->
<ul>
{% for item in items %}
<li url="{% url project.item.views.details item.pk %}">{{ item.name }}</li>
{% endfor %}
<ul>
<div id="details"></div>
<script>
$("li").click(function(elmt){
// I just reuse the url attribute from the element clicked
var url = $(elmt.currentTarget).attr('url');
$.getJSON(url, function(data) {
if (data.success) {
$("#details").html(data.html);
} else {
$("#details").html("Something went wrong");
}
});
});
</script>
Here is the code I use in my view:
def details(request, item_id):
item = Items.objects.get(pk=item_id)
# Just render a view with the details, and return the view
html = render_to_string("items/_details.html", {'item': item})
return HttResponse(simplejson.dumps({'success': True, 'html': html}), mimetype="application/json")
What do you think about my way to do that?
Thank you in advance for your help!
Nothing wrong with the Django code but you may want it to work for non javascript clients as well and use valid HTML:
<ul>
{% for item in items %}
<li>{{ item.name }}</li>
{% endfor %}
<ul>
$("a").click(function(){
// I just reuse the url attribute from the element clicked
// li does not have an url attribute
var url = $(this).attr('href');
$.getJSON(url, function(data) {
if (data.success) {
$("#details").html(data.html);
} else {
$("#details").html("Something went wrong");
}
});
return false;
});
def details(request, item_id):
item = Items.objects.get(pk=item_id)
# Just render a view with the details, and return the view
if request.is_ajax():
html = render_to_string("items/_details.html", {'item': item})
return HttResponse(simplejson.dumps({'success': True, 'html': html}), mimetype="application/json")
else:
#non ajax request rendering complete html
return render_to_response("items/detail.html", {'item': item})
I personally prefer using middleware to host web services since they allow you to not load Django in its entirety, but still access what you need to.
Still, using views for web services is certainly valid and works.