How to use expressions in if statements in DBT - sql

I want to know how, if possible, I can use dbt expressions that are enclosed in two curly brackets ({{ }}), inside a statement that is enclosed in a curly bracket and a percent sign ({% %}).
For example, I want to execute a piece of code in DBT if the table exists. In my head, it would look something like:
{% if {{this}} is not none %}
do something
{% endif %}
But there's a syntax issue here and I can't seem to be able to use expressions inside statement blocks. I have seen the following implementation but I want to know how I can replace source with {{this}}.
{% set table_exists=source('db', 'table') is not none %}
{% if table_exists %}
do something
{% endif %}
These are the docs I have read:
'this' jinja function
jinja and macros
dbt if table exists example
using load_relation to check if model exists

Don't Nest Your Curlies
If you're inside either {{ ... }} or {% ... %}, your code will be executed by the jinja templating engine. this is a variable that is already set in the jinja context. You use {{ this }} in SQL, but if you're already in the jinja context provided by {% ... %}, you can just write this, without the curlies.
Your if block becomes:
{% if this is not none %}
do something
{% endif %}

Related

How to check if condition in django template part

I want add simple css class in the template first round of loop when for loop runs. {{forloop.counter}} shows count of for loops each time. so I want to do something like this {% if forloop.counter==1 %} show {% endif %}. but it shows error as below:
Could not parse the remainder: '==1' from 'forloop.counter==1'
How to do it? any solution?
You're forgetting about the spaces around the equal signs:
{% if forloop.counter == 1 %}

Is it possible to use a liquid "where" array filter with nested properties?

I'm trying to filter an array of blocks using block settings. I can filter by properties like "type" using the following syntax:
{% assign example = section.blocks | where: "type", "photos" %}
What I need to do is filter by block settings, something like this:
{% assign example = section.blocks | where: settings.collection, collection.handle %}
The above example is failing silently.
A note: Currently I am accomplishing what I need using a capture with a for loop and an if statement, and then assigning with a split — but the code is so bloated, and doing all that for a simple filter operation seems ridiculous. I find myself constantly feeling like I'm fighting with liquid, and I guess I'm hoping it might be just a bit more elegant than I'm giving it credit for.
I don't know much about Ruby, but it seems you can't pass nested properties with dot notation to the where filter. However, after seeing people accessing nested values using map, I tested mixing the two, and the map filter seems to work well for this case.
I have a boolean setting called default in my blocks, and I got the settings object for the last block with default set to true using this:
{% assign obj = section.blocks | map: 'settings' | where: 'default' | last %}
Of course, then you can't get data outside of the settings object that was extracted. For that I think you really would need to loop through the section.blocks and find filter manually using the if tag.
You are doing it wrong. where will work only at the root element. In your case section.blocks is the root element so where can be used for something like section.blocks.abcd_property.
Rough example: {% assign example = section.blocks | where: 'collection', collection.handle %} will load all section blocks having their collection property as collection.handle value
This will work
{% if settings.collection == collection.handle %}
{% assign example = section.blocks %}
{% else %}
{% assign example = '' | split: '' %}
{% endif %}
Previously used map which loses outer data but found string notation works with where for nested properties:
E.g., Using a posts collection where each .md file has the front-matter:
header:
isArchived: true
The following liquid snippet filters archived posts via header.isArchived:
{% assign archived = site.posts | where: "header.isArchived", true %}

Jinja / Django for loop range not working

I'm building a django template to duplicate images based on an argument passed from the view; the template then uses Jinja2 in a for loop to duplicate the image.
BUT, I can only get this to work by passing a list I make in the view. If I try to use the jinja range, I get an error ("Could not parse the remainder: ...").
Reading this link, I swear I'm using the right syntax.
template
{% for i in range(variable) %}
<img src=...>
{% endfor %}
I checked the variable I was passing in; it's type int. Heck, I even tried to get rid of the variable (for testing) and tried using a hard-coded number:
{% for i in range(5) %}
<img src=...>
{% endfor %}
I get the following error:
Could not parse the remainder: '(5)' from 'range(5)'
If I pass to the template a list in the arguments dictionary (and use the list in place of the range statement), it works; the image is repeated however many times I want.
What am I missing? The docs on Jinja (for loop and range) and the previous link all tell me that this should work with range and a variable.
Soooo.... based on Franndy's comment that this isn't automatically supported by Django, and following their link, which leads to this link, I found how to write your own filter.
Inside views.py:
from django.template.defaulttags import register
#register.filter
def get_range(value):
return range(value)
Then, inside template:
{% for i in variable|get_range %}
<img src=...>
{% endfor %}

Variable within liquid if statement when calling shopify settings

I thought this would be simple to solve but I am trying to put a variable within a liquid statement.
I have my variable {{ loop_index }} and I want it to be within this statement :
{% if settings.dropdown-[loop_index]-select %}
I tried putting [...] round it but that didn't work. Basically it should say settings.dropdown-1-select, settings.dropdown-2-select.
What am I doing wrong?
Create a string containing the variable name, then use the square bracket notation to access the setting with that name. For example:
{% capture var %}dropdown-{{ loop_index }}-select{% endcapture %}
{% if settings[var] %}

Shopify liquid: How can I conditionally include snippets in Shopify liquid?

I would like to include a snippet in a template but only if the snippet file exist. Is there any way I can do it?
Now I'm just using:
{% include 'snippetName' %}
But this throws the error:
Liquid error: Could not find asset snippets/snippetName.liquid
The reason I need such a functionality is because I have a background process that adds the snippet later on.
Had this problem myself. This was my solution:
{% capture the_snippet_content %}{% include the_snippet %}{% endcapture %}
{% unless the_snippet_content contains "Liquid error" %}
{% include reviews_snippet %}
{% endunless %}
Basically capture the snippet’s content as a variable.
If there is no snippet Shopify generates the error:
Liquid error: Could not find asset
snippets/caroline-flint-reviews.liquid
So check to see if it’s generated that… if so don’t print the snippet
:D
Of course this would break if you intended your snippet to include "Liquid error" or if Shopify ever change the error message.
Extending on Jon's answer;
Create a file called snippet.liquid
{% capture snippet_content %}{% include snippet %}{% endcapture %}
{% unless snippet_content contains "Liquid error" %}
{{ snippet_content }}
{% endunless %}
Then when you want to include a file only if it exists
{% include 'snippet' with 'filename_of_include' %}
Okay, Coming here in 2021.
The include syntax is deprecated and infrequently used, also extending #a.wmly answer, this should be the latest syntax replacing include with render:
{% capture snippet_content %}{% render 'your-snippet-name' %}{% endcapture %}
{% if snippet_content contains "Could not find asset" %}
{% comment %} do nothing {% endcomment %}
{% else %}
{% render 'your-snippet-name' %}
{% endif %}
references for include vs render : https://shopify.dev/docs/themes/liquid/reference/tags/deprecated-tags#include
Alternatively, you could create your own tag which does a check on the existence of the file, before attempting to process it.
https://github.com/Shopify/liquid/wiki/Liquid-for-Programmers#create-your-own-tags
#vovafeldman Not sure why you can't have a blank snippet, but there's no file exists.
The only other option I can think of is since you are using a BG process to generate the snippet (and I assume upload it), you can always use the template API to upload the version of the template that includes the snippet at the same time.
Using the code listed above by Jon or a.wmly both still gave me errors. However, simply writing
{% include 'snippet_name' %}
worked just fine.
Note that this only worked for files located in the "snippets/" folder. So Templates, for instance, did not work using this method.