DTL - If statement not comparing to be true... don't know why - python

I'm currently working on a Django project and I have the current models
from django.db import models
class Topic(models.Model):
def __str__(self):
return self.topic_text
topic_text = models.CharField(max_length=100)
class Subtopic(models.Model):
def __str__(self):
return self.subtopic_text
topic = models.ForeignKey(Topic)
subtopic_text = models.CharField(max_length=100)
class Question(models.Model):
def __str__(self):
return self.question_text
topic = models.ForeignKey(Topic)
subtopic = models.ForeignKey(Subtopic)
question_text = models.CharField(max_length=200)
mod_date = models.DateTimeField('date modified')
pub_date = models.DateTimeField('date published')
answer_text = models.TextField()
After passing that through my views
def index(request):
question_list = Question.objects.all()
topic_list = Topic.objects.all()
subtopic_list = Subtopic.objects.all()
context = {
'topic_list': topic_list,
'subtopic_list': subtopic_list,
'question_list': question_list
}
return render(request, 'interview/index.html', context)
And the following template
<ul>
{% for topic in topic_list %}
<li>{{ topic.topic_text}}</li>
{% for subtopic in subtopic_list %}
{{topic.topic_text}} , {{subtopic.topic}}
**THIS HERE DOES NOT WORK**
{% if subtopic.topic == topic.topic_text %}
<ul>
<li>{{ subtopic.subtopic_text}}</li>
<ul>
{% endif %}
{% for question in question_list %}
<li>{{ question.question_text }}</li>
{% endfor %}
</ul>
{% endfor %}
</ul>
{% endfor %}
</ul>
However the line in the if statement is not working. When I change the == to != it prints (the wrong stuff) so I know it's not my syntax but just the fact they are not equal; however, when I check it with
{{topic.topic_text}} , {{subtopic.topic}}
Finance , Finance
Finance , Coding
Finance , Finance
Coding , Finance
Coding , Coding
Coding , Finance
My thought is that for DTL it's like Java and that you can't compare strings using the == ... but I couldn't find anything unique about string comparisons for DTL.

It's because you're comparing an object to a string.
You can also remove your second foreign key from Question since you already have one on Subtopic that points to Topic.
You would reference it as such:
{{Question.Subtopic.Topic.topic_text}}
which will give you the exact same thing.

After doing additional testing, I get the following:
{% if topic.topic_text == 'Finance' %}
Evaluates to true
{% if subtopic.topic == 'Finance' %}
Evaluates to false
Now, I'm not 100% sure of the cause but I'm thinking it has to do with the fact that subtopic.topic is actually pointing to the Topic Primary Key (Which is not set to topic_text) and then Django 'hides' it AFTER the comparison with the following function. Maybe? I'm going to make some changes to the model and let you guys know.
def __str__(self):
return self.topic_text
So apparently, Django does the comparison before the output so what was happening was it was comparing topic.topic_text (A string) to subtopic.topic (An object) and then transforming the object into string based on the def __ str __ function I typed above. I solved it by doing the following
{% if subtopic.topic.topic_text == topic.topic_text%}

You can use ifequal for this
{% if subtopic.topic == topic.topic_text %} can be changed to {% ifequal subtopic.topic topic.topic_text %}
Thank should fix your issue https://docs.djangoproject.com/en/1.8/ref/templates/builtins/

Related

Reverse and get_absoulute_url with django 2.0

I'm getting an error when accesing my url "...pokemon/list/"
Reverse for 'pkmn-detail' not found. 'pkmn-detail' is not a valid view function or pattern name.
What i'm trying to do is first show a list of the created pokemons, then link to the detail page of each one through it's number.
I have defined a get_absoulte_url method and used reverse with it in my model, so here are my models, views, urls and templates relevant:
pokeworld/models.py
class Pokemon(models.Model):
pkmn_number = models.IntegerField(unique=True)
pkmn_name = models.CharField(max_length=30)
pkmn_type = models.CharField(max_length=20, choices=TYPE_CHOICES, default='Normal')
pkmn_desc = models.CharField(max_length=150)
pkmn_slug = AutoSlugField(populate_from='pkmn_name', unique_with='pkmn_number')
def get_absolute_url(self):
return reverse('pkmn-detail', kwargs={'pk': self.id})
pokeworld/views.py
class PokemonList(ListView):
model = Pokemon
template_name = 'pokeworld/pokemonlist.html'
def get_queryset(self):
return Pokemon.objects.all().order_by('pkmn_number')
def PokemonDetail(request, pk):
try:
pokemon_id = Pokemon.objects.get(pk=pk)
except Pokemon.DoesNotExist:
raise Http404("Pokemon does not exist")
return render(request, 'pokemondetail.html', context={'pkmn_id':pkmn_id})
pokeworld/templates/pokeworld/pokemondetail.html
{% extends 'baseP.html' %}
{% block title %} Detail {{ pkmn.pkmn_name }} {% endblock %}
{% block content %}
<h1>#{{ pkmn.pkmn_number }} {{ pkmn.pkmn_name }}</h1>
<p><strong>Type:</strong> {{ pkmn.pkmn_type }}</p>
{% endblock %}
pokeworld/urls.py
urlpatterns = [
...
path('pokemon/list/', PokemonList.as_view(), name='pkmn-list'),
path('pokemon/detail/<int:pk>', PokemonDetail, name='pkmn-detail'),
I really don't know what to edit, i've searched and searched but i don't know if i'm not understading the solutions that others have been given or if i have a made a mess in my code, i'm really hoping someone can point me in the right direction

DJANGO: Sorting sets of sets

I have this models (simplified):
#models.py
class Expression(models.Model):
text = models.CharField(max_length=254)
class Country(models.Model):
name = models.CharField(max_length=100)
class Definition(models.Model):
expression = models.ForeignKey(Expression)
country = models.ForeignKey(Country)
text = models.CharField(max_length=254)
class Vote(models.Model):
definition = models.ForeignKey(Definition)
And this view
#views.py
def index(request):
expressions = Expression.objects.all()
return render(request, 'expression_index.html', { 'expressions':expressions)
So it will show the last 10 created expressions.
Then in the template I have this:
#index.html
{% for expression in expressions %}
{{ expression }}
{% for definition in expression.definition_set.all %}
<ul>
<li>{{ definition }}</li>
</ul>
{% endfor %}
{% endfor %}
Every definition has several votes.
Every vote is a single row so we can do:
definition.votes_set.count()
How can I achieve to display them like this:
The top definition of every country alphabetically. Each country appears only with one definition.
Lets say Germany has two definitions for expression "A" and Denmark has three definitions for the same expression it will show only two definitions: the one with the most votes.
I hope I'm making sense.
Thanks
I think something like this should work (untested)
from django.db.models import Count
{{ expression.definition_set.annotate(Count('votes_set')) }}
{% for definition in expression.definition_set.order_by('country','votes_set__count') %}
This queryset will sort alphabetically by country, then each country from it's top voted definition to least.
expression = Expression.objects.get(text__exact="A")
definitions = Definition.objects.filter(expression=expression).annotate(num_votes=Count('vote')).order_by("country__name", "-num_votes")
If i try to keep only the top definition of each country as you wanted, and set .distinct("country") at the end of the queryset, it will throw this error:
NotImplementedError at annotate() + distinct(fields) is not implemented.
So another solution would be:
import operator
expression = Expression.objects.get(text__exact="A")
# Get top definitions sorted by num of votes and convert the values to list.
top_definitions = list(Definition.objects.filter(expression=expression).annotate(num_votes=Count('vote')).order_by("num_votes").values("id", "country", "country__name", "expression", "text", "num_votes"))
# Remove dublicate countries and leave the only the top voted definition.
definitions = list({v['country']: v for v in top_definitions}.values())
# Sort alphabetically by country.
definitions.sort(key=operator.itemgetter('country__name'))
return render(request, 'expression_index.html', {'definitions': definitions, 'expression': expression})
template:
<h1>{{ expression.text }}</h1>
<ul>
{% for definition in definitions %}
<li>{{ definition.country__name }} - {{ definition.text }} - {{ definition.num_votes }}</li>
{% endfor %}
</ul>

How to display multiple ForeignKey filtered items in a single view in django?

I'm trying to understand the best way to display ForeignKey filtered data in a Django model.
I have three models reduced to this:
// models.py
class Publisher(models.Model)
def publisher_name = models.TextField()
def publisher_slug = models.SlugField()
def founded_year = models.IntegerField()
class Album(models.Model)
def album_name = models.TextField()
def publisher = models.ForeignKey('Publisher', related_name='albums')
class Song(models.Model)
def song_name = models.TextField()
def album = models.ForeignKey('Album', related_name='songs')
def published_year = models.IntegerField()
I have a URL that is composed of: /<publisher>/<published_year>/
The view I'm having trouble composing is supposed to be details like this:
Title of: Publisher.publisher_name
List of All Albums by the publisher: List of All songs from that album published the same year as the publisher__published_year: List of All songs from that album published as the url
The way, I've tried to do this that works right now is similar to this:
// views.py
class SongYearView(TemplateView):
def get_context_data(self, **kwargs):
context = super(SongYearView, self).get_context_data(**kwargs)
context['publisher'] = Publisher.objects.get(slug=kwargs['publisher_slug']
album_list=[]
for album in context['publisher'].albums.all():
single_album = dict()
single_album['album'] = album
single_album['publisher_year_song'] = album.songs.filter(published_year=context['publisher'].published_year)
single_album['filtered_year_song'] = album.songs.filter(published_year=kwargs['published_year']
album_list.append(single_album)
context['albums'] = album_list
return context
Then in the template I'm doing (with stripped out formatting)
// template.html
{{ publisher.name }}
{% for album in albums %}
{{ album.album.album_name }}
{% for song in album.publisher_year_song %}
{{ song.song_name }}
{% endfor %}
{% for song in album.filtered_year_song %}
{{ song.song_name }}
{% endfor %}
{% endfor %}
While this does work, it's not pretty and I'm pretty sure there are better ways of doing this.
This is an odd example, but just a basic example of my more detailed models. The way to think about it is Publisher -> Album -> Song or A -> B -> C. And I'm trying to get a view of all B items, that are only linked with a specific A item and then get two sets of C items for each B item, where one set is filtered on an A property and the other set is filtered on a passed argument from a URL.
I tried to get a custom model.Manager to help get this constructed, but didn't have much luck.
You could do add a custom template filter of_year:
#register.filter
def of_year(songs, year):
return songs.filter(published_year=year)
And change your template to
// template.html
{{ publisher.name }}
{% for album in publisher.albums %}
{{ album.album.album_name }}
{% for song in album.songs|of_year:publisher.founded_year %}
{{ song.song_name }}
{% endfor %}
{% for song in album.songs|of_year:filtered_year %}
{{ song.song_name }}
{% endfor %}
{% endfor %}
And clean your view:
// views.py
class SongYearView(TemplateView):
def get_context_data(self, **kwargs):
context = super(SongYearView, self).get_context_data(**kwargs)
context['publisher'] = Publisher.objects.get(slug=kwargs['publisher_slug'])
context['filtered_year'] = kwargs['published_year']
return context
Edit: rename the template filter

Haystack search on a many to many field is not working

I'm trying to run a search on a model that has a many to many field, and I want to filter the search using this field.
here is my current code:
search_indexes.py
class ListingInex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True, use_template=True)
business_name = indexes.CharField(model_attr='business_name')
category = indexes.MultiValueField(indexed=True, stored=True)
city = indexes.CharField(model_attr='city')
neighborhood= indexes.CharField(model_attr='neighborhood')
state = indexes.CharField(model_attr='state')
address = indexes.CharField(model_attr='address')
zip_code = indexes.CharField(model_attr='zip_code')
phone_number = indexes.CharField(model_attr='phone_number')
def get_model(self):
return listing
def index_queryset(self, using=None):
return self.get_model().objects.all()
def prepare_category(self, obj):
return [category.name for category in obj.category_set.all()]
listing_text.txt
{{ object.business_name }}
{{ object.state }}
{{object.city}}
{{object.zip_code}}
{{object.phone_number}}
{{object.neighborhood}}
{% for category in obj.category.all %}
{{ category.name }}
{% endfor %}
I'm trying to do a simple search like:
search_results = SearchQuerySet().filter(category=query_text).filter
it returns an empty list. Thanks in advance.
Reading your code I think the problem is here:
{% for category in obj.category.all %}
{{ category.name }}
{% endfor %}
Category is not an object, is a MultiValueField. Maybe if you try something like:
{% for category in object.category.all %}
{{ category.name }}
{% endfor %}
object.category.all instead of obj.category.all. I'm not sure the solution is this, but I'm pretty sure the error could be in this 3 lines.

Filter the data and display result ordered by no. of post

In Django I need to filter the data and display the result like. for example
Company3(20)
Company1(12)
Company2(3)
Here "Company1,Company2,Company3" are Company Names and inside the brackets "20,12,3" are no. of jobs posted by the particular company.
models.py
class User(models.Model):
first_name= forms.CharField(max_length=30,widget=forms.TextInput())
last_name = forms.CharField(max_length=30,widget=forms.TextInput())
username = forms.CharField(max_length=30,widget=forms.TextInput())
email = forms.EmailField(widget=forms.TextInput())
password = forms.CharField(widget=forms.PasswordInput())
companyname = forms.CharField(max_length=30,widget=forms.TextInput())
class jobs(models.Model):
emp = models.ForeignKey(User, unique=False)
title = models.CharField(max_length=30)
referencecode = models.CharField(max_length=30)
jobsummary = models.TextField()
jobdetails = models.TextField()
key_skills = models.CharField(max_length=30)
I tried to give views.py is like
def search_result(request):
details=User.objects.filter(jobs__isnull=False).select_related()
return render_to_response('searchresult.html', {'details': details})
templates
<ul>
{% for d1 in details %}
<li>{{ d1.companyname }}({{ d1.count }})</li>
{% endfor %}
</ul>
Give some ideas to display the results as like above
perhaps a more efficient would look like
details = User.objects.filter(jobs__isnull=False).annotate(job_count=Count('jobs'))\
.order_by('job_count')
and then in the template
<ul>
{% for d1 in details %}
<li>{{ d1.companyname }}({{ d1.job_count }})</li>
{% endfor %}
</ul>
You should use d1.jobs_set.count instead, to get the count of jobs.
So update your template to:
<ul>
{% for d1 in details %}
<li>{{ d1.companyname }}({{ d1.jobs_set.count }})</li>
{% endfor %}
</ul>
You really should have a Company model; which would have made this a simple task with the help of the aggregation api; but for your case you'll need to do it in your view:
from collections import defaultdict
from django.shortcuts import render
def search_result(request):
company_count = defaultdict(int)
for obj in User.objects.filter(jobs__isnull=False).select_related():
company_count[obj.companyname] += 1
return render(request, 'searchresult.html', {'details': company_count})
Your template would become:
{% for company_name in details %}
{{ company_name }}({{ details.company_name }})
{% endfor %}

Categories