This is my first project with Django and I got a problem. In the backend I created news, but I have an issue displaying the news on the frontpage. Models should be fine since I can create news into the admin panel. But I can't figure out where is my mistake.
I have app 'pages'>views.py
from django.shortcuts import render, redirect, get_object_or_404
from mainnews.models import Mainnews
# Create your views here.
def home_view(request):
main = Mainnews.objects.all()
context = {
'main' : main
}
return render(request, 'index.html', context)
root>urls.py
from pages.views import home_view
urlpatterns = [
path('admin/', admin.site.urls),
path('', home_view, name = 'home'),
]
and app mainnews>views.py
from django.shortcuts import render, get_object_or_404
from .models import Mainnews
# Create your views here.
def index(request):
main = Mainnews.objects.all()
context = {
'main' : main
}
return render(request, 'index.html', context)
and the template mainnewsandevents.html that extends to index
{% block content %}
<!-- Section 2 News and Events -->
<div id="news-container">
<div class="jumbo-news">
<img id = 'jumboImgUrl' class='jumbo-img' src="{{ main.image.url }}">
<h2 id = 'jumboTitle' class='jumbo-title'>{{ main.title }}</h2>
<h4 id = 'jumboDescription' class='jumbo-parag'>{{ main.description }}</h4>
</div>
{% endblock %}
Fix it like this:
def home_view(request):
main = Mainnews.objects.first()
# or main = Mainnews.objects.last()
# other code
or if you need to show all objects on your template use something like it:
{% block content %}
<!-- Section 2 News and Events -->
<div id="news-container">
<div class="jumbo-news">
{% for article in main %}
<img id = 'jumboImgUrl' class='jumbo-img' src="{{ main.image.url }}">
<h2 id = 'jumboTitle' class='jumbo-title'>{{ main.title }}</h2>
<h4 id = 'jumboDescription' class='jumbo-parag'>{{ main.description }}</h4>
{% endfor %}
</div>
{% endblock %}
Depends on your needs.
Also you shouldn't use not obvious names for variables so you shall use main_news instead of main.
main is an array of objects right so you need a for loop to get every object
{% block content %}
<!-- Section 2 News and Events -->
<div id="news-container">
<div class="jumbo-news">
{% for obj in main %}
<img id = 'jumboImgUrl' class='jumbo-img' src={{ obj.image.url }}>
<h2 id = 'jumboTitle' class='jumbo-title'>{{ obj.title }}</h2>
<h4 id = 'jumboDescription' class='jumbo-parag'>{{ obj.description }}</h4>
{% endfor %}
</div>
{% endblock %}
Related
I'm trying to clone the Instagram web page using Django(version-3.1).
My Django project has an app called 'post'.
One of its template I have a form which is posting a comment to a post. The form post request should call the path('add_comment/',views.add_comment,name='add_comment'), but It's calling path('<slug:slug>/',views.post_details,name='post_details'), instead. And raising DoesNotExist at /post/add_comment error. I added print() statement at the beginning of both add_comment() and post_details() methods to find out which is running when the request is made. I have no idea what I have done wrong.
The project GitHub link - https://github.com/mirasel/Instagram_Clone
the post_details.html template is -
{% extends 'base.html' %}
{% load static %}
{% block title %} post {% endblock %}
{% block profilephoto %} {{ propic.url }} {% endblock %}
{% block body %}
<div>
<div>
<img src="{{post.image.url}}" alt="post" height="250px" width="250px">
</div>
<div>
<a href="{% url 'instagram:profile' post.uploader %}">
<img src="{{uploader.profile_pic.url}}" alt="{{uploader}}" style="border-radius: 50%;" height="24px" width="24px">
{{ post.uploader }}
</a><br>
<p>{{ post.date_published.date }}</p>
</div>
<div>
<p>{{ post.caption }}</p>
</div>
<div>
<form action="{% url 'post:add_comment' %}" id="comment_form" method="POST">
{% csrf_token %}
<textarea name="comment" id="comment" cols="30" rows="1" placeholder="Write a comment..."></textarea>
<input type="hidden" name="slug" id="slug" value="{{post.slug}}">
<!-- <input type="submit" style="display: none;" name="submit"> -->
</form>
<script>
$(function(){
$("#comment").keypress(function (e) {
if(e.which == 13 && !e.shiftKey) {
$(this).closest("form").submit();
e.preventDefault();
}
});
});
</script>
{% endblock %}
the views.py -
from django.shortcuts import render,redirect
from instagram.views import get_nav_propic,get_profile_details
from .models import UserPost,PostComment,PostLike
from django.http import JsonResponse
def get_post_likes(post):
likes = PostLike.objects.filter(post=post)
total_likes = len(likes)
likers = []
for l in likes:
likers.append(get_profile_details(l.liker))
return {'likers':likers,'total_likes':total_likes}
def get_post_comments(post):
comments = PostComment.objects.filter(post=post)
total_comments = len(comments)
commenter = []
comment = []
for c in comments:
commenter.append(get_profile_details(c.commenter))
comment.append(c.comment)
postcomment = zip(commenter,comment)
return {'post_comment':postcomment,'total_comments':total_comments}
def upload_post(request):
if request.method == 'POST':
image = request.FILES['post_img']
caption = request.POST['caption']
uploader = request.user
UserPost.objects.create(uploader=uploader,image=image,caption=caption)
return redirect('instagram:feed')
else:
context = {
'propic' : get_nav_propic(request.user)
}
return render(request,'post/upload_post.html',context)
def post_details(request,slug):
print('I am here in post details')
post = UserPost.objects.get(slug=slug)
context = {
'propic' : get_nav_propic(request.user),
'post' : post,
'uploader' : get_profile_details(post.uploader),
'LIKES' : get_post_likes(post),
'COMMENTS' : get_post_comments(post),
}
return render(request,'post/post_details.html',context)
def add_comment(request):
print('I am here in add comment')
if request.method == 'POST':
post_slug = request.POST.get('slug')
post = UserPost.objects.get(slug=post_slug)
user = request.user
comment = request.POST.get('comment')
PostComment.objects.create(post=post,commenter=user,comment=comment)
return redirect('post:post_details',slug=post_slug)
the urls.py -
from django.urls import path
from . import views
app_name='post'
urlpatterns = [
path('upload_post/',views.upload_post,name='upload_post'),
path('<slug:slug>/',views.post_details,name='post_details'),
path('add_comment/',views.add_comment,name='add_comment'),
]
The error - Error page
Solved
I had to make the URL path of add_comment as following-
#previous one
path('add_comment/',views.add_comment,name='add_comment'),
#modified one
path('comment/add_comment/',views.add_comment,name='add_comment'),
This is because the pattern for the slug URL and add comment URL were similar.
Because Django will process the urlpatterns sequentially, from docs:
Django runs through each URL pattern, in order, and stops at the first
one that matches the requested URL, matching against path_info.
And '/add_comment' is a valid slug <slug:slug>, so post_details will be called.
So you should keep the definition of the most generic url patterns at last:
urlpatterns = [
path('upload_post/',views.upload_post,name='upload_post'),
path('add_comment/',views.add_comment,name='add_comment'),
path('<slug:slug>/',views.post_details,name='post_details'),
]
Hopefully this will work for you.
NOTE: This question is not about creating or using a base template!
I'm creating a products app in my project, using only django and html/css, and all pages in this part has a sidebar nav menu that categorizes different product models and types. So this sidebar will be used in all other product pages.
Here is my views.py file:
from django.shortcuts import render
from .models import (
Product,
Usage,
SubUsage,
MainModel,
PumpType,
HeadFlowDataSet,
)
def products_usage_main(request):
product_queryset = Product.objects.all()
usage_queryset = Usage.objects.all()
sub_usage_queryset = SubUsage.objects.all()
main_model_queryset = MainModel.objects.all()
pump_type_queryset = PumpType.objects.all()
context = {
"product_queryset": product_queryset,
"usage_queryset": usage_queryset,
"sub_usage_queryset": sub_usage_queryset,
"main_model_queryset": main_model_queryset,
"pump_type_queryset": pump_type_queryset,
}
return render(request, "products/products_usage_main.html", context)
def sidebar_data(request):
usage_queryset = Usage.objects.all()
sub_usage_queryset = SubUsage.objects.all()
main_model_queryset = MainModel.objects.all()
pump_type_queryset = PumpType.objects.all()
context = {
"usage_queryset": usage_queryset,
"sub_usage_queryset": sub_usage_queryset,
"main_model_queryset": main_model_queryset,
"pump_type_queryset": pump_type_queryset,
}
return render(request, "products/products_sidebar.html", context)
And the sidebar template is as shown below:
<ul class="nav flex-column list-unstyled my-3 ms-3">
{% for usage_item in usage_queryset %}
<li class="nav-item p-2 ms-4">
<a href="#" class="text-decoration-none nm-text-color fw-semibold"
data-bs-toggle="collapse"
data-bs-target="#usage_{{ usage_item.usage_name_fa }}">
<i class="fa-solid fa-angle-left me-2 icon-selector"></i>
الکتروپمپهای {{ usage_item.usage_name_fa }}
</a>
<ul class="submenu collapse" id="usage_{{ usage_item.usage_name_fa }}"
data-bs-parent="#nav_accordion">
{% for sub_usage in sub_usage_queryset %}
{% if sub_usage.usage == usage_item %}
<li class="my-2 ms-4">
<a href="#" class="text-decoration-none nm-text-color fw-semibold">
{{ sub_usage }}
</a>
</li>
{% endif %}
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
And now I'm creating a proucts main page for example, which should implement this sidebar.
I included this sidebar template in my products page template as shown below:
<section>
<div class="container-fluid">
<div class="row">
<div class="col-6 col-lg-4 px-0">
{% include "products/products_sidebar.html" %}
</div>
<div class="col-6 col-lg-8">
content
</div>
</div>
</div>
</section>
Now, I know that without a URL, the view sidebar_data() won't be called, and for now my urls are as shown below:
urlpatterns = [
path("application/", products_usage_main, name="products_usage_main"),
path("application/<str:pk>", product_detail, name="product_detail"),
]
And as expected, context data sent in the sidebar_data() view, will not be sent and so my sidebar will not be populated with the data.
How am I supposed to acheive this?
There is one way, in which I have to send the queryset data sent to sidebar in all the different product pages, but I think there should be a more sufficient way.
Your help is appreciated in advance.
To achieve this you need to pass the same context in your all views. A simple demonstration of your views would be as follows:
views.py
# Since these context will be common to all views it would be written outside any view function
def get_common_queryset():
usage_queryset = Usage.objects.all()
sub_usage_queryset = SubUsage.objects.all()
main_model_queryset = MainModel.objects.all()
pump_type_queryset = PumpType.objects.all()
queryset_dictionary = {
"usage_queryset": usage_queryset,
"sub_usage_queryset": sub_usage_queryset,
"main_model_queryset": main_model_queryset,
"pump_type_queryset": pump_type_queryset,
}
return queryset_dictionary
# and in every other views
def products_usage_main(request):
...
context_of_view = {
...
}
common_context = get_common_queryset()
context = {**context_of_view, **common_context} # dictionary expansion
return render(request, "template_name.html", context)
Following is my urls.py file:
from django.urls import path, re_path, include
from . import views
app_name = 'blog'
urlpatterns = [
path('', views.post_list, name='list'),
path('<slug>/', views.post_detail, name='detail'),
]
My views.py file:
from django.shortcuts import render
from .models import Post
# Create your views here.
def post_list(request):
posts = Post.objects.all().order_by('date')
return render(request, 'blog/post_list.html', {'posts': posts})
def post_detail(request, slug):
post_det = Post.objects.get(slug=slug)
return render(request, 'blog/post_detail.html', {'singlepost': post_det})
And my post_detail.html page:
{% extends 'base.html' %}
{% block content %}
<div class="container-fluid">
<div class="row">
{% for post in posts %}
<div class="post col-md-10 shadow mx-auto">
<!-- post-thumbnail -->
<div class="post-thumbnail">
<img src="{{singlepost.thumb.url}}">
</div>
<!-- /post-thumbnail -->
<h2 class="post-title bg-dark text-light pad1 text-center">{{ singlepost.title }}</h2>
<p class="post-content">{{ singlepost.body }}</p>
<p class="post-info grey border pad1">{{ singlepost.date }}</p>
</div>
{% endfor %}
</div>
</div>
{% endblock content %}
Screenshot from the error page:
Django - Page Not Found Error
What appears to be the problem here? Keep in mind that I'm new to django, however, this is the first time I come across an url such as the one noted in the error report.
I have made few changes,
In urls.py,
path('detail/<slug:slug>/', views.#restofyoururl ),
You have not added your homepage html, so check if you have added the url correctly. In your homepage html
<a href={% url 'blog:detail' post.slug %}> {{post.title}}#add as per your model </a>
Note : You can add class based view for your detail page.
I have a ModelForm that posts news items to a database, and it uses a javascript textarea to allow the authorized poster to insert certain pieces of HTML to style text, like bold and italics. However, since I have the template output using the "safe" filter, it outputs all the HTML the form widget tries to pass on. This includes a bothersome <br> tag that never goes away, making it so you can submit without form validation reading the field as empty and stopping you. How can I make that I can not only filter the <br> tag, but completely remove it from the data? Here is relevant code:
Models.py:
from django.db import models
from django.forms import ModelForm, forms
from django.contrib.auth.models import User
# Create your models here.
class NewsItem(models.Model):
user = models.ForeignKey(User)
date = models.DateField(auto_now=True)
news = models.TextField(max_length=100000, blank=False, help_text='HELP TEXT')
def __unicode__(self):
return u'%s %s %s' % (self.user, self.date, self.news)
class NewsForm(ModelForm):
class Meta:
model = NewsItem
exclude=('user','date',)
Views.py:
from news.models import NewsForm, NewsItem
from django.shortcuts import render
from django.http import HttpResponseRedirect, HttpResponse
def news(request):
if request.method == 'POST':
item = NewsItem(user=request.user)
form = NewsForm(request.POST, instance=item)
if form.is_valid():
form.save()
return HttpResponseRedirect('/news/')
else:
form = NewsForm()
news_list = NewsItem.objects.all()
return render(request, 'news_list.html', {'news_list': news_list, 'form': form})
news_list.html:
{% extends "base.html" %}
{% block title %}News in the Corps{% endblock %}
{% block content %}
<h2 id="page_h">News in the Corps</h2>
{% if user.is_authenticated %}
<h3>Post News</h3>
<script src="{{ STATIC_URL }}nicEdit.js" type="text/javascript"></script>
<script type="text/javascript">bkLib.onDomLoaded(nicEditors.allTextAreas);</script>
<div id="news_poster">
<form id="news_poster" action="/news/" method="POST">{% csrf_token %}
{{ form }}
<input type="submit" value="Submit" />
</form>
</div>
{% endif %}
<ul id="events_list">
{% if news_list %}
<div id="news_list">
{% for news in news_list %}
{% if news.id == 1 %}
<hr />
{% endif %}
<div id="{{ news.id }}" class="news_item">
<p class="poster">Posted By: {{ news.user }} | Posted On: {{ news.date }} | Link</p>
<div id="news_item">
{{ news.news|safe }}
</div>
</div>
<hr />
{% endfor %}
</div>
{% endif %}
</ul>
{% endblock %}
You can try the removetags template filter:
{{ news.news|removetags:"br"|safe }}
I can't help but thinking that the "removetags" as Timmy O'Mahony suggested might work if it was structured like this:
{{ news.news|safe|removetags:"br"}}
Give it a shot and see if it works. I would reply, but my karma's not height enough to directly reply to an answer with a suggestion.
I was changing some views earlier related to some geolocation (that failed) and upon restoring the previous views, I'm receiving this error:
TemplateSyntaxError at /report/all/
Caught NoReverseMatch while rendering: Reverse for 'profiles_profile_detail' with arguments '('',)' and keyword arguments '{}' not found.
What's odd is that the views I altered and restored had nothing to do with this view or template. The urls.py file was not touched at all. All other pages in the application are displaying normally. I can't figure out what the problem might be.
Views:
from django.http import HttpResponse, HttpResponseRedirect, Http404
from django.shortcuts import render_to_response, get_object_or_404, redirect
from django.template import RequestContext
from django.core.urlresolvers import reverse
from myapp.report.models import Story, UserProfile
from myapp.report.forms import ProfileForm, StoryForm
from django.contrib.auth.decorators import login_required
from django.contrib.gis.utils import GeoIP
def all_stories(request):
if not request.user.is_authenticated():
return redirect("django.contrib.auth.views.login")
all_stories = Story.objects.all().order_by("-date")
return render_to_response("report/storyline.html",
{'stories': all_stories},
context_instance=RequestContext(request))
def story_detail(request, story_id):
story = get_object_or_404(Story, id=story_id)
return render_to_response('report/detail.html',
{'story': story},
context_instance=RequestContext(request))
#login_required
def submit_story(request):
if request.method =="POST":
story_form = StoryForm(request.POST, request.FILES)
if story_form.is_valid():
new_story = story_form.save(commit=False)
new_story.author = request.user
new_story.save()
return HttpResponseRedirect("/report/all/")
else: # GET request
story_form = StoryForm()
return render_to_response("report/report.html", {'form': story_form}, context_instance=RequestContext(request))
Forms (changed but restored; appear to be working):
from django import forms
from stentorian.report.models import UserProfile, Story
from django.contrib.gis.utils import GeoIP
class ProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
class StoryForm(forms.ModelForm):
class Meta:
model = Story
exclude = ('author',)
Template:
{% extends 'base.html' %}
{% block page_title %}Stentorian{% endblock %}
{% block headline %}Stentorian Storyline{% endblock %}
{% block content %}
<div class="row">
<div class="span12">
<h2>Welcome {{ user.username }}</h2>
<div class="accordion" id="story_accordion">
{% for story in stories %}
<div class="accordion-group">
<div class="accordion-heading">
<a class="accordion-toggle story-header" data-toggle="collapse" data-parent="#story_accordion" href="#story_{{ story.id }}">
{{ story.title }} - {{ story.author.username }} - {{ story.date }}
</a>
</div>
<div id="story_{{ story.id }}" class="accordion-body collapse{% if forloop.counter0 == 0 %} in{% endif %}">
<div class="accordion-inner">
<!-- <h2>{{story.title}}</h2>-->
<span>{{story.author}} </span><br>
<span>{{story.topic}}</span><br>
<span>{{story.zip_code}}</span><br>
<span>{{story.date}}</span><br>
<p>{{story.copy}}</p>
</div>
</div>
</div>
<br>
{% endfor %}
</div>
</div>
</div>
{% endblock content %}
The error is coming up on the line:
{% for story in stories %}
If anyone can provide an idea of why this is happening, it would be most appreciated. Again, the url wasn't changed, which seems to be the chief reason for this error.
Seems like u r not getting user.username
Try with this.
<h2>Welcome {{ request.user.username }}</h2>