How can I render new HTML content in Django template? - django

I'm a beginner in Django.
In my template file, I have the following:
<select id="selectbox"></select>
<div id="containerdiv"></div>
Within the containerdiv, I can return a HttpResponse such as:
<form> <!-- some more input elements here --> </form>
so now I will have a new form within the div. The content of the form will change depending on the value of selectbox. However, I also have {% csrf_token %} tag within the rendered HttpResponse which is not being rendered properly. Is this even the correct way to work with Django?

You could load as many forms in the page by the following method
def formPage(request):
form1=FormA()
form2=FormB()
#as many as you want
return render(request,"example.html",{"form1"=form1,"form2":form2})
Then call the forms in the HTML pages as per the name specified in the view, and use vanilla JS to render form as per choice selected in the choice box
You can refer the following link: JS content manipulation

Related

Why is Django rendering one of my app's templates as plain text

I am working on a blog development in Django and there are different categories of posts or articles on category_list.html which have been created using ORM library and to each category i have added some articles using ORM library with the help of category slug which are rendered on category_view.html and problem is that list of categories are shown perfectly on category_list.html after adding from admin panel of django and when I click on any category name(contains get_absolute_url link), it takes me perfectly to category_view.html page but on category_view.html, data is shown in the form of text means renders the complete content of category_view.html in the form of plain text. All other templates are getting rendered by django perfectly but what is the reason that category_view.html is getting rendered as plain text? Please help me
def category_list(request,category_slug=None):
category=None
categories=CategoryList.objects.all()
# article=Article.objects.all()
return render(request,'category_list.html',{'categories':categories})
def category_view(request,category_slug):
category=get_object_or_404(CategoryList,slug=category_slug)
article=Article.objects.filter(category=category)
return render(request,'category_view.html',{'category':category},{'article':article})
My url.py contains the following urls:
path("",views.index),
path('category',views.category_list, name='category_list'),
path('<slug:category_slug>',views.category_view, name='story_by_category'),
This is link in category_list.html which takes me to category_view.html
<div class="row py-3">
{%for c in categories%}
<div class="col-lg col-12 homeimg" id="img1">
<h5>{{c.name}}</h5>
<img class="secimg border-info" src="{{c.image_url|default_if_none:'#'}}" alt="gameplay
videos">
</div>
{%endfor%}
</div>

How to process django url tags in context variables

I'm creating a django-based website where page content is stored in a model textfield with a detail view of the model displaying it. How can I put {% url %} tags in the content to link to other pages without hard coding links?
Putting the tag into the textfield will just print the tag as plain text. (or if inside an href create a broken link)
Other options are
parsing the content manually inside the view and replacing the tags with the correct url
using some django supplied string parser to create the links before sending to the template
maybe there is a way to do it in the template with a filter or tag around the variable.
I could probably do the manual way but I am hoping there is a django way that I am missing.
class Page(models.Model):
content = models.TextField(blank=True)
class PageView(DetailView):
model=Page
context_object_name='page'
{% extends "base.html" %}
{% block content %}
{{ page.content|safe }}
{% endblock %}
Edit for clarity:
Content in admin
What it renders
What it should render
Edit 2:
I was able to find a solution to the second option thanks to this answer on another question. Using that template_from_string function I rendered the page content as a template then replaced the content in the context with the rendered result.
class PageView(DetailView):
model=Page
context_object_name='page'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# Add to context here
context['page'].content = template_from_string(context['page'].content).render(context)
return context
your url's will have a name as shown below-
path('page//',PageView.as_view, name="page-detail")
and in your Page Detail
hope this is what your asking for
Let see if I understood you well, do you want django to show you a url as such and not as plain text?
If you want to avoid django to show you the data as plain text, you can use the escape filter as follows: {{string | escape}}
Check this page for more details about django filters and tags

How do I use AJAX for pagination in Django-Tables2?

I am using django-tables2 and I am trying to display the data of the next page without loading another page. I think AJAX could be used.
From what I have found, it seems that it might not be possible.
There has been some discussion about this Support AJAX sorting/pagination
Is there something that I should look at to figure it out ?
It is possible however it's not so easy since django-tables2 (and django in general) are geared more to the Server Side Rendered world. I will sketch a solution here and consider that interesting topic for my blog (https://spapas.github.io):
You'll need to override the django-tables2 template that'll be used. You can't use the default one since the pagination to it is done by normal links. You should override it to use Ajax calls - take a look at this question for more Is it possible to custom django-tables2 template for a specific page in this case?. What you have to do is disable the default link functionality of the page links and call them through ajax. Depending on how you're going to do it this may be possible to be done through a script in your view's template without the need to override the table template at all.
You'll need to modify your view to detect if it's called by ajax (i.e through these pagination buttons you've defined above) or not and return a different template each time. If it's called normally then you'll just render your classic template. If it is called through ajax then it will return only the portion of the html that only contains the table.
Now in your normal template you'll put the table inside a div named (f.e) #the_table - when the user clicks on a pagination link you'll do the ajax call and the response will contain only the table - you'll then replace the contents of the #the_table div with what you just received.
So you should have two templates for your view, your view.html which will be something like:
{% extends base.html %}
{% block content %}
blah blah
<div id='the_table'>
{% include 'partial_table.html' %}
</div>
{% endblock %}
{% block extra_script %}
<script>
// You can do something like (NOT TESTED):
// I don't remember if the pagination links belong to a class
// if not you may want to add that class yourself
$('pagination-link').click(function(e) {
// Don't follow the link
e.preventDefault();
// Do the ajax request
$.get($(this).attr("href"), function(data) {
// Replace the table with what you received
$('#the_table').html(data)
});
});
</script>
{% endblock %}
And your partial_table.html:
{% load django_tables2 %}
{% render_table table %}
Now in your view if for example you are using CBVs then you'll have to use the template_name = view.html as defined above and override get_template_names like this:
def get_template_names(self):
# Sometimes the is_ajax() is not working properly so if it doesn't
# just pass the ajax_partial query parameter to your ajax request
if self.request.is_ajax() or self.request.GET.get('ajax_partial'):
return 'partial_table.html'
return super().get_template_names()
More info can be found in this recipe at my Django CBV guide: https://spapas.github.io/2018/03/19/comprehensive-django-cbv-guide/#implement-a-partial-ajax-view

Including non-form in a Django SessionWizardView

Can a non-form web page be included in a django SessionWizardView?
For example, I want the user to FillOut Form1, Form2, Then View a web page (in same session) (click next), and then Form3? All this while maintaining the same session.
If so, how is this best accomplished? Any examples or snippets?
There's a fairly easy hack for this. Create a plain old form that has one field that is hidden from the user, has no content, and isn't required.
I do this:
class BlankForm(forms.Form):
nothing = forms.CharField(required=False, widget=HiddenInput)
Include it in your SessionWizardView call just like the other pages:
SessionWizardView.as_view([Form1, Form2, BlankForm, Form3])
In the template page you can use some logic like this to display info:
{% if wizard.steps.current == '2' %}
Whatever you want to show on the BlankForm
{% endif %}

Django: custom content in admin form

For one of my models, I want to show extra content in the change_form. Basically, my model looks like this:
class News(models.Model):
...
class NewsFromSource(models.Model):
news = models.ForeignKey(News)
...
I want to add a 'search' button that, when clicked, triggers a web service request to an external news source, pulls down the available content, and lists all the news pieces contained. The user can then select one of the pieces to "attach" to the News currently edited in the admin interface (i.e. create a new NewsFromSource based on the content downloaded through the web service).
I am done with the web service. What is the best approach to implementing the search-button, list display for the results (I have a view and template that work, need to get those into the form somehow) and the saving part?
What I ended up doing is the following:
1)
I created a view for fetching search results, which boils down to this:
#/myproject/admin/views.py
#never_cache
def news_search(request):
#...query web service
if 'q' in request.POST:
search_term = request.POST['q']
else:
search_term = ''
news = NewsSearch()
news.search(search_term)
return render_to_response( 'news_search_results.html',
{ 'q': search_term,
'news': news.result_list,
'page': page,
'page_left': news.page_left,
'page_right': news.page_right}
)
2) I mapped the view:
#/myapp/urls.py
...
url(r'^myapp/news/search/$', views.news_search),
3) I extended change_form.html for the news model with the following code:
#/myproject/templates/admin/myapp/news/change_form.html
{% extends "admin/change_form.html" %}
{% block after_field_sets %}
...
{% csrf_token %}
<input type="text" name="q" id="news-search-term">
<div id="news-search-results"></div>
...
function submitSearchForm() {
$.post("/myapp/news/search/",
{ 'q': $('#news-search-term').val(),
'csrfmiddlewaretoken': $('input[name=csrfmiddlewaretoken]').val() },
function(data){
$('#news-search-results').html(data);
}
);
}
{{ block.super }}
{% endblock %}
4) I created an html template for displaying the results (news_search_results.html, see 1)
So basically I am sending an AJAX request from the admin page to a custom view to retrieve results from the webservice which then are displayed in a div.
Each element in the results list has a button that sends another request that stores the element with the news id as a ForeignKey.
I have no idea whether this is particularly against Django principles. But it seems to work alright.
Suggestions on doing this in a more "Djangonian" way are welcome.
We'll assume you have a related News model. Add that field to raw_id_fields of the modeladmin we're going to hack, then:
Overload the change_form template for this model, extend admin/change_form.html in admin/yourapp/yourmodel/change_form.html
Add javascript in that template to:
Hide the input and magnifier icon from the news raw id field form raw, you can do that in css too
Add something like a span with a button style in that form row that will open a popup when it is clicked
The popup it should open should be your working view/template with a form to select the news
When the user selects a news, the popup should do an ajax post request to get the news id, and close itself
the value is set to the raw id field input that is hidden, this is pretty tough but fear not someone (disclamer: I) published an article with the whole technical details, also found another one but I didn't test it
It's going to be quite some work. Patience and perseverance will be your best qualities for this mission B)