Having trouble getting setcontent to work as expected with Taxonomies.
I'm in a record template and want to pull in other items that share any of the same taxonomy values. So I don't want to hardcode the values in, but instead compare to my current record.
For example, here's a hardcoded query, checking for items that have 'Apps' in their topics taxonomy.
{% setcontent relinterviews = 'interviews' where { topics: 'Apps' } %}
Instead I need something like this pseudo code, but that works:
{% setcontent relinterviews = 'interviews' where { topics in record.taxonomy.topics } %}
Ideally, I want to be pulling in items that match two different taxonomies - Topics and Roles - but I'd settle for one.
Try these:
To search for two of the same taxonomy.
{% setcontent relinterviews = 'interviews' where { topics: 'Apps || Other' } %}
To search across two separate taxonomies.
{% setcontent relinterviews = 'interviews' where { topics: 'Apps', roles: 'MyRole' } %}
Related
I try to do a search engine if the word in my DB thah I created then display the word on the HTML page and if not then nothing.. I did it right in VIEW but I can not apply it on the HTML page I searched the internet and did not find an answer I'm sure I fall for something stupid.
This is the view
def Search_word(request):
search = request.POST.get("search") #Grab the search item
return render(request,"search_page.html", {"search":search})
this is the html:
{%for i in Word.English_word%}
{%if search in Word.English_word%}
{{search}}
{%endif%}
{%endfor%}
and the urls:
path("Search_page",views.Search_word ,name="Search-page"),
models:
class Words(models.Model):
English_word = models.CharField(max_length=30)
Hebrew_word = models.CharField(max_length=30)
How_To_Remember = models.CharField(max_length=40)
Name = models.CharField(max_length=20)
pub_date = models.DateTimeField()
The problem is that even if the word is valid it does not show me anything ..
You should implement the filtering logic in the view, not in the template. Templates are for rendering logic, not business logic. Furthermore one should filter with the database, since databases are designed to do this.
The view thus looks like:
def Search_word(request):
search = request.POST.get('search')
items = Word.objects.filter(English_word__contains=search)
return render(
request,
'search_page.html',
{'search': search, 'items': items}
)
and then in the template we render this with:
{% for item in items %}
{{ item.English_word }}: {{ item.Hebrew_word }} <br>
{% endfor %}
You can use as lookup __contains to check if the English_word has a substring that is equal to search, with __icontains you check case-insensitive, with __iexact you look for Words that match search case-insensitive, and finally you can filter with Engish_word=search for an exact match.
I am building a website with DJANGO where people put words and association how to remember the word.
I built the part of inserting the word.
I am now stuck in the part of implementing the word search and extracting the information from the DB.
def Search_word(request):
if request.method == "POST":
search = request.POST["search"]
word = Words.objects.filter(English_word__contains = search)
return render(request,"search_page.html",{word:word , search:search})
else:
return render(request,"search_page.html",{})
{% if search %}
<h1> You searched for {{search}}</h1>
{% for Words in search %}
{{Words.English_word}}
{{ Words.Hebrew_word }}
{{ Words.How_To_Remember}}
{% endfor %}
{% else %}
<h1> Hey! You Forgot To Search </h1>
{% endif %}
if you want to search only in one field, Django supports search which is much better and more accurate than contains
words = Words.objects.filter(English_word__search = search_term)
but if you like to have some sort of search engine-like functionality you can use PostgreSQL with Django's full text search feature
in model.py add these commands
from django.contrib.postgres.search import SearchVector
in your model manger:
def full_search(self, search_term):
return self.annotate(
search=SearchVector('English_word') +
SearchVector('blog__tagline')).filter(search=seach_term)
this method will remove <in/at/is/the/...> other English words and only search with word-to-vector algorithms
if you have to work with ranking the search results:
from django.contrib.postgres.search import SearchQuery, SearchRank,SearchVector
vector = SearchVector('english_word')
query = SearchQuery(search_term)
Word.objects.annotate(rank=SearchRank(vector, query)).order_by('-rank')
this will annotate the results based on their likelihood to search term.
by the way It's best practice to use Model Mangers and avoid doing ORM stuff in views.
Django Docs on search:
https://docs.djangoproject.com/en/3.2/ref/contrib/postgres/search/
Hello i have implemented a simple search form and search view to show search result. Now i want to paginate them. But there is a problem with the page in the url. My search url looks like ../search?q=Bla
Now if i try to add pagination like: ../search?q=Bla?page=2 (at least thats how i understand it would work) it takes the whole string after q= to my database filter. I took a look at how stackoverflow handles searching and pagination and found out using '&' here is the view code:
def search(request):
# get query search parameters
page = request.GET.get('page', 1)
query = request.GET.get('q', '')
# query none or empty
if query is None or query == '':
return redirect('home')
# query valid
else:
# icontains make sure to ignore character sensitivity
post_list = Post.objects.filter(title__icontains=query)
paginator = Paginator(post_list, 5)
try:
posts_l = paginator.page(page)
except PageNotAnInteger:
posts_l = paginator.page(1)
except EmptyPage:
posts_l = paginator.page(paginator.num_pages)
return render(request, 'search.html', {'post_list': posts_l, 'query': query})
and here the HTML Snippet:
{% if post_list.paginator.num_pages > 1 %}
<div class="pagination">
<span class="step-links mb-5 mx-auto">
{% if post_list.has_previous %}
<a class="mr-3" href="?page={{ post_list.previous_page_number }}&q={{ query }}">zurück</a>
{% endif %}
<span>Seite {{ post_list.number }} von {{ post_list.paginator.num_pages }}</span>
{% if post_list.has_next %}
<a class="ml-3" href="?page={{ post_list.next_page_number }}&q={{ query }}">nächste</a>
{% endif %}
</span>
</div>
{% endif %}
So now the url is build like search?q=Test for the first page. And for the other pages (which suprisingly works) is search?page=2&q=Test. Now im happy it works but i dont quite how just adding &q={{ query }} solved my problem. Is this some kind of universal RFC? I dont quite understand since i was just checking out how this side does it. implemented it and works?
A query string [wiki] is the part after the question mark (?) of a URL. It is a string that consists out of a sequence of key-value pairs separated by an ampersand (&). The key and the value are separated by the equals sign (=). Both the key and the value are percent-encoded [wiki]. So as you found out:
page=2&q=Test
is a querystring that contains two key-value pairs: page maps to 2 and q to test.
The code is however not entirely "safe". If the query itself contains an ampersand &, etc. then this can result in an incorrect query. You should make use of the |urlencode template filter [Django-doc] to percentage encode the value:
<a class="ml-3" href="?page={{ post_list.next_page_number }}&q={{ query|urlencode }}">nächste</a>
I have container.twig including component.twig and passing an object called 'mock'.
In container.twig:
{% set mock = {
title : "This is my title"
}
%}
{% include 'component.twig' with mock %}
This is working fine but I want to move the mock data to its own file. This isnt working:
Container.twig
{% include 'component.twig' with 'mock.twig' %}
In mock.twig
{% set mock = {
title : "This is my title"
}
%}
Im using gulp-twig but it works like standard twig in most respects. https://github.com/zimmen/gulp-twig
The problem
Twig context is never stored in the template object, so this will be very difficult to find a clean way to achieve this. For example, the following Twig code:
{% set test = 'Hello, world' %}
Will compile to:
<?php
class __TwigTemplate_20df0122e7c88760565e671dea7b7d68c33516f833acc39288f926e234b08380 extends Twig_Template
{
/* ... */
protected function doDisplay(array $context, array $blocks = array())
{
// line 1
$context["test"] = "Hello, world";
}
/* ... */
}
As you can see, the inherited context is not passed to the doDisplay method by reference, and is never stored in the object itself (like $this->context = $context). This deisgn allow templates to be reusable, and is memory-friendly.
Solution 1 : using global variables
I don't know if you are aware of Global Variables in Twig. You can do a bunch of hacks with them.
The easiest usage is to load all your globals inside your twig environment.
$loader = new Twig_Loader_Filesystem(__DIR__.'/view');
$env = new Twig_Environment($loader);
$env->addGlobal('foo', 'bar');
$env->addGlobal('Hello', 'world!');
Then, you can use {{ foo }} and {{ Hello }} in your whole application.
But there are 2 problems here:
As you're trying to load variables from twig files, I assume you have lots of variables to initialize depending on your feature and don't want to load everything all time.
you are loading variables from PHP scripts and not from Twig, and your question want to import variables from a twig file.
Solution 2 : using a Twig extension
You can also create a storage extension that provide a save function to persist some template's context somewhere, and a restore function to merge this stored context in another one.
proof_of_concept.php
<?php
require __DIR__.'/vendor/autoload.php';
class StorageTwigExtension extends Twig_Extension
{
protected $storage = [];
public function getFunctions() {
return [
new Twig_SimpleFunction('save', [$this, 'save'], ['needs_context' => true]),
new Twig_SimpleFunction('restore', [$this, 'restore'], ['needs_context' => true]),
];
}
public function save($context, $name) {
$this->storage = array_merge($this->storage, $context);
}
public function restore(&$context, $name) {
$context = array_merge($context, $this->storage);
}
public function getName() {
return 'storage';
}
}
/* usage example */
$loader = new Twig_Loader_Filesystem(__DIR__.'/view');
$env = new Twig_Environment($loader);
$env->addExtension(new StorageTwigExtension());
echo $env->render('test.twig'), PHP_EOL;
twig/variables.twig
{% set foo = 'bar' %}
{% set Hello = 'world!' %}
{{ save('test') }}
twig/test.twig
{% include 'variables.twig' %}
{{ restore('test') }}
{{ foo }}
Note: if you only want to import variables without actually rendering what's inside twig/variables.twig, you can also use:
{% set tmp = include('variables.twig') %}
{{ restore('test') }}
{{ foo }}
Final note
I'm not used to the JavaScript twig port, but it looks like you can still extend it, that's your go :)
Because of Twig's scoping rules (which I assume are replicated by the gulp version), you cannot pass variables up from a child template without creating a helper function. The closest thing you can do is to use inheritance to replicate this.
As such, your mock.twig file would become
{% set mock = {
title : "This is my title"
}
%}
{% block content %}{% endblock %}
Your container.twig would then become
{% extends 'mock.twig' %}
{% block content %}
{% include 'component.twig' with mock %}
{% endblock %}
This achieves your goals of separating the mock content from the templates for the most part and, using dynamic extends, you can do something like
{% extends usemock == 'true'
? 'contentdumper.twig'
: 'mock.twig' %}
with a contentdumper.twig file that is just a stub like so
{% block content %}{% endblock %}
and then set the usemock variable to determine if you will be using the mock data or not.
Hopefully this helps, even though it doesn't really solve the exact problem you are having.
I am trying to create a dynamic hyperlink that depends on a value passed from a function:
{% for item in field_list %}
<a href={% url index_view %}{{ item }}/> {{ item }} </a> <br>
{% endfor %}
The problem is that one of the items in field_list is "Hockey Player". The link for some reason is dropping everything after the space, so it creates the hyperlink on the entire "Hockey Player", but the address is
http://126.0.0.1:8000/Hockey
How can I get it to go to
http://126.0.0.1:8000/Hockey Player/
instead?
Use the urlencode filter.
{{ item|urlencode }}
But why are you taking the name? You should be passing the appropriate view and PK or slug to url which will create a suitable URL on its own.
Since spaces are illegal in URLs,
http://126.0.0.1:8000/Hockey Player/
is unacceptable. The urlencode filter will simply replace the space with %20, which is ugly/inelegant, even if it does kind of get the job done. A much better solution is to use a "slug" field on your model that represents a cleaned-up version of the title field (I'll assume it's called the title field). You want to end up with a clean URL like:
http://126.0.0.1:8000/hockey_player/
To make that happen, use something like this in your model:
class Player(models.Model):
title = models.CharField(max_length=60)
slug = models.SlugField()
...
If you want the slug field to be pre-populated in the admin, use something like this in your admin.py:
class PlayerAdmin(admin.ModelAdmin):
prepopulated_fields = {"slug": ("title",)}
....
admin.site.register(Player,PlayerAdmin)
Now when you enter a new Player in the admin, if you type "Hockey Player" for the Title, the Slug field will become "hockey_player" automatically.
In the template you would then use:
{% for item in field_list %}
<a href={% url index_view %}{{ item.slug }}/> {{ item }} </a> <br>
{% endfor %}
There is this builtin filter .
http://docs.djangoproject.com/en/dev/ref/templates/builtins/#urlencode
Although you should be using one of these
http://docs.djangoproject.com/en/dev/ref/models/fields/#slugfield