Django uploaded files not displaying in template page - django

I am trying to display the top 5 recently posted files but doesnt seem to show up.
When i get all the objects by using Model.objects.all(), it gives me all the objects from Db but when i am trying to get the top 5, it does not display.
Kindly help and suggest me. Thanks
my views.py is
def about_experiment(request, ex_link_name):
researcher = None
study = None
posts = None
exp = get_object_or_404(Experiment,link_name = ex_link_name)
high_scores = ScoreItem.objects.filter(experiment=exp,active=True)
context = {
'request': request,
'exp':exp,
'high_scores': high_scores,
'awards':AwardItem.objects.filter(experiment=exp,visible=True),
'posts':Help.objects.filter().order_by('-date')[0],
'documents':Help.objects.filter().order_by('-document')[:5]
}
if exp.about_file:
context['about_file'] = settings.EXPERIMENT_DIRS+exp.about_file.get_include_path()
if request.method == 'POST':
form = AboutHelp(request.POST, request.FILES)
if form.is_valid():
obj = form.save(commit = False)
obj.save()
return HttpResponseRedirect('/about/%s/' %ex_link_name)
#return redirect(reverse('lazer.views.about_experiment', kwargs={ 'ex_link_name':obj.link_name }))
else:
form = AboutHelp()
return render(request, 'about_experiment.html', context)
destination template page
<div class="tab-pane" id="irb">
<h4> List of file(s) uploaded:</h4>
<!--File upload-->
{% if documents %}
<ul>
<li> {{ documents.document }} </li>
</ul>
{% else %}
<p>No such documents available.</p>
{% endif %}
<!--File upload ends-->

documents is a queryset and you are picking top 5. You need to do this like this.
<div class="tab-pane" id="irb">
<h4> List of file(s) uploaded:</h4>
<!--File upload-->
{% for doc in documents %}
<ul>
<li> {{ doc.document }} </li>
</ul>
{% empty %}
<p>No such documents available.</p>
{% endfor %}
<!--File upload ends-->

Related

How to paginate multiple queries in a single function-based-view or class-based-view in django?

I have a search function that queries multiple models. I have the expected results displayed in a html template and so far all is fine. The problem is that I want to paginate the results using django's built in Pagination class. Pagination with multiple models is where I'm now stuck. I have other class based views working well paginating single models.
def search_results(request):
if request.method == 'POST':
searched = request.POST['searched']
books = Book.objects.filter(description__icontains=searched,
title__icontains=searched).order_by('-id')
sermons = Sermon.objects.filter(description__icontains=searched,
title__icontains=searched).order_by('-id')
other_sermons = SermonsByOtherFathers.objects.filter(description__icontains=searched,
title__icontains=searched).order_by('id')
other_books = BooksByOtherFathers.objects.filter(description__icontains=searched,
title__icontains=searched).order_by('-id')
context = {
'searched': searched,
'sermons': sermons,
'other_sermons': other_sermons,
'books': books,
'other_books': other_books,
}
if searched == "":
return HttpResponse('Please type something in the search input.')
return render(request, "search_results.html", context)
This is a simplified version of my html template.
{% for book in books %}
<tr>
<td>
{{ book.title }}
<p> {{book.author}} </p>
<p> {{ book.category }} </p>
<p> {{ book.description }} </p>
</td>
</tr>
{% endfor %}
<-- ...and the same loops goes for the rest of the other querysets. -->
{% for book in other_books %}
<-- code here -->
{% endfor %}
{% for sermon in sermons %}
<-- code here -->
{% endfor %}
{% for sermon in other_sermons %}
<-- code here -->
{% endfor %}
Any help with the django multiple-model pagination part will be appreciated.

Trouble paginating results from a 3rd party API in Django

I'm making a portfolio project where I'm using the Google Books API to do a books search, and the Django Paginator class to paginate the results. I've been able to get search results using a CBV FormView and a GET request, but I can't seem to figure out how to get pagination working for the API response.
The solution I can think of is to append &page=1 to the url of the first search, then pull that param on every GET request and use that to paginate. The problem is, I can't figure out how to append that param on the first search, and I don't know how I'd increment that param value when clicking the pagination buttons.
Here's what I've got now:
Form:
class SearchForm(forms.Form):
search = forms.CharField(label='Search:', max_length=150)
View:
class HomeView(FormView):
template_name = "home.html"
form_class = SearchForm
pageIndex = 0
def get(self, request, *args, **kwargs):
# get submitted results in view and display them on results page. This will be swapped out for an AJAX call eventually
if "search" in request.GET:
# getting search from URL params
search = request.GET["search"]
kwargs["search"] = search
context = super().get_context_data(**kwargs)
# Rest API request
response = requests.get(
f'https://www.googleapis.com/books/v1/volumes?q={search}&startIndex={self.pageIndex}&key={env("BOOKS_API_KEY")}'
)
response = response.json()
items = response.get("items")
# pagination...needs work
paginator = Paginator(items, 2)
page_obj = paginator.get_page(1)
context["results"] = page_obj
return self.render_to_response(context)
else:
return self.render_to_response(self.get_context_data())
Template:
{% extends "base.html" %}
{% block content %}
<form action="/">
{{ form }}
<input type="submit" value="Submit">
</form>
<h1>Books</h1>
<ul>
{% for result in results %}
<li>{{ result.volumeInfo.title }} : {{result.volumeInfo.authors.0}}</li>
{% empty %}
<li>Search to see results</li>
{% endfor %}
</ul>
{% if results %}
<div class="pagination">
<span class="step-links">
{% if results.has_previous %}
« first
previous
{% endif %}
<span class="current">
Page {{ results.number }} of {{ results.paginator.num_pages }}
</span>
{% if results.has_next %}
next
last »
{% endif %}
</span>
</div>
{% endif %}
{% endblock content %}
I also looked at Django REST Framework for this, but the Google Books API response doesn't contain any info on next page, previous page, etc. I've done this kind of pagination in React and it's not difficult, I'm just having trouble adjusting my mental model for how to do this to Django. If anyone could offer some advice on how to make this work, I'd be very grateful.

How to customise ModelAdmin UI

How does one go about editing the template(s) shown when using wagtail.contrib.modeladmin?
Assuming
class EventsAdmin(ModelAdmin):
menu_label = 'Events'
list_display = ('title',)
Say I want to make the titles clickable, how would I go about doing so?
I figured I could check the templates in wagtail/contrib/modeladmin/templates and add something like <a href="{{ url }}" /> alas the furthest I got to finding that title section was in wagtail/contrib/modeladmin/templates/modeladmin/includes/result_row_value.html where it outputs the title section through the {{ item }} tag
{% load i18n modeladmin_tags %}
{{ item }}{{ url }}{% if add_action_buttons %}
{% if action_buttons %}
<ul class="actions">
{% for button in action_buttons %}
<li>{% include 'modeladmin/includes/button.html' %}</li>
{% endfor %}
</ul>
{% endif %}
{{ closing_tag }}
{% endif %}
#modeladmin_tags.py
#register.inclusion_tag(
"modeladmin/includes/result_row_value.html", takes_context=True)
def result_row_value_display(context, index):
add_action_buttons = False
item = context['item']
closing_tag = mark_safe(item[-5:])
request = context['request']
model_admin = context['view'].model_admin
field_name = model_admin.get_list_display(request)[index]
if field_name == model_admin.get_list_display_add_buttons(request):
add_action_buttons = True
item = mark_safe(item[0:-5])
context.update({
'item': item,
'add_action_buttons': add_action_buttons,
'closing_tag': closing_tag,
})
return context
Going further I don't really understand how the <td> with the title are put in there nor what I can do to make it clickable or customise that template.
A screenshot to illustrate the UI section

Django: How to add comments under post

I have trouble adding comments under my posts on the website I'm creating using Django.
This is my story.html file, which is supposed to show the story title, the story itself, all the comments of the story and give users the ability to add a new comment. Although the form is shown, it is not usable. Even though I have added comments to the stories manually through admin, none of them is shown.
{% extends "pinkrubies/base.html" %}
{% block content %}
<div class="post-preview">
<h2 class="post-title"> {{ story.title }}</h2>
<p class="post-subtitle">
{{ story.story }}
</p>
</div>
<div class="post-preview">
{% for com in latest_comments %}
<div class="post-preview">
<p class="post-subtitle"> {{ comment.com }} </p>
</div>
{% endfor %}
</div>
{% if user_id %}
<div class="post-preview">
<form action="{% url 'pinkrubies:story' user.id story.id %}" method="post">
{% csrf_token %}
<div class="form-group">
<p class="post-title">
Comments
</p>
<textarea id="text" name="text"class="form-control" placeholder="Comment" rows="4">{{ comment.com }}
</textarea>
</div>
<button type="submit" class="btn btn-primary"> Submit </button>
</form>
</div>
{% else %}
<p class="post-meta">You must have an account to comment. Log in or Register</p>
{% endif %}
{% endblock %}
views.py
def story_view(request, user_id, story_id):
latest_comments = Comment.objects.order_by('-date')
if story_id is not None:
story = get_object_or_404(Story, pk=story_id)
else:
story = Story()
story.user_id = user_id
if request.method == 'POST':
story.title = request.post.get('title')
story.story = request.post.get('story')
story.date = timezone.now()
story.save()
return HttpResponseRedirect(reverse('pinkrubies:story', args=(user_id,)))
else:
context = {
'user_id': user_id,
'story_id': story_id,
'title': story.title,
'story': story,
'comments': story.comments,
'latest_comments': latest_comments
}
return render(request, 'pinkrubies/story.html', context)
def comment_view(request, comment, user_id):
latest_comments = Comment.objects.order_by('-date')
if request.method == 'POST':
comment.com = request.POST['com']
comment.date = timezone.now()
comment.save()
return HttpResponseRedirect(reverse('pinkrubies:story', args=(user_id,)))
else:
context = {'latest_comments': latest_comments}
return render(request, 'pinkrubies/story.html', context)
I am aware I have added the "latest_comments" in both views, I did that to see if any of it works and it doesn't. I'm not even sure that the comment_view is needed.
Also, when I try to submit a comment, this error is thrown:
AttributeError: 'WSGIRequest' object has no attribute 'post'
in story_view story.title = request.post.get('title')
Any help is welcome!
Thank you !!!
First of all, if you want to get something from POST, you should use request.POST.get('title'); although I would rather use a Form and let it handle the request.
At a first glance, this:
{% for com in latest_comments %}
<div class="post-preview">
<p class="post-subtitle"> {{ comment.com }} </p>
</div>
{% endfor %}
Sould be
{% for comment in latest_comments %}
<div class="post-preview">
<p class="post-subtitle"> {{ comment.com }} </p>
</div>
{% endfor %}
In your code, you're using com to iterate through latest_comments, yet you try to use comment to access com attribute (not sure how your Comment model looks like though)
It's accessed via request.POST. WSGIRequest object does not have a post field it has POST field.
Also, you are not sending the fields you are attempting to read from request.
...
story.title = request.POST.get('title')
story.story = request.POST.get('story')
...
only field you are sending is called text and it should be accessed like this
text = request.POST.get('text')
also template has more errors please check your code once again.

Using redirect sends me to /tag/?search=input instead of /tag/input (Django URL argument from form)

I have a page where there is a path /tag/name_of_tag and you can see all posts tagged with that tag.
Inside the page, you can also select another tag in a form and go to that tag.
The problem is that instead of going to /tag/searched_tag, it goes to /tag/?search=searched_tag
How can I change it doesn't leave the ?search= part?
urls.py:
url(r'tag/(?P<input_tag>\w+)$', views.tag_view, name='tag'),
views.py:
def tag_view(request, input_tag):
form = TagSearchForm()
if request.method == 'GET':
form = TagSearchForm(request.GET)
if form.is_valid():
input = form.cleaned_data['search']
print(input)
return redirect('fortykwords:tag_view', input)
else:
form = SearchForm()
latest_post_list = Post.objects.filter(tags=input_tag, status__exact="published")
paginator = Paginator(latest_post_list, 3)
page = request.GET.get('page')
posts = paginator.get_page(page)
context = {'latest_post_list': latest_post_list, 'page_tag': input_tag, 'form': form}
return render(request, 'fortykwords/tag.html', context)
forms.py:
class TagSearchForm(forms.Form):
search = tagulous.forms.SingleTagField(
tag_options=tagulous.models.TagOptions(
autocomplete_view='fortykwords:post_tags_autocomplete'
),
label='Tags',
required=True,
help_text=_('Filter by lead tags. You can organize leads by any tag you want.'),
)
tag.html:
{% extends "base_generic.html" %}
{% block content %}
<form action="." method="get">
{{ form }}
<input type="submit" value="Submit" />
</form>
<h3>Posts with the tag {{ page_tag }}</h3>
{% if latest_post_list %}
<ul>
{% for post in latest_post_list %}
<li> {{ post.author }} {{ post.pub_date }}
<br>
{{ post.title }}</li>
{% for tag in post.tags.all %}
{{ tag.name }}
{% endfor %}
{% endfor %}
</ul>
{% else %}
<p>No posts are available.</p>
{% endif %}
{% endblock %}
You need to provide the argument input to redirect method as input_tag=input.
Example:
return redirect('fortykwords:tag_view', input_tag=input)
It's showing as /tag/?search=searched_tag because your form is submitting by GET but never getting to the redirect. It seems is_valid() is returning False.
I've tested a very similar version of your code and don't think it's a bug in tagulous, but would still be interested to know what had gone wrong (I wrote tagulous). Spotted a couple of places you can streamline your code a bit, so try::
def tag_view(request, input_tag):
# Can't see any POSTs in your example, so you can pass the form GET here
# Might also be nice to pass the original tag in so it shows in the form
form = TagSearchForm(request.GET, initial={'search': input_tag})
# The form already has the GET, so you can go straight into the is_valid
if form.is_valid():
input = form.cleaned_data['search']
print('Valid: ', input)
return redirect('fortykwords:tag_view', input)
else:
print('Invalid: ', form.errors, form.non_field_errors)
# You can remove the else for if not GET, which would never be reached
# on to pagination as before
(although fwiw I'd recommend ipdb instead of print)