Accessing dictionary inside Django template - django

I am customizing my item query result and marking these items as added in the cart based on DB values, i have succeeded in making this dictionary but the issue is how to access its values now inside the template
my view
menu_items =[]
menus = MenuItem.objects.all().order_by('-date_added')
for item in menus:
print(item.id)
menus_added['item']=item
if item.id in cartitem:
menus_added['is_added']=True
else:
menus_added['is_added']=False
menu_items.append(menus_added)
menus_added = {}
print(menu_items)
restaurants = Restaurants.objects.all()
categories= Category.objects.all()
return render(request,'store/store.html',context={
'product':menu_items, <-- i want access this dictionary
'restaurants':restaurants,
'categories':categories
})
this approach is not working
template
{% for item in product.item %}
<div class="col-md-4">
<figure class="card card-product-grid">
<div class="img-wrap">
<img src="{{item.image_url}}">
</div> <!-- img-wrap.// -->
<figcaption class="info-wrap">
<div class="fix-height">
{{item.item_name}}
<div class="price-wrap mt-2">
<span class="price">{{item.price}}</span>
<del class="price-old">${{item.price}}</del>
</div> <!-- price-wrap.// -->
</div>
{% if is_added %}
Added !
{% else %}
Add to cart
{% endif %}
</figcaption>
</figure>
</div> <!-- col.// -->
{% endfor %}

You don't need for loop here({% for item in product.item %}), just try {{product.image_url}}, not {{item.image_url}}
or {{ product.price }}, not {{item.price}}

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.

Getting an empty query set Django

I'm trying to develop a search functionality but only getting a empty query set every single time .
class SearchView(TemplateView):
template_name = "search.html"
def get_context(self, **kwargs):
context = super().get_context(**kwargs)
kw = self.request.GET.get("search")
results = Thread.objects.filter(Q(heading__icontains=kw) | Q(thread_content__icontains=kw))
print(results)
context["results"] = results
return context
Template
{% extends 'base.html' %}
{% block title %}Search{% endblock %}
{% block content %}
<div class = "container">
<div class = "row">
<div class = "col-md-12">
<h3>Search results for <span class="text-info">"{{ request.GET.search }}"</span></h3>
<h3>{{results}}</h3>
<hr>
{% for item in results %}
<div class="col-md-4">
<img src = "{{item.image.url}}" class="img-fluid" alt = "">
</div>
<div class="col-md-8">
<h4>{{item.heading}}</h4>
<p>{{item.thread_content}}</p>
</div>
{%endfor%}
</div>
</div>
</div>
{% endblock %}
request.GET.search is returning correctly , but the rest is not getting displayed
This was a real strange issue. The Browser cache took a long time to refresh with my updated code. Once I cleared the Browser Cache and Settings, it started working again.

How to check active accordion based on object id?

Here {% c_url request 'display' %} this will return either display class or None. if display class return I want to keep accordion collapse open. But this is opening all the collapse.
I want to apply display class to the particular #collapseid only. How can I do it ?
template
{% for n in navs %}
<li>
<a
data-toggle="collapse"
class="sub{{n.id}} {% c_url request 'active' %}"
href="#collapse{{n.id}}"
aria-expanded="true"
aria-controls="collapse"
><p>
{{n.title}}
</p></a
>
<div class="collapse{{n.id}} {% c_url request 'display' %}" id="collapse{{n.id}}">
<ul class="nav">
{% for i in n.nav_set.all %}
..............
{% endfor %}
</ul>
</div>
</li>
{% endfor %}
c_url template tag
#register.simple_tag
def c_url(request, value):
if request.resolver_match.url_name in ['url1', 'url2']:
return value
I can suggest two 'easier' options to do it:
Set active status flag on n in navs in context (in views.py):
for n in navs:
if <condition for active>:
n.active = True
Then in the template:
{% if n.active %}display{% endif %}
Add an additional option to the context for the active collapse id:
views.py:
for n in navs:
if <condition for active>:
context['active_id'] = n.id
Then in the template:
{% if n.id == active_id %}display{% endif %}

Django iteration (for ... in ...) how to put it in different divs?

I have few instances of model.
my model:
class Record(models.Model):
name = models.ForeignKey(Car)
image = models.ImageField(upload_to='images/')
created = models.DateTimeField(
default=timezone.now)
view:
def allrecords(request):
records = Record.objects.all().order_by('created')
return render(request, 'mycar/allrecords.html', {'records' : records})
I want show it on my website. In my template i have:
{% for record in records %}
<img src={{ record.image.url}}/>
<div>
{{record.name}}
</div>
{% endfor %}
Now i get list of my records, but i would like put the newest record to first div, next to second etc. How can i do that?
I show simple screen how i would like have that (if someone will create new record, it will go to first div and other records will change place. Is any possibility to do something like that?
edit:
<div>
{% for record in records %}
{% if forloop.counter == 1 %}
<img src={{ record.image.url}}/>
<div>
{{record.name}}
</div>
{% endif %}
{% endfor %}
</div>
<div>
{% for record in records %}
{% if forloop.counter == 2 %}
<img src={{ record.image.url}}/>
<div>
{{record.name}}
</div>
{% endif %}
{% endfor %}
</div>
.
.
# till your 5th image
You can use forloop.counter to get the iteration number and check what is the iteration the loop and handle data accordingly.
In addition you can use CSS to make the layout work as you want.
Here is the information for Django template counter
Edit :
{% for record in records %}
<div>
{% if forloop.counter == 1 %}
# Here you can get your first images
<img src={{ record.image.url}}/>
<div>
{{record.name}}
</div>
{% endif %}
</div>
<div>
{% if forloop.counter == 2 %}
# Here you can get your first images
<img src={{ record.image.url}}/>
<div>
{{record.name}}
</div>
{% endif %}
</div>
.
.
# till your 5th image
{% endfor %}
There are two ways to do this. If you want to set this option for a single view then:
def all_records(request):
records = Record.objects.all().order_by('-created')
return render(request, 'mycar/allrecords.html', {'records' : records})
You're almost correct but order_by('created') leads to asceding order while order_by('-created') leads to descending order which is what you require.
Alternatively, if you want to have this setting to apply to all views then set class Meta in your models.py which will ensure that wherever you use Record.objects.all() it returns Records in descending order of created field:
class Record(models.Model):
name = models.ForeignKey(Car)
image = models.ImageField(upload_to='images/')
created = models.DateTimeField(
default=timezone.now)
class Meta:
ordering = ('-created')
It's Django design pattern to make all logical decisions in models and views and only just plugin formatted data in templates. You shouldn't add any complex logic in templates.
I'm assuming the question means that the model might have more than 5 records. If so, a more generic solution would be
<div class='row'>
<div class='firstimage'>
<img src={{ records[0].image.url}}/>
{{record.name}}
</div>
{% for record in records %}
{% if forloop.counter > 1 %}
<div class='subsequentimage'>
<img src={{ record.image.url}}/>
{{record.name}}
</div>
{% endif %}
{% cycle "" "</div><div class='row'>" "" %}
{% endfor %}
</div>
Note the use of the 'cycle' tag to begin a new row div every third cell div.
I don't know what your CSS classes are to distinguish between rows and cells so I used 'row', 'firstimage' (which might be defined to take up twice as much width) and 'subsequentimage' as example classes.
I recommend you to use the context variables:
def all_records(request):
records = Record.objects.all().order_by('-created')
newest = records[:5]
oldest = records[5:]
return render(request, 'mycar/allrecords.html', {'newst' : newest,
'oldest': oldest })
In your template :
{% for new in newst %}
<div>what you want with news</div>
{% endfor %}
{% for old in oldest %}
<div>what you want with olds</div>
{% endfor %}

combine number of database requests using ORM

I am working on a website, where a user can vote and comment on different projects in various categories. Whenever a user returns to the site, their votes will be highlighted and all the comments will be visible.
The problem is that every time the page is loaded there are many database calls due to the design of my models or due to me not finding an efficient way of retrieving the data.
My models are as follows:
class ProjectCategory:
title=models.CharField(...)
class Project:
category=models.ForeignKey(ProjectCategory)
title=models.CharField(...)
def ownedComments(self):
return Comment.objects.filter(project=self).order_by('-submissionTime')
def ownedCommentsPreview(self):
return Comment.objects.filter(project=self).order_by('-submissionTime')[0:3]
def ownedVotes(self):
return Vote.objects.filter(project=self,upVoted=True).count()
class Vote:
project=models.ForeignKey(Project)
user=models.ForeignKey(User)
vote=models.IntegerField(...)
class Comment:
project=models.ForeignKey(Project)
user=models.ForeignKey(User)
title=models.CharField(...)
Here are relevant parts of my views.py:
def getCurrentUserData(request=None):
if (request==None) or (request.user.is_authenticated()==False):
return {'loggedInUsername':'Anonym','userIsLoggedIn':False}
return {'loggedInUsername':request.user.username,'userIsLoggedIn':True}
def getProjectResponse(request,surveyFile=None,additionalInfo={}):
userVotedUp=[]
if surveyFile!=None:
userVotes=Vote.objects.filter(upVoted=True,surveyFile=surveyFile)
for vote in userVotes:
userVotedUp.append(vote.project.id)
answerDict={'userVotedUp':userVotedUp,'prjCategories':PrjCategory.objects.select_related(),'projects': Project.objects.prefetch_related('category').filter(visible=True),'spammerquestion':spammerquestion.SpammerQuestion().getRandomQuestion(),'rotatingLines':helpers.getRandomRotatingLines(),'backgroundimageurl':helpers.getBackgroundImageUrl()}
answerDict.update(getCurrentUserData(request))
answerDict.update(additionalInfo)
return answerDict
def showProject(request,prjNo):
currentPrj=get_object_or_404(Project,prjNo=prjNo,visible=True)
surveyFile=assignSurveyFile(request,create_surveyFile_if_not_existing=False)
return render_to_response('website/singleproject.html', getProjectResponse(request,surveyFile,{'currentPrj':currentPrj,'immediateProjectID':currentPrj.id}),context_instance=RequestContext(request))
The template contains many iterations over projects and categories, there might be several database calls happening here. Relevant parts of the template are:
{% for project in projects %}
self.vote['{{ project.id }}']=ko.observable(new Vote({'totalVoteNumber':ko.observable({{ project.ownedVotes }}),'userVoteState':ko.observable({% if project.id in userVotedUp %}true{% else %}false{% endif %})}));
self.comments['{{ project.id }}']=ko.observableArray([]);
{% for comment in project.ownedCommentsPreview %}
self.comments['{{ project.id }}'].push(new Comment({'description':'{{ comment.description|striptags|safe }}','submissionTime':'{{ comment.submissionTime|humanDT }}','commentUuid':'{{ comment.commentUuid }}','deletable':false}));
{% endfor %}
{% endfor %}
{% for prjCat in prjCategories %}
.prjCatUnderline{{ prjCat.id }} {border-bottom: 0px solid {{ prjCat.color }};}
.prjCatUnderline{{ prjCat.id }}:hover {border-bottom: 3px solid {{ prjCat.color }};}
{% endfor %}
{% for prjCat in prjCategories %}
{{ prjCat.title }}
{% if not forloop.last %}<span class="catpipe">|</span>{% endif %}
{% endfor %}
<script type="text/javascript">
var projectLocations = [{% for project in projects %}{% if project.location != '' %}['{{ project.title }}', {{ project.location }}, {{ project.id }}, '{{ MEDIA_URL }}{{ project.mapImage }}', {{ project.mapImage.width }}, {{ project.mapImage.height }}, '{{ project.id }}'],
{% endif %}{% endfor %}];
</script>
{% for project in projects %}
<div class="item prjCat{{ project.category.id }}">
<div class="prjnumberbox">
<div class="numberbar" style="background-color:{{ project.category.color }}"></div>
<div class="prjnumber">{{ project.prjNo|stringformat:"02d" }}</div>
<div class="numberbar" style="background-color: {{ project.category.color }}"></div>
</div>
<div class="prjheadline"><span>{{ project.title }}</span></div>
<div class="prjimagecontainer">
<!-- ko with: $root.vote['{{ project.id }}'] -->
<div class="prjimageoverlay"><a data-bind="click: function(data,event) { $root.showSingleProjectData('{{ project.id }}',data) },css : { imgVoted :userVoteState }" class="singleProjectOverlay" href="{% url 'website.views.showProject' prjNo=project.prjNo %}"></a></div>
<div class="prjimage"><img src="{{ MEDIA_URL }}{{ project.teaserImage }}" /></div>
<!-- /ko -->
</div>
<div class="prjtextcontainer" {% if project.ownedComments|length_is:"0" %}style="background-image:none;"{% endif %}>
<div class="prjtext">{{ project.teaserText|safe }} <a class="singleProjectOverlay" data-bind="click: function(data,event) { showSingleProjectData('{{ project.id }}',data) }" href="{% url 'website.views.showProject' prjNo=project.prjNo %}">mehr >></a></div>
<div class="votesline"><span class="voteslinefont" data-bind="with: vote['{{ project.id }}']"> <span class="votecount" data-bind="text: totalVoteNumber">{{ project.ownedVotes }}</span> votes </span></div>
<div class="prjcomments nojs">
{% for comment in project.ownedCommentsPreview|slice:":4" %}
<div class="prjcommentitem">
{{ comment.teaserdescription }}
</div>
{% endfor %}
</div>
<div class="prjcomments" data-bind="foreach: comments['{{ project.id }}'], visible: comments['{{ project.id }}']().length > 0">
<!-- ko if: $index() < 4 -->
<div class="prjcommentitem">
<em data-bind="text: submissionTime"> </em><br/>
<span data-bind="text: description"> </span>
[X]
</div>
<!-- /ko -->
</div>
</div>
</div>
{% endfor %}
For the front page I'd like to retrieve all the projects, most recent three comments, the total number of votes for a project and the comments and votes by the user.
It would be great if that was possible with one db call, or with two, a general one to get the number of votes and the comments, and one for the data specific to the user.
CUrrently I am retrieving all the projects with one call, so I am automatically getting all the project categories. Then I get all the comments at once and assign them to the projects in python. I then get the comments and votes for a certain user with one call each.
Is there a way - without using sql directly - to get
comments and votes for a user with a single database call
comments, projects, accumulated number of votes per project and project categories at once?
One idea would be to download the whole database using select_related() and then sorting everything out in Python, but if in the future I have a large number of votes or comments, this might not be a good idea.