Sort python list with comparing integers - python

Here are my original two (2) functions:
def user_bible(query):
output = requests.get("http://getbible.net/json?passage={0}".format(query))
json_dict_output = json.loads(output.text.strip("();"))
before_for_loop_parse = json_dict_output[u'book'][0][u'chapter'] #[u'2'][u'verse']
keys = before_for_loop_parse.keys()
keys.sort(compare_number_strings)
stored_list = []
for k in keys:
stored_list.append(before_for_loop_parse[k][u'verse'])
return parse_rough_draft(json_dict_output)
and my second small function:
def compare_number_strings(string1, string2):
return cmp(int(string1), int(string2))
Then my tutor helped me edit a new function which allowed for chapter and verse numbers to be presented in the function's output
def parse_rough_draft(json_dict_output):
books = json_dict_output[u'book']
result_dict={}
for i in books:
book_name_variable = i[u'book_name']
current_book_value = result_dict.setdefault(book_name_variable, {})
chapter_variable = i[u'chapter_nr']
chapter_value = current_book_value.setdefault(chapter_variable, {})
all_chapter_verses_variable = i[u'chapter']
for m in all_chapter_verses_variable.keys():
verse = all_chapter_verses_variable[m]
chapter_value[m] = verse[u'verse']
return result_dict
But, my new function parse rough draft(): outputs an unsorted list. I am trying to sort this list and then compare the integers of the list so the output will present verses from say "Jn 2:4-19" in proper numerical order. In this function parse rough draft(): am I defining a dictionary above the for loop, and thus is everything in the for loop incorporated in my result_dict dictionary?
I added:
keys = result_dict.keys()
keys.sort(compare_number_strings)
return keys
But now the output on my jinja2 template page only prints the output ' Book: John '
from the following Bible.html template
</form>
{% with messages = get_flashed_messages() %}
{% with books = messages[0] %}
{% if books %}
<div class="well">
<div class="row" style="margin: 50px;margin-right: 100px; font-size:150%;">
<div class="col-md-12">
<!--<h5>Scripture:</h5> -->
{% for book in books %}
<div class="book">
Book: {{book}}
{% for chapter in books[book]%}
<div class="chapter">
Chapter: {{chapter}}
{% with sorted_keys = books[book][chapter].keys() %}
{% for verse in sorted_keys %}
<div class="verse">
Verse: {{verse}}
<div class="verse-text">{{books[book][chapter][verse]}}</div>
</div>
{% endfor %}
{% endwith %}
</div>
{% endfor %}
</div>
{% endfor %}
</div>
</div>
</div>
{% endif %}
{% endwith %}
{% endwith %}
</div>
The function can be seen live here:
http://shielded-brushlands-1568.herokuapp.com/Bible/
and the github repo here:
https://github.com/phillipsk/webapp/blob/master/templates/bible.html

Related

How to list objects of the same date?

I want to list all items in my template, but I want to list items under the same year. For example,
under the 2021 title, model objects for that year should be listed. Year titles should come dynamically. How can I do it?
views.py
def press_list(request):
press_contents = PressContent.objects.all().order_by('-date')
context = {
'press_contents': press_contents
}
return render(request, "press_list.html", context)
models.py
class PressContent(models.Model):
label = models.CharField(max_length=500)
url = models.URLField(max_length=500)
date = models.DateTimeField(blank=True, null=True)
press_list.html
{% for press in press_contents %}
<div class="card" style="width: 18rem; margin:15px">
<div class="card-header">
{{ press.date.year }}
</div>
<ul class="list-group list-group-flush">
<li class="list-group-item">{{ press.label }}</li>
# Other objects from this year should come here.
</ul>
</div>
{% endfor %}
To be clear:
2021
obj 1
obj 2
2020
obj 3
obj 4
...
...
You can work with the {% regroup … by … %} template tag [Django-doc]:
{% regroup press_contents by year as pressitems %}
{% for pressyear in pressitems %}
<div class="card" style="width: 18rem; margin:15px">
<div class="card-header">
{{ pressyear.grouper }}
</div>
<ul class="list-group list-group-flush">
{% for press in pressyear.list %}
<li class="list-group-item">{{ press.label }}</li>
# Other objects from this year should come here.
{% endfor %}
</ul>
</div>
{% endfor %}
If you can afford to convert a queryset into a list of objects, then you can use the built-in template filter regroup (I think, I've never used it).
Another approach would be to write a python generator function and pass it in the context, to be iterated over by the template. This avoids issues with resource consumption when the queryset comprises a large number of objects. Something like
def year_grouper():
qs = PressContent.objects.all().order_by('-date')
last_object_year = 1000000000
for obj in qs:
obj.year_changed = ( obj.date.year != last_object_year )
yield obj
last_object_year = obj.date.year
and
{% for obj in year_grouper %}
{% if obj.year_changed %}
... year header, etc.
{% endif %}
... display obj
{% endfor %}

Elasticsearch Python Django: How to limit the output text content and highlight the input keyword

This is my search function in views.py
def search(request, pk, slug):
es = Elasticsearch()
es_client = Elasticsearch(['http://127.0.0.1:9200'])
print('called search')
search_text = request.GET.get('qq')
print('Search text: {}'.format(search_text))
print('cluster id/ ealstic search index: {}'.format(pk))
s = None
count = 0
try:
if search_text:
s = Search(index=str(pk)).using(es_client).query("match", content=search_text)
response = s.execute()
count = 0
for hit in s:
count += 1
print(str(count) + ' - ' + str(hit.currnet_url))
#print(hit.content)
else:
print('nothing more found')
else:
print('No text to search')
except Exception as e:
count = 0
print('Exception caught')
msg = 'Cluster is not ready to be searched'
return render(request, 'base_app/cluster_search.html', {'warning':msg, 'count':count})
return render(request, 'base_app/cluster_search.html', {'cluster':slug, 'hits':s, 'count':count})
This is how I am indexing data to Elasticsearch.
def elastic_indexer(text, depth, url, clusrer_id):
es_client = Elasticsearch(['http://127.0.0.1:9200'])
doc = {
"date": time.strftime("%Y-%m-%d"),
"currnet_url": url,
"depth": depth,
"content": text
}
res = es_client.index(index= str(clusrer_id), doc_type="_doc", body=doc)
print(res["result"])
This is the frontend template where the users input a text to search.
{% extends "account/base.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block head_title %}{% trans "Search" %}{% endblock %}
{% block content %}
Go Back
<P style="font-size:17px;">You are searching in {{cluster.title}}</P>
<form method="GET" action="">
{% csrf_token %}
<button class="btn btn-primary" action="">Search</button>
<input id="q" name="qq" type="text" placeholder="enter search text here" style="width: 500px;">
</form>
{% if hits %}
<table>
{% for hit in hits %}
<tr>
<td>Hit: {{hit.currnet_url}}</td>
</tr>
<tr>
<td>Content: {{hit.content}}</a></td>
</tr>
{% empty %}
<h3> No search result found </h3>
{% endfor %}
</table>
{% endif %}
<div class="pagination">
<span class="step-links">
{% if page_obj.has_previous %}
« first
previous
{% endif %}
<span class="current">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
</span>
{% if page_obj.has_next %}
next
last »
{% endif %}
</span>
</div>
{% endblock %}
This is returning everything, all the text stored in "content", how do I limit this to only the user's input text and only show limited characters before and after the input text? and including highlighting the input text? Please help me out
Example:
What it shows:
*User inputs text, assuming it's "django"*
hits: https://www.djangoproject.com/
Content: all of the scraped text stored in "content"
What I want it to show:
User inputs text, assuming it's "django"
hits: https://www.djangoproject.com/
Content: 10 words before "django" and 10 words after "django"

Counter increment in template outside of for loop

I need to do a counter increment within a loop. I had a look at django for.counter, but unfortunately, my increments dont exactly occur within each iteration of the loop. So is there any way at all that I can implement increment of a variable within django template, without going to great pains to implement a new object in my code to do this without such an increment?
In the following code, I am writing the lines {{ count = 0 }}, {{ count += 1 }} just for illustration purpose. I know it wont work. The following is a very simplified form of my template:
<div class="jumbotron slotgroup slotavailable mb-1 mt-5" id="jumbo_week_avail">
<div class="slot-header" role="alert">
Headertext
</div>
{% if weeklyslotsav %}
{% for day,daynum in weekzip %}
{{ count = 0 }}
{% if daynum in weeklyslotsav.day %}
{% for weekslotav in weeklyslotsav %}
{% if weekslotav.day == daynum %}
<div class="row row_week_avail{{ weekslotav.day }}" id="row_week_avail{{ weekslotav.day }}_{{ count }}">
</div>
{{ count += 1 }}
{% endif}
{% endfor %}
{% else %}
<div class="row row_week_avail{{ daynum }}" id="row_week_avail{{ daynum }}_0">
</div>
{% endif %}
{% endfor %}
{% else %}
{% for weekday, weeknum in weekzip %}
<div class="row row_week_avail{{ weeknum }}" id="row_week_avail{{ weeknum }}_0">
</div>
{% endfor %}
{% endif %}
</div>
The following is a segment from my views:
def edit_doctorslots(request, cliniclabel, doctor_id):
doctor_id=int(doctor_id)
doc = get_object_or_404(doctor, docid=doctor_id)
cl = Clinic.objects.get(label=cliniclabel)
print("Clinic name", cl.name)
regularslotsav = ''
try:
regularslotsav = Timeslots.objects.filter(clinic =cl, doctor =doc, available =True)
except:
pass
regularslotsbr = ''
try:
regularslotsbr = Timeslots.objects.filter(clinic =cl, doctor =doc, available =False)
except:
pass
weekavzip = ''
try:
weeklyslotsav = Weekdays.objects.filter(clinic =cl, doctor =doc, available =True)
weekav = range(0, len(weeklyslotsav))
weekavzip = list(zip(weeklyslotsav, weekav))
except:
pass
weeklyslotsbr = ''
try:
weeklyslotsbr = Weekdays.objects.filter(clinic =cl, doctor =doc, available =False)
except:
pass
formslot = SlotForm()
formspecialdays = SpecialdaysForm()
formweekdays = WeekdaysForm()
weekdays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
weekdaynum = [0,1,2,3,4,5,6]
weekzip = list(zip(weekdays, weekdaynum))
newweekzip = weekzip
return render(request, 'clinic/editslots0.html', {'rnd_num': randomnumber(), 'clinic': cl, 'doctor': doc, 'formslot': formslot, 'formspecialdays': formspecialdays, 'formweekdays': formweekdays, 'weekzip': weekzip, 'newweekzip': newweekzip, 'regav': regularslotsav, 'regbr': regularslotsbr, 'weekav': weekavzip, 'weekbr': weeklyslotsbr, 'weeklyslotsav': weeklyslotsav })
I've seen many similiar questions on SO. However in all of them I've seen people introducing for.counter. But this is not suitable for my purpose.
You can use with tag to set variables in template as -
{% with count=0 %}
{{ count}}
...do other stuffs
{% endwith %}
and for maths you could use django math filters like
{{ count|add:"1" }}
You can code you with use of both.
For more about setting variable in django template - How to set a value of a variable inside a template code?
and for using math in django - How to do math in a Django template?
Hope this helps you.

Recursively find child items and list in jinja

I'm trying to display "notes" in a nested list. Each note has a property called parentID that indicates a note that it is nested under.
Currently I am achieving a single level nest by doing this:
models.py
class Note(Model):
title = CharField()
tags = CharField()
content = TextField()
parentID = IntegerField(default=0)
class Meta:
database = db
app.py
def getSubnotes(note):
note_id = note.id
subnotes = models.Note.select().where(models.Note.parentID == note_id)
return subnotes
app.jinja_env.globals.update(getSubnotes=getSubnotes)
Index.html
<div class="row">
<div class="medium-12 medium-centered">
<ul>
{% for note in notes %}
{% if note.parentID == 0 %}
<li>{{ note.title }}</li>
<ul>
{% for subnote in getSubnotes(note) %}
<li>{{ subnote.title }}</li>
{% endfor %}
</ul>
{% endif %}
{% endfor %}
</ul>
</div>
I would like to, however, recursively find all children notes of a single note and list them out, so there are nests of nests.
I have seen this as an example of how to recursively list in jinja (from jinja docs):
<ul class="sitemap">
{%- for item in sitemap recursive %}
<li>{{ item.title }}
{%- if item.children -%}
<ul class="submenu">{{ loop(item.children) }}</ul>
{%- endif %}</li>
{%- endfor %}
</ul>
However I am confused about what .children actually is. How is it referencing itself or items of the same type?
How would I go about doing this recursively or is there a better method for achieving the same thing?
Any help is very much appreciated!
In the example from the docs, I think that item.children is just an iterable of items of the same type. Then {{ loop(item.children) }} causes the current loop to be executed over the iterable item.children creating a nested list.
You can verify this:
import jinja2
templ = """
{%- for item in items recursive %}
{{item.name}}
{%- if item.children %}
{{- loop(item.children) }}
{%- endif %}
{%- endfor %}
"""
items = [{'name': 'Bobby'},
{'name': 'Jack',
'children': [
{'name': 'Jake'},
{'name': 'Jill'}]},
{'name': 'Babby', 'children': []}]
template = jinja2.Template(templ)
print(template.render(items=items))
prints out
Bobby
Jack
Jake
Jill
Babby
So in your example, I think you should be able to do something like
<div class="row">
<div class="medium-12 medium-centered">
<ul>
{% for note in notes recursive %}
{% if note.parentID == 0 %}
<li>{{ note.title }}</li>
<ul>
{{ loop(getSubnotes(note)) }}
</ul>
{% endif %}
{% endfor %}
</ul>
</div>
as long as getSubnotes(note) returns empty if the note has no subNotes.
Even more complete, in my opinion (it explores lists and dictionaries inside lists):
<dl class="row">
{% for key, value in json.items() recursive %}
{% set outer_loop = loop %}
<dt class="col-3">{{ key }}</dt>
<dd class="col-9">
{% if value is string %}
{{ value }}
{% elif value is mapping %}
<dl class="row">
{{ loop(value.items()) }}
</dl>
{% elif value is iterable %}
<ol>
{% for item in value %}
<li>
{% if item is mapping %}
<dl class="row">
{{ outer_loop(item.items()) }}
</dl>
{% else %}
{{ item }}
{% endif %}
</li>
{% endfor %}
</ol>
{% else %}
{{ value }}
{% endif %}
</dd>
{% endfor %}
</dl>
I wonder if/how could be simplified.

Django: Template posting random letters instead of correct variable

In a template, I have the following:
{% for t,k in draft_l %}
<li>
<div id="name_area"><span>{{ t }}</span></div>
<ul id="tool_area">
<li>Edit</li>
<li>Publish</li>
<li>Rename</li>
<li>Delete</li>
<li style="display: none;">{{ k }}</li>
</ul>
</li>
{% endfor %}
This is the view:
user = request.user
user_drafts = Draft.objects.filter(user = user)
drafts = dict()
for d in user_drafts:
drafts[d.title] = d.id
alertnum = get_alertnum(user)
return render_to_response('Posting/Pages/posting_draft.html', {'STATIC_URL':STATIC_URL, 'draft_l' : drafts, 'selected':"dr", 'alertnum': alertnum})
The value of k seems to be random letters. When I added a print statement to the for loop, all of the numbers for the ID seemed right. Could you comment if you think it "should work"
{% for t,k in draft_l.items %}
Templates work a little differently than native python. Notice the .items.

Categories