How to iteratively render the first X fields in a Django form - html

I'm rendering a form in a Django html template by using a for loop and iterating over the fields. I want to add some sections & headers inside my form, so is there a way to 'slice' the form fields or otherwise iteratively display only a subsection of fields?
Something like
{% for field in form.slice(0, 5) %}
<!-- render first 5 fields -->
<h2>Section 2</h2>
<p>Some text about next section</p>
{% for field in form.slice(5, 10) %}
<!-- render the next 5, etc. -->
I know the worst case answer is to render each field manually, but it's a VERY long form. Here's my existing form code.
{% for field in form %}
<div class="field">
<label class="label" for="{{field.id_for_label}}">
{{field.label}}
</label>
<div class="control">{{field}}</div>
{% if field.help_text %}
<p class="help">{{field.help_text}}</p>
{% endif %}
<ul class="errorlist">
{% for error in field.errors %}
<li class="is-danger help">{{error}}</li>
{% endfor %}
</ul>
</div>
{% endfor %}

You can make use of Django forloop.counter0 or forloop.counter variables. The first one which keeps track of the iteration inside the loop starting with index 0 and the second one indexes iterations starting with 1 (see the bottom of this section see the bottom of this section https://docs.djangoproject.com/en/4.0/ref/templates/builtins/#for for more):
{% for field in form %}
{% if forloop.counter0 == 5 %}
<h2>Section 2</h2>
<p>Some text about section 2</p>
{% elif forloop.counter0 == 8 %}
<h2>Section 3</h2>
<p>Some text about section 3</p>
{% endif %}
<div class="field">
<label class="label" for="{{field.id_for_label}}">
{{field.label}}
</label>
<div class="control">{{field}}</div>
{% if field.help_text %}
<p class="help">{{field.help_text}}</p>
{% endif %}
<ul class="errorlist">
{% for error in field.errors %}
<li class="is-danger help">{{error}}</li>
{% endfor %}
</ul>
</div>
{% endfor %}
You would still have to manually check for the values. If you want for example to add section content in a way you can iterate the content every 5 fields you can take advantage of divisibleby and Django-Mathfilters to divide:
{% for field in form %}
{% if forloop.counter0|divisibleby:5 %}
<h2>Section {{ forloop.counter0|div:5}}</h2>
<p>Some text about section {{ forloop.counter0|div:5}}</p>
{% endif %}
<div class="field">
<label class="label" for="{{field.id_for_label}}">
{{field.label}}
</label>
<div class="control">{{field}}</div>
{% if field.help_text %}
<p class="help">{{field.help_text}}</p>
{% endif %}
<ul class="errorlist">
{% for error in field.errors %}
<li class="is-danger help">{{error}}</li>
{% endfor %}
</ul>
</div>
{% endfor %}
For more references you can see Modulus % in Django template to know about divisibleby and Is there a filter for divide for Django Template? to get some other methods on how to divide numbers in your Django template!

Related

Shopify - How to call images and tittles from a specific collection into the product recommendation module

what I'm trying to do is bring products pictures and titles from specific collection into my product recommendation module.
This is the module im trying to call my products.
{% if section.settings.show_product_recommendations %}
<div class="product-recommendations"
data-section-type="product-recommendations"
data-components="product-block"
data-url="{{ routes.product_recommendations_url }}?section_id={{ section.id }}&product_id={{ product.id }}&limit=12">
{% if recommendations.performed and recommendations.products_count > 0 %}
<div class="product-recommendations-container product-slider">
<div class="wide-container section-spacing">
<div class="product-list swiper-container" data-products-in-view="{{ section.settings.grid }}">
<h2 class="h2 section-heading" data-cc-animate>
{{ section.settings.title }}
</h2>
<div class="swiper-wrapper" data-normheights=".image" data-normheights-inner="img">
{%- for product in recommendations.products -%}
<div class="swiper-slide">
{% render 'product-block', product: product, product_class: product_class, i: forloop.index, animate: forloop.index, show_vendor: section.settings.show_vendor, hide_swatches: section.settings.hide_swatches %}
</div>
{%- endfor -%}
</div>
<div class="swiper-scrollbar"></div>
{% render 'svg-chevron-left' %}
{% render 'svg-chevron-right' %}
</div>
</div>
</div>
{% endif %}
</div>
{% endif %}
So far i did tried something like this. But this code has to be integrated into to code above because what Im trying to do is call specific collection to my recommendations module.
/collections/224916897949 is ID of my collection list and it has multiple products. Instead of using the Shopify panel to add collection I would like to add by liquid.
{% assign collection = collections[section.settings.collection] %}
{% for product in collection.products.224916897949 limit: 12 %}

HTML search function using a wildcard - shopify

I am a super beginner with HTML, however, I am trying to resolve an issue with my website. I am trying to concatenate a wildcard(*) to the end of whatever a consumer tries to search so that it picks up similarly tagged items, however, I cannot figure out where to add said code... Our current search query works well when pulling up items based on partial keywords, but when hitting the 'enter' button it will say it could not find any products.
Additional notes: This is a Shopify website with a theme from halothemes so most of this is coded by them.
{% assign grid_results = true %}
<div class="search-page collection-template" data-search-page>
<div class="container">
{% if search.performed %}
{% comment %}
Avoid accessing search.results before the opening paginate tag.
If you do, the pagination of results will be broken.
{% endcomment %}
{% paginate search.results by 15 %}
{% comment %}
We don't have any results to show. Feel free to show off featured products
or suggested searches here.
{% endcomment %}
{% if search.results_count == 0 %}
<header class="page-header">
<h2>
{% render 'multilang' with settings.search_1 %}
<strong> "{{ search.terms }}" </strong>
{% render 'multilang' with settings.search_2 %}
</h2>
</header>
{% else %}
<header class="page-header">
<h2>
{% render 'multilang' with settings.search_3 %}
<strong> "{{ search.terms }}" </strong>
{% render 'multilang' with settings.search_4 %}
</h2>
</header>
{% comment %}
Each result template, based on the grid_layout variable above
{% endcomment %}
<div class="block-row col-main">
{% if grid_results == false %}
<div class="product-collection products-list product-search row">
{% for product in search.results %}
<div class="grid-item col-12{% if settings.product_image_border%} grid-item-border{% endif %}">
{% render 'search-result' with product as product %}
</div>
{% endfor %}
</div>
{% else %}
<div class="products-grid product-search row product-collection">
{% for product in search.results %}
<div class="grid-item col-6 col-md-4{% unless settings.layout_style == 'layout_style_1170' %} col5 col-lg-3{% endunless %}{% if settings.product_image_border%} grid-item-border{% endif %}">
{% if settings.style_product_grid == 'style_product_grid_2' %}
{% render 'product-grid-item-style-2' with product as product %}
{% else %}
{% render 'product-grid-item' with product as product %}
{% endif %}
</div>
{% endfor %}
</div>
{% endif %}
</div>
{% endif %}
{% if paginate.pages > 1 %}
<div class="padding">
{% render 'pagination-page' paginate: paginate %}
</div>
{% endif %}
{% endpaginate %}
{% else %}
{% comment %}
If search.performed is false, someone either accessed the page without
the q parameter, or it was blank.
Be sure to show a search form here, along with anything else you want to showcase.
{% endcomment %}
<header class="page-header">
<h2 style="text-align:center" {% if settings.enable_multilang %}data-translate="general.search.title"{%endif%}>{{ 'general.search.title' | t }}</h2>
<div class="header-search__form">
<form action="/search" method="get" class="search-bar" role="search">
<input type="hidden" name="type" value="product">
<input type="search" name="q"
{% if settings.enable_multilang %} data-translate="general.search.placeholder" translate-item="placeholder"{% endif %}
placeholder="{{ 'general.search.placeholder' | t }}"
class="input-group-field" aria-label="Search Site" autocomplete="off">
<button type="submit" class="btn icon-search">
{% render 'icon-search' %}
</button>
</form>
</div>
</header>
{% endif %}
Please let me know if you guys need any additional information! Thank you!
You can use a simple script to add a wildcard to the search query on submitting the form e.g:
var searchForm = document.querySelector(".search-bar");
searchForm.addEventListener("submit", function(e) {
var searchInput = searchForm.querySelector("[name=q]");
var q = searchInput.value;
if (!q.match(/\*$/)) {
e.preventDefault();
searchInput.value = q + "*";
searchForm.submit();
}
});

How to arrange content into grid view dynamically?

I want to arrange the following Figure1 content into horizon grid view, here content coming into vertical so, how to arrange into horizontal grid view, like Figure2
Figure1:
Figure2:
Here I only required the css class in div, Please tell the css class to arrange the grid into horizontal form.
Jinja2 Templates
_data_grid.html
This template, takes rows(number of data, like in the following Figure2 we have 5 data), and columns(Image Name, Type, Status, public, protected, Formate, size, Action), All these info comes from the database and django framework.
{% load i18n %}
{% with table.needs_form_wrapper as needs_form_wrapper %}
<div class="table_wrapper">
{% if needs_form_wrapper %}<form action="{{ table.get_full_url }}" method="POST">{% csrf_token %}{% endif %}
{% with columns=table.get_columns rows=table.get_rows %}
{% block grid %}
<grid id="{{table.slugify_name}}">
<div>
{% block grid_caption %}
<h3 class='table_title'>{{ table }}</h3>
{{ table.render_table_actions }}
{% endblock grid_caption %}
</div>
</br>
</br>
</br>
</br>
{% block grid_body %}
<div>
{% for row in rows %}
{{ row.render }}
{% empty %}
{{ table.get_empty_message }}
{% endfor %}
</div>
{% endblock grid_body %}
</grid>
{% endblock grid %}
{% endwith %}
{% if needs_form_wrapper %}</form>{% endif %}
</div>
{% endwith %}
_data_grid_cell.html
This template is used to fill the content,
{% if cell.inline_edit_mod and cell.update_allowed %}
{% else %}
{% if cell.inline_edit_available and cell.update_allowed %}
{% else %}
<ul>{{ cell.value }}</ul>
{% endif %}
{% endif %}
If you want to code the css your self flexbox will be what you are looking for. But I will be easier and probably cleaner to use css frameworks like Bootstrap, your code should look somthing like this, then you can add django template tags:
<div class="container">
<div class="row">
<div class="col-sm-4 col-md-4"><!--block 1--></div>
<div class="col-sm-4 col-md-4"><!--block 2--></div>
<div class="col-sm-4 col-md-4"><!--block 3--></div>
<div class="col-sm-4 col-md-4"><!--block 4--></div>
</div>
</div>
Check (Bootstrap Grid) for more details and explanation for the css classes.

Django template: Invalid block tag: 'endif', expected 'empty' or 'endfor'

I am getting an error saying my template is not correct.
The error goes like: Invalid block tag: 'endif', expected 'empty' or 'endfor'
My code is here, the bug is on the last line. Which part is not correct?
{% if entries %}
{% for entry in entries %}
<section class="no-padding" id="portfolio">
<div class="container-fluid">
(% if entry.scammer_name %}
<div class="row no-gutter result-wrapper control-group">
<div class="col-lg-3 result-label">
<label class="control-group result-padding">
suspect's name:
</label>
</div>
<div class="col-lg-9 result">
<label class="control-group result-padding light-font">
{{ entry.scammer_name }}
</label>
</div>
</div>
{% endif %}
</div>
</section>
{% endfor %}
{% endif %}
Add {% endfor %}{% endif %} to the last line of code.
For loops require endfor tags
{% if mike %}
{% if jake %}
{% for x in squid %}
{{ x.do_stuff }}
{% endfor %}
{% endif %}{# closes jake tag #}
{% endif %}{# closes mike tag #}

Twig loop grouping divs

I want to populate a twig page with information stored in the database. I use a loop to make multiple divs containing different entries of the same tables. The only problem is that I want to group the divs by4.. and I can't stop the loop when I reach the fourth step. In the end i get a big colon of divs.
Can anyone please tell me how to group the divs by 4?
This is my twig template:
<form method="POST" id="form-book">
<section id="portfolio" class="container main">
<ul class="gallery col-4">
{% for type in typeandrooms %}
{% for t, room in type %}
<li>
{% if t == 0 %}
<div class="preview">
{% set var_id = 'bundles/twnelo/images/portfolio/thumb/item' %}
{% set var_id = var_id ~ room.getType.id %}
{% set var_id = var_id ~ '.jpg' %}
<img src="{{ asset(var_id) }}">
<div class="overlay">
</div>
</div>
<div class="desc">
<h5> {{ room.getType.name }} </h5>
<strong>Beds: </strong>Double bed<br/>
<strong>Available rooms: </strong> {{ type|length }} <br/>
<strong>Prices: </strong> {{ room.getPrice }} <br/>
<button type = "submit" name="singleapartment" value = "{{ room.getType.id }}" class="btn btn-success btn-small">Book a room !</button>
</div>
{% endif %}
{% if loop.index % 4 == 0 and loop.index > 0 %}
</li>
Al 4-lea pas
<li>
{% endif %}
</li>
{% endfor %}
{% endfor %}
</ul>
</section>
</form>
{% endfor %}
Problem is solved. This is the new template:
<form method="POST" id="form-book">
<section id="portfolio" class="container main">
<ul class="gallery col-4">
{% for rooms in typesandrooms %}
{% for room in rooms %}
{% if loop.index == 1 %}
<li>
<div class="preview">
{% set var_id = 'bundles/twnelo/images/portfolio/thumb/item' %}
{% set var_id = var_id ~ room.getType.id %}
{% set var_id = var_id ~ '.jpg' %}
<img src="{{ asset(var_id) }}">
<div class="overlay">
</div>
</div>
<div class="desc">
<h5> {{ room.getType.name }} </h5>
<strong>Facilities: </strong>{% for facility in room.getFacilities %} {% if loop.index < 4 %} {{ facility.getFacility }}; {% endif %} {% endfor %}<br/>
<strong>Available rooms: </strong> {{ rooms|length }} <br/>
<strong>Prices: </strong> {{ room.getPrice }} Lei <br/>
<button type = "submit" name="singleapartment" value = "{{ room.getType.id }}" class="btn btn-success btn-small">Book a room !</button>
</div>
</li>
{% endif %}
{% endfor %}
{% endfor %}
</ul>
</section>
</form>
You have to open the first row right before the loop.
{% for type in typeandrooms %}
+ <li>
{% for t, room in type %}
- <li>
And close the last one right after
{% endif %}
- </li>
{% endfor %}
+ </li>
{% endfor %}
And given this line {% if t==0 %} I reckon you'll need to use a counter instead of index.loop. Else you could end up with less than 4 room per list row. The best practice would be to parse the array first in your controller and remove the rooms with t==0 then just remove the {% if t==0 %} line in your twig template and it'll work with index.loop, you want to keep the logic in twig to a minimum.