How to reuse a Django template? - django

Currently, I have almost two exact same templates and they use the same Django form, but there is only 1 parameter that changes in these two forms which is the action method, that is,
Django form
class DropDownMenu(forms.Form):
week = forms.ChoiceField(choices=[(x,x) for x in range(1,53)]
year = forms.ChoiceField(choices=[(x,x) for x in range(2015,2030)]
template 1
<form id="search_dates" method="POST" action="/tickets_per_day/">
<div class="row">
<div style="display:inline-block">
<h6>Select year</h6>
<select name="select_year">
<option value={{form.year}}></option>
</select>
</div>
<button type="submit">Search</button>
</div>
</form>
template 2
<form id="search_dates" method="POST" action="/quantitative_analysis/">
<div class="row">
<div style="display:inline-block">
<h6>Select year</h6>
<select name="select_year">
<option value={{form.year}}></option>
</select>
</div>
<button type="submit">Search</button>
</div>
</form>
The only thing that varies is the action method, so I would like to know if it is possible to re-use one template that varies only in the action method. If it is possible, can you help me with the code?
I checked this question django - how to reuse a template for nearly identical models? but I am not using any model here with my templates.

Of course there is a way. {% include %} to the rescue!
Create a base template for your form, like this:
<!-- form_template.html -->
<form id="search_dates" method="POST" action="{{ action }}">
<div class="row">
<div style="display:inline-block">
<h6>Select year</h6>
<select name="select_year">
<option value={{form.year}}></option>
</select>
</div>
<button type="submit">Search</button>
</div>
</form>
Notice the placeholder action. We'll need it in the next step.
Now, you can reuse this template, by simply writing:
<!-- a_template.html -->
{% include 'form_template.html' with action='/tickets_per_day/' %}
<!-- b_template.html -->
{% include 'form_template.html' with action='/quantitative_analysis/' %}

Well from your views you can pass action in the context and use that in template in this way you don't have to create two separate templates. Lets say the template name is abc.html used by two views:
def my_view_a(request):
ctx = {'action': '/tickets_per_day/'}
return render(request, 'abc.html', ctx)
def my_view_b(request):
ctx = {'action': '/quantitative_analysis/'}
return render(request, 'abc.html', ctx)
Then in template you would simply do:
<form id="search_dates" method="POST" action="{{ action }}">
In the above code the action is hardcoded better to use reverse to resolve url path by name:
ctx = {'action': reverse('namespace:url_name')} # replace namespace and url_name with actual values

Use this in template2:
{% include "template1.html" with form=form %}
It will work.

Related

How can two HTML template elements be updated using (HTMX)?

I have a form in which there are three fields, basically these fields contain drop-down lists - selections. These select lists are based on a data model that has fields associated with ForeynKey .
After completing this form.
I update information, code and do calculations in code.
Further after the calculations.
I am updating two elements on the template - a table and a graph.
I have these two elements in separate parts of the template.
Like two different pieces of HTML .
With (HTMX) I can only update one element on the table - this element is a chunk of the HTML template - which is updated by rendering that chunk of that template. How can I update another piece of the template?
How can two HTML template elements be updated using (HTMX) ?
I would be very grateful for any help.
--
<div class="row">
<div class="col-6">
<form method="POST" class="post-form">
{% csrf_token %} {{form_1.as_p}}
<button type="submit" class="save btn btn-light">Form</button>
</form>
</div>
</div>
<div class="row">
<div class="col">
{{ div_1|safe }}
{{ script_1|safe }}
</div>
</div>
<div class="row">
<div class="col">
{{ div_2|safe }}
{{ script_2|safe }}
</div>
</div>
--
class Form_1(forms.ModelForm):
class Meta:
model = Model_1
fields = "__all__"
--
class Model_1(models.Model):
name_1 = models.CharField(max_length=150, verbose_name="Name_1")
name_2 = models.CharField(max_length=150, verbose_name="Name_2")
def __str__(self):
return self.name_1, self.name_2
--
def form_1(request):
context = {}
form = Form_1(request.POST or None)
if form.is_valid():
form.save()
script_1, div_1 = components(data_table)
context['script_1'] = script_1
context['div_1'] = div_1
script_2, div_2 = components(fig)
context['script_2'] = script_2
context['div_2'] = div_2
return render(request, "data_table", "fig", context)
context['form_1'] = form
return render(request, "form_1.html", context)
added
def index_htmx(request):
context = {}
///code///
if request.htmx:
print("HTMX")
return render(request, 'index_htmx_added.html', context)
return render(request, "index_htmx.html", context)
index_htmx_added.html
<div id="table"
hx-swap="beforeend"
hx-swap-oob="true"
class="col-6">
{{ div|safe }}
{{ script|safe }}
</div>
<div id="figure"
hx-swap="beforeend"
hx-swap-oob="true"
class="col-6">
{{ div_2|safe }}
{{ script_2|safe }}
</div>
index_htmx.html
<div class="row">
<div class="col-4">
<select
id="select-name"
class="custom-select"
name="select"
autocomplete="off"
hx-get="{% url 'index_htmx' %}"
hx-target="#figure, #table"">
{% for select in selector %}
<option value="{{ select }}">{{ select }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="row">
<div id="table" class="col-6">
{{ div|safe }}
{{ script|safe }}
</div>
<div id="figure" class="col-6">
{{ div_2|safe }}
{{ script_2|safe }}
</div>
</div>
HTMX call this feature Out of Band Swap. In the response HTML you can have multiple HTML fragments with different targets and HTMX will swap the corresponding element on the page. Given your page looks like this:
<div id="tabular_data">...Tabular data...<div>
<div id="graph">...Graph...</div>
The response HTML should contain this (note the added hx-swap-oob="true"):
<div id="tabular_data" hx-swap-oob="true">...New tabular data...<div>
<div id="graph" hx-swap-oob="true">...New graph...</div>
HTMX will find id="tabular_data" element and swaps its content with the new content then do the same with id="graph" element.
These oob elements must be in the top level of the response, and not a children of an element.
At the backend you need to create a new template that contains all the element you want to swap together or just join the rendered HTML fragments when you return the response.

Django - Can't display category and sub category in template html

How can display category and sub category in product template?
what is missing in below code
This is a part of View.py according product view, shows filtering category and subcategory from model.py.
class ProductView(View):
def get(self,request,*args,**kwargs):
categories=Categories.objects.filter(is_active=1)
categories_list=[]
for category in categories:
sub_category=SubCategories.objects.filter(is_active=1,category_id=category.id)
categories_list.append({"category":category,"sub_category":sub_category})
merchant_users=MerchantUser.objects.filter(auth_user_id__is_active=True)
return render(request,"admin_templates/product_create.html",{"categories":categories_list,"merchant_users":merchant_users})
this is part of model.py according model after migrate,
class Products(models.Model):
id=models.AutoField(primary_key=True)
url_slug=models.CharField(max_length=255)
subcategories_id=models.ForeignKey(SubCategories,on_delete=models.CASCADE)
product_name=models.CharField(max_length=255)
brand=models.CharField(max_length=255, default="")
product_max_price=models.CharField(max_length=255)
product_discount_price=models.CharField(max_length=255)
product_description=models.TextField()
productTemplate.html
<div class="col-lg-6">
<label>Category</label>
<select name="sub_category" class="form-control">
{% for category in categories %}
<optgroup label={{ category.category.title }}>
{% for sub_cat in category.sub_category %}
<option value="{{ sub_cat.id }}">{{ sub_cat.title }}</option>
{% endfor %}
</optgroup>
{% endfor %}
</select>
</div>
I implemented this solution and I will teach you step by step how to implement it. Rather, a spoiler of what we will learn:
With that in mind, let's get our hands dirty:
The first thing we will need to do is return the published categories to our template . In the file views.pyin the method of receita, where we return the receita.htmlchosen recipe to the template , which is also the page that displays the categories select, we will create a filter to return the published categories to us. And we can do this with the following code:
categorias = Receita.objects.filter(publicada=True).values('categoria').distinct('categoria')
See, through the Recipes object we filter all the recipes that have the true flag for published. After that, we just get the category values. So we say to django: - django, returns me only the recipes that have true for published, but I just want the category column . And the distinct? To serve? The distinct will guarantee us that there will be no repetition in the data. Example:
If the filter returns to us that the category column has: dessert, salty, dessert, soup, salty ... what the distinct will do is to avoid repeated data, with that we will only have: dessert, salty, soup. How are you?
In possession of that, we need to pass this value to our dictionary that will go to the context of our template:
receita_a_exibir = {
'receita': receita,
'categorias': categorias
}
Note that we pass to the 'categories' key the value of our filter that was saved in the categories variable.
Now we can move the dictionary into context:
return render(request, 'receita.html', receita_a_exibir)
Great, now we can access the categories in our template receita.html'
And to display them we can go through each category and put the name of that category in our select. Also remembering that we need to redirect the url to our search route when we click on the search button:
<div class="receipe-post-search mb-80">
<div class="container">
<form action="{% url 'buscar' %}">
<div class="row">
<div class="col-12 col-lg-5">
<select type="text" name="buscar">
{% for categoria in categorias %}
<option value="{{categoria.categoria}}">{{categoria.categoria}}</option>
{% endfor %}
</select>
</div>
<div class="col-12 col-lg-2 text-right">
<button type="submit" class="btn delicious-btn">Buscar</button>
</div>
</div>
</form>
</div>
Now, with our template ready, you will be able to see the categories in the select.
The next step is to modify our search method so that it can search by category and not just the name of the recipe as it used to.
In views.py, in the method of buscar, let's say to django: search for the name of the recipe or all the recipes in that category. We can do this through the object Q used to set up queries where we will have more than one possible answer :
lista_receitas = lista_receitas.filter(Q(nome_receita__icontains=nome_a_buscar) | Q(categoria__icontains=nome_a_buscar))
That is, filter the recipes that have that name or that have that category. And in order to Qwork, we will need to import it:
from django.db.models import Q
You can test it! With these modifications you will be able to use the select categories.
Summary of modified files:
views.py file
from django.db.models import Q
.
def buscar(request):
lista_receitas = Receita.objects.filter(publicada=True).order_by('-data_receita')
if 'buscar' in request.GET:
nome_a_buscar = request.GET['buscar']
if buscar:
lista_receitas = lista_receitas.filter(Q(nome_receita__icontains=nome_a_buscar) | Q(categoria__icontains=nome_a_buscar))
dados = {
'receitas' : lista_receitas,
}
return render(request, 'buscar.html', dados)
.
def receita(request, receita_id):
receita = get_object_or_404(Receita, pk=receita_id)
categorias = Receita.objects.filter(publicada=True).values('categoria').distinct('categoria')
receita_a_exibir = {
'receita': receita,
'categorias': categorias
}
return render(request, 'receita.html', receita_a_exibir)
.
Recipe.html file
.
<div class="receipe-post-search mb-80">
<div class="container">
<form action="{% url 'buscar' %}">
<div class="row">
<div class="col-12 col-lg-5">
<select type="text" name="buscar">
{% for categoria in categorias %}
<option value="{{categoria.categoria}}">{{categoria.categoria}}</option>
{% endfor %}
</select>
</div>
<div class="col-12 col-lg-2 text-right">
<button type="submit" class="btn delicious-btn">Buscar</button>
</div>
</div>
</form>
</div>
Some django documentation references:
Distinc
Object Q
I hope I helped you

Django checkbox for filter

Im having some problem when I want to keep a checkbox checked. When I send the form all the checkbox are checked. so idk how to change the if statement for that :(
<div class="form-group">
<label >Marca</label>
{% for brand in q %}
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" id="{{brand.brand}}" name="test" value="{{brand.brand}}" {% if marca %} checked="checked" {%endif%}>
<label class="custom-control-label" for="{{brand.brand}}" style="cursor: pointer;">{{brand.brand}}</label>
</div>
{% endfor %}
</div>
And here is the view:
marca = request.GET.get('test')
if marca :
products = products.filter(brand__name__in=request.GET.getlist('test'))
All the other things are fine. It shows me the brands that I choose. So I just want to keep the checkbox that I checked :( and I think the problem is that If statement in the template
Just pass a set of the values in the values to the template:
marca_vals = set(request.GET.getlist('test'))
# …
context = {
'marca_vals': marca_vals,
# …
}
return render(request, 'some_template.html', context)
in the template you can then render it with checked in case the value is in the marca_vals:
<input type="checkbox" {% if brand.brand in marca_vals %}checked{% endif %} class="custom-control-input" id="{{brand.brand}}" name="test" value="{{brand.brand}}">
You might however want to consider using a form, or even django-filters [readthedocs] to both make filtering and rendering the form more convenient.

Using modelForm hidden field with Formsets without using Crispyform.

I am working with forms sets, I was wondering how one could use
<input type='hidden'
inside a form set. (Django formsets allow us to use multiple forms instances of a single form)
Its easy to do in normal single form where you just put the field with the type='hidden' and name='fieldname' e.g.
<input type='hidden' name='user' value='{{request.user.id}}'>
Dealing with formsets is a bit catchy, how to achieve the same behavior with the forms sets?
Views.py
PictureFormSet = modelformset_factory(Picture, form=UpdatePictureForm, extra=0)
formset_qset = Picture.objects.filter(id__in=[15, 16, 17, 18, 19, 20])
if request.method == POST:
ctx['form_set'] = PictureFormSet(request.POST, queryset=formset_qset)
ctx['form_set'].save()
ctx['form_set'] = PictureFormSet(queryset=formset_qset)
return render_to_response('temp tabs.html', context_instance=RequestContext(request, ctx))
Template
<form method="POST" action="" class="form-horizontal">
{% for form in form_set %}
{{form.id}}
<div class="form-group">
<label class="col-lg-2 control-label">
{% with form.meta_data.value|load_meta_data as meta %}
<div class="portfolio-item video-container">
<a class="" href="{% url 'view_image' form.id.value %}?in=pro">
<i style="background-image: url({{ meta.image_size.thumbnail_small }});"
class="ds-thumbnail-container"></i>
</a>
</div>
{% endwith %}
</label>
<div class="col-lg-8 ">
{{ form.name }}
</div>
</div>
{% endfor %}
{{ form_set.management_form }}
{% csrf_token %}
<input type="submit" value="Submit">
</form>
Explanation
Here in this code, We are rendering images from the database for editing there names. we have url information inside the meta_data, so we have selected
fields=['id', 'meta_data', 'name']
We want to change/Update the name, but not the meta_data
This code works fine for the most part, but how i want to keep one field unchanged for the modal?
I have meta_data field that I am using in the template, but i do not want that field to be modified, that value should be in the form like this
{{form.meta_data}}
This turns it into text area, with different name and id. and it expects it be changing. but i want to declare a hidden field and sets its value to the form.meta_data.value
If you have any questions regarding this please do not hesitate to ask.
Thanks.

Django identifying non field validation error is associated with which form

Is there a way to identifying the validation error is associated with which form for a template contaning multiple forms?
Let me explain the scenario. I have login window popup script within my base.html
<div id="dialog1" class="window">
<form method="post" action="/accounts/login/?next=/IW/home" id='login-form' name=login-form>{% csrf_token %}
<div class="d-header">
{{ form.non_field_errors }}
<input type="text" name="username" id="id_username" value="" onclick="this.value=''"/><br/>
<input type="password" name="password" id="id_password" value="" onclick="this.value=''"/><br/>
<input type="hidden" name="login_form" value="1" />
<input type="submit" value="login" />
</div>
{% endif %}
</div>
</form>
</div>
<div id="mask"></div>
{% if form.non_field_errors %}
<script>
var maskHeight = $(document).height();
var maskWidth = $(window).width();
//Set heigth and width to mask to fill up the whole screen
$('#mask').css({'width':maskWidth,'height':maskHeight});
$('#mask').show();$('.window').show();
</script>
{% endif %}
As all other templates extends base,html whenever there is an error non_field error then login window pops up . I would like to show the login error only when login form is submit not on submit of someother form with a non field error.
For this I need to identify the name of the form.something like this {% ifequal form.form_name login_form %} - Display login error .Is this possible??
They isn't anything special about the name 'form' in the template. It's just a default context name, you can choose to name your forms anything you like.
Just name the forms differently in your context:
from django.http import Http404
def detail(request, poll_id):
# NOTE: This view code isn't really form processing code, just using it to show
# how you can pass different names into your template context.
login_form = MyLoginForm()
detail_form = MyDetailForm()
try:
p = Poll.objects.get(pk=poll_id)
except Poll.DoesNotExist:
raise Http404
return render_to_response('polls/detail.html', {'poll': p, 'login_form': login_form, 'detail_form': detail_form})
And then:
<div id="dialog1" class="window">
<form method="post" action="/accounts/login/?next=/IW/home" id='login-form' name=login-form>
{% csrf_token %}
<div class="d-header">
{{ login_form.non_field_errors }}
.
.
.
Also, if you want to do multiple instances of the same form type, have a look at formsets