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.
Related
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 %}
I am trying to create a specific complex query in Django that I am struggling with.
I am using pagination to display a list of cakes on the index page. I want to sort them by different attributes. Below is a screenshot of my index page.
Name (A-Z) & Name (Z-A) are implemented by simply ordering the Cake queryset by 'name' or '-name' which I am getting as POST from the form at the top of the page.
cakes_list = Cake.objects.all().order_by('name')
However I am struggling to order the queryset by minimum price.
Each cake is available in different dimensions which have different prices (dimensions and prices between cakes are different). These are stored in Dimension with a foreign key pointing to the Cake they belong to.
I want to find out the cheapest option for each cake and order my list of cakes that is used in the pagination based on that (both min price asc and desc).
I have also created a method from_price which returns the price of that cake. Which I use in my template to display each cake name together with the minimum price. But I cannot seem to be able to implement that into my sorting.
I appreciate help with how I can create a query or similar that allows me to sort all of my cakes based on the minimum price for each. I am just learning Django, so my current implementations might not be ideal.
vault/models.py:
class Cake(models.Model):
name = models.CharField(max_length=200)
def from_price(self):
temp = self.dimension_set.aggregate(Min('price')).get('price__min')
if not temp:
temp = 0
return temp
class Dimension(models.Model):
cake = models.ForeignKey(Cake, on_delete=models.CASCADE)
dimension = models.CharField(max_length=50)
price = models.DecimalField(max_digits=6, decimal_places=2)
vault/views.py
def index(request):
#from the form on the index page
order_by = request.POST.get('order_by')
if not order_by:
order_by = 'name'
cakes_list = Cake.objects.all().order_by(order_by)
paginator = Paginator(cakes_list, 5)
page_number = request.GET.get('page', 1)
page_obj = paginator.get_page(page_number)
return render(request, 'vault/index.html', {'page_obj': page_obj, 'order_by': order_by})
vault/templates/vault/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{# Form for cake sorting dropdown #}
<form action="{% url 'vault:index' %}" method="post">
{% csrf_token %}
<label for="order_by">Order by:</label>
<select name="order_by" id="order_by">
<option {% if order_by == "name" %} selected="selected" {% endif %} value="name">Name (A-Z)</option>
<option {% if order_by == "-name" %} selected="selected" {% endif %} value="-name">Name (Z-A)</option>
{% comment %}
New options for ordering by price
<option {% if order_by == "" %} selected="selected" {% endif %} value="name">Price from (Low to High)</option>
<option {% if order_by == "" %} selected="selected" {% endif %} value="-name">Price from (High to Low)</option>
{% endcomment %}
</select>
<input type="submit" value="Select">
</form>
{# Code for printing the list of cakes #}
{% if page_obj %}
<ul>
{% for cake in page_obj %}
<li>
<a href="{% url 'vault:detail' cake.id %}">
{{ cake.name }}
{% if cake.from_price %}
- from £{{ cake.from_price|floatformat:'2' }}
{% endif %}
</a>
</li>
{% endfor %}
</ul>
{% else %}
<p>No cakes are available</p>
{% endif %}
{# Code for the pagination navigation elements #}
<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>
</body>
</html>
Try to use annotation before ordering like that:
cakes_list = Cake.objects.annotate(
max_price=Max('dimension__price'),
).order_by('max_price')
If you need a min price value on each Cake record then probably the easies way is to use subquery:
from django.db.models import OuterRef, Subquery
sub_q = Dimension.objects.filter(cake=OuterRef('id')).order_by('price')
qs = Cake.objects.annotate(min_price=Subquery(sub_q.values('prize')[:1]).order_by('min_price')
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.
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
Lots of documentation on this already, but haven't been able to get any of them to work for me. Like the title implies, trying to get a set of objects that use Django Voting to sort based on the number of their votes (high to low). Have tried this and a few others, but nothing fruitful.
Using Django Voting, here is URL Conf & HTML
#urls.py
url(r'^$', 'questions'),
url(r'^(?P<object_id>\d+)/(?P<direction>up|down|clear)/vote/$',
vote_on_object, dict(model = Question, template_object_name = 'question',
template_name = 'qanda/confirm_vote.html', post_vote_redirect = '/home/', allow_xmlhttprequest=True)),
Questions in the URLconf leads to the questions view which renders questions.html
#questions.html
{% load voting_tags %}
{% votes_by_user user on the_question as vote_dict %}
{% scores_for_objects the_question as score_dict %}
<div class="question">
{% if the_question %}
<ul>
{% for question in the_question %}
{% dict_entry_for_item question from vote_dict as vote %}
{% dict_entry_for_item question from score_dict as score %}
<div class="votearrowdiv">
<div class="upvotearrow"></div></a>
<form class="linkvote" id="linkup{{ question.id }}" action="/home/{{ question.id }}/{% if vote and vote.is_upvote %}clear{% else %}up{% endif %}/vote/" method="POST">
{% csrf_token %}
<input type="image" id="linkuparrow{{ question.id }}" src="{{ media_url }}img/aup{% if vote and vote.is_upvote %}mod{% else %}grey{% endif %}.png">
</form>
<div class="downvotearrow"></div></a>
<form class="linkvote" id="linkdown{{ question.id }}" action="/home/{{ question.id }}/{% if vote and vote.is_downvote %}clear{% else %}down{% endif %}/vote/" method="POST">
{% csrf_token %}
<input type="image" id="linkdownarrow{{ question.id }}" src="{{ media_url }}img/adown{% if vote and vote.is_downvote %}mod{% else %}grey{% endif %}.png">
</form>
</div>
<li>
<div class="votecounter"><div class="numbercount">
<span class="score" id="linkscore{{ question_id }}"
title="after {{ score.num_votes|default:0 }} vote{{ score.num_votes|default:0|pluralize }}">
{{ score.score|default:0 }}
</span>
</div></div>
{{ question.question_text }}
{% endfor %}
{% endif %}
Here's my current view:
#views.py
def questions(request, movie_id):
p = Movie.objects.get(pk=movie_id)
k = Question.objects.filter(movie=p).order_by('q_pub_date')
l = k.reverse()
return render_to_response('qanda/questions.html', {'movie':p, 'the_question':l}, context_instance = RequestContext(request))
I know I can't sort using "score" because it's not in the model. What do I need to change in my view to sort this correctly?
EDIT:
Robert, here's models.py. Tried your solution, and a number of variations, but I don't have a voting attribute to the model. Take a look:
#models.py
class Question(models.Model):
movie = models.ForeignKey(Movie, blank=True, null=True)
question_text = models.CharField(verbose_name = "Question", max_length = 250)
question_detail = models.CharField(verbose_name = "Details (Optional)", max_length = 5000, blank = True, null = True)
q_pub_date = models.DateTimeField(auto_now_add = True)
q_author = models.ForeignKey(User)
Any insight?
It'd be handy if you posted your model.py, but I'm going to make some guesses.
Firstly, this might help:
#views.py
def questions(request, movie_id):
p = Movie.objects.get(pk=movie_id)
k = Question.objects.filter(movie=p).order_by('-q_pub_date')
...
(don't need to use reverse, can just begin it with -)
I'm going to guess that your score could be sorted as follows:
k = Question.objects.filter(movie=p).order_by('movie__score', '-q_pub_date')
The __ (double underscore) will refer to an attribute of related model.
I've been known to live and die by this: https://docs.djangoproject.com/en/dev/topics/db/queries/#related-objects