the code is working without any issues but the problem is that after I like a post instead of the like button changing the entire for loop having the posts stops functioning. ie there is nothing displayed other than the users username. The server doesn't throw any particular error it just doesn't display the for loop. I feel its an issue with the render part but I'm not quite sure what exactly is wrong with it
below are my files
views.py
from django.shortcuts import render,get_object_or_404
from django.views.generic import ListView
from .models import Blog
from django.http import HttpResponseRedirect
class BlogsList(ListView):
model=Blog
template_name='blog/home.html'
context_object_name='blogs'
ordering=['-date_posted']
def like_post(request, blog_id):
post = get_object_or_404(Blog, id=blog_id)
is_liked=False
if post.likes.filter(id=request.user.id).exists():
post.likes.remove(request.user)
is_liked=False
else:
post.likes.add(request.user)
is_liked=True
context={
'is_liked':is_liked
}
return render(request, 'blog/home.html', context)
models.py
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
from django.urls import reverse
class Blog(models.Model):
title=models.CharField(max_length=100)
content=models.TextField()
date_posted=models.DateTimeField(default=timezone.now)
author=models.ForeignKey(User, on_delete=models.CASCADE)
likes=models.ManyToManyField(User,related_name='likes',blank=True)
def __str__(self):
return self.title
def get_absolute_url():
return reverse('blog-home')
urls.py
from django.urls import path
from . import views
urlpatterns=[
path('',views.BlogsList.as_view(),name='blog-home'),
path('<int:blog_id>/like/', views.like_post, name='like_post')
]
and home.html
{{ user.username }}
{% block content %}
{% for post in blogs %}
<article class="media content-section">
<img class="rounded-circle article-img" src="{{ post.author.profile.image.url }}">
<div class="media-body">
<div class="article-metadata">
<h2>{{ post.author }}</h2>
<small class="text-muted">{{ post.date_posted|date:"F d, Y" }}</small>
</div>
<h2>{{ post.title }}</h2>
<p class="article-content">{{ post.content }}</p>
</div>
<div>
<form action="{% url 'like_post' post.id %}">
{% csrf_token %}
{% if is_liked %}
<button type='submit' name='blog_id' value="{{ post.id }}" class="btn btn-danger">Unlike</button>
{% else %}
<button type='submit' name='blog_id' value="{{ post.id }}" class="btn btn-primary">Like</button>
{% endif %}
</form>
</div>
</article>
{% endfor %}
{% endblock %}
you can directly use the redirect shortcut instead of render because render will not going to show all the post. You can either pass all the post in like view or simply call the list view by redirecting it.
from django.shortcuts import redirect
def like_post(request, blog_id):
# rest of code
return redirect(post.get_absolute_url()) # redirect will going to call the BlogsList and your all post will be rendered
When you click like button, your code is rendering from like_post view. In that view, context has no data called blogs. at the end of like_post, you should redirect to your BlogsListView instead of returning a HttpResponse.
you can use a django shortcut function redirect to do this.
from django.shortcuts import redirect
#...
#...
#... your code
def like_post(request, blog_id):
post = get_object_or_404(Blog, id=blog_id)
if post.likes.filter(id=request.user.id).exists():
post.likes.remove(request.user)
else:
post.likes.add(request.user)
return redirect('blog-home')
Also, you need to figure out some way to get is_liked context in home itself. consider checking documentation here
Related
I have a blog set up with Django that I use to post some of my notes and personal how-tos. I have an articles model that takes data from a form rendered in the template. The application displays my articles posted dynamically in the template. My goal is to include code snippets as a <pre> tag within the form data that I post, while writing as little HTML as possible.
models.py
from django.db import models
from django.contrib.auth import get_user_model
from django.db import models
from django.urls import reverse
class Article(models.Model):
title = models.CharField(max_length=100)
body = models.TextField()
date = models.DateTimeField(auto_now_add=True)
author = models.ForeignKey(
get_user_model(),
on_delete=models.CASCADE,
)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('article_detail', args=[str(self.id)])
views.py
from django.shortcuts import render
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.views.generic import ListView, DetailView
from django.views.generic.edit import UpdateView, DeleteView, CreateView
from django.urls import reverse_lazy
from .models import Article
class ArticleListView(LoginRequiredMixin, ListView):
model = Article
template_name = 'article_list.html'
class ArticleCreateView(LoginRequiredMixin, CreateView):
model = Article
template_name = 'article_new.html'
fields = ('title', 'body',)
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
templates/article_new.html
{% extends 'base.html' %}
{% block title %}New article{% endblock title %}
{% block content %}
<h1>New article</h1>
<form action='' method='post'>
{% csrf_token %}
{{ form.as_p }}
<button class='btn btn-success ml-2' type='submit'>Save</button>
</form>
{% endblock content %}
templates/article_list.html
{% extends 'base.html' %}
{% block title %}Articles{% endblock title %}
{% block content %}
<br/>
<div class='row'>
<div class='col-8'>
{% for article in object_list %}
<div class='card' style='background: #292b2c'>
<div class='card-header' style='background: #292b2c;'>
<span class='font-weight-bold'>{{ article.title }}</span> ·
<span class='text-muted'>by {{ article.author }} | {{ article.date }}</span>
</div>
<div class='card-body' style='background: #1a1a1a;'>
<p>{{ article.body|linebreaks }}</p>
edit<a> | <a href="{% url 'article_delete' article.pk %}">Delete
</div>
<div class='card-footer' style='background: #292b2c'>
{% for comment in article.comments.all %}
<p class='font-weight-bold'>
<span class='font-weight-bold'>{{ comment.author }} ·</span>
{{ comment }}
</p>
{% endfor %}
</div>
</div>
<br />
{% endfor %}
Is there a way that I can display code snippets as a <pre> tag within the form I posted for tutorial purposes?
I tried wrapping the {{ articles.body }} in <pre> tags within the actual template but that will just turn all text into <pre>. I have successfully kept the whitespace from my original entry by using {{ articles.body|linebreaks }}
I don't necessarily want to use RichTextField() because I want to keep it simple but I will if I have to.
If you want to keep it simple and short, you could add the safe templatetag to your body. This will allow you to render HTML from your input:
https://docs.djangoproject.com/en/4.1/ref/templates/builtins/#safe
...
<div class='card-body' style='background: #1a1a1a;'>
<p>{{ article.body|safe|linebreaks }}</p>
...
</div>
...
And then, when you're writing the blog, you can wrap the code inside a <pre> tag:
Hello this is my tutorial
This is a piece of code:
<pre>my_function()</pre>
Hope you enjoyed it!
And that will be rendered.
I decided to learn Django and started with the 'Django Polls App' which I figured would be the most simple, I am gripping the idea of how it works but I am stuck. To learn a bit better, I changed the variables and names from the original docs to my own.
Example : question_text = q_text, Choice = Choices, choice_text = choice.. etc.
Now I can't figure out what's wrong with my code as I can't make the polls work. There is no error code but it simply doesn't display the number of votes or show a success sign. I was also following Traversy Media's Django Crash Course (Polls App).
My code :
views.py
from django.http import Http404, HttpResponseRedirect
from django.shortcuts import render, get_object_or_404
from django.urls import reverse
from django.template import loader
from .models import Question, Choices
def index(request):
latest_ques = Question.objects.order_by('-published')[:5]
context = {'latest_ques': latest_ques}
return render(request, 'polls/index.html', context)
def detail(request, question_id):
try:
question = Question.objects.get(pk=question_id)
except Question.DoesNotExist:
raise Http404("Question does not exist")
return render(request, 'polls/detail.html', {'question': question})
def results(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/results.html', {'question': question})
def vote(request, question_id):
question = get_object_or_404(Question, pk=question_id)
try:
selected_choice = question.choices_set.get(pk=request.POST['choices'])
except (KeyError, Choices.DoesNotExist):
return render(request, 'polls/detail.html', {
'question': question,
'error_message': "You didn't select a choice.",
})
else:
selected_choice.votes += 1
selected_choice.save()
return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))
models.py
from django.db import models
class Question(models.Model):
q_text = models.CharField(max_length=200)
published = models.DateTimeField('date published')
def __str__(self):
return self.q_text
class Choices(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
def __str__(self):
return self.choice
details.html
{% extends 'base.html' %}
{% block content %}
<a class="btn btn-secondary btn-sm mb-3" href="{% url 'polls:index' %}">Back To Polls</a>
<h1 class="text-center mb-3">{{ question.q_text }}</h1>
{% if error_message %}
<p class="alert alert-danger">
<strong>{{ error_message }}</strong>
</p>
{% endif %}
<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
{% for choices in question.choices_set.all %}
<div class="form-check">
<input type="radio"
name="choices"
class="form-check-input"
id="choices{{ forloop.counter }}"
value="{{ choices.id }}">
<label for="choices{{ forloop.counter }}">{{ choices.choice }}</label>
</div>
{% endfor %}
<input type="submit" value="Vote" class="btn btn-success btn-lg btn-block mt-4" />
</form>
{% endblock %}
results.html
{% extends 'base.html' %}
{% block content %}
<h1 class="mb-5 text-center">{{ question.q_text }}</h1>
<ul class="list-group mb-5">
{% for choices in question.choices_set.all %}
<li class="list-group-item">
{{ choices.choice }} <span class="badge badge-success float-right">{{ choices.votes }} vote{{ choices.votes | pluralize }}</span>
</li>
{% endfor %}
</ul>
<a class="btn btn-secondary" href="{% url 'polls:index' %}">Back To Polls</a>
<a class="btn btn-dark" href="{% url 'polls:detail' question.id %}">Vote Again?</a>
{% endblock %}
urls.py
from django.urls import path
from . import views
app_name = 'polls'
urlpatterns = [
path('', views.index, name='index'),
path('<int:question_id>/', views.detail, name='detail'),
path('<int:question_id>/results/', views.results, name='results'),
path('<int:question_id>/vote/', views.vote, name='vote'),
]
I've been on the internet for hours and can't figure it out. Not getting a proper answer. Thought I'd try my luck here.
I've tried to change the names of multiple variables, I've had many errors throughout but this one I can't figure out. The solution would actually be quite simple I know it but can't really put a finger on it. Thanks.
Nevermind, I found out that there were some misspelled variables. It worked after I went line by line to find the error.
I've just started my first app with Django by following a video on YouTube.
The app is a students dashboard with 8 tools and features to help the student to make note, search for help, save books, etc.
When I follow the steps I get stuck in the creation of a new note but note from the admin side but from the actual notes template that has a crispy form and a create button.
The program is supposed for writing a title and description (the content of the note) and then press the create button. When I try to click, nothing is happening.
#This is the view.py page in the dashboard app :
from django.shortcuts import render
from . forms import *
from django.contrib import messages
# Create your views here.
def home(request):
return render(request, 'dashboard/home.html')
def notes(request):
if request.method == "POST":
form = NotesForm(request.POST)
if form.is_valid():
notes = Notes(user=request.user,title=request.POST['title'],description=request.POST['description'])
notes.save()
messages.success(request,f"Notes Added from {request.user.username} Successfully")
else:
form = NotesForm()
notes = Notes.objects.filter(user=request.user)
context = {'notes':notes,'form':form}
return render(request,'dashboard/notes.html',context)
and this is the notes.html page in the dashboard app > template folder > dashboard folder :
{% extends 'dashboard/base.html' %}
<!-- Load the static files here -->
{% load static %} {% load crispy_forms_tags %}
<!-- loading the crispy files must be here so now i write anything to
create some space and lines here we go baby lets add more -->
{% block content %}
<div class="container">
<div class="row">
{% for note in notes %}
<div class="col-md-3">
<a href="#">
<div class="card">
<div class="card-header">{{note.title}}</div>
<div class="card-body">{{note.description|slice:"0:100"}}</div>
<div class="card-footer mt-auto">
<i class="fa fa-trash fa-2x"></i>
</div>
</div>
</a>
</div>
{% endfor %}
<br /><br />
</div>
</div>
<br /><br />
<div class="container">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Create Notes</legend>
</fieldset>
{% crispy form %}
<div class="form-group">
<button href="" class="btn btn-outline-info" type="submit">Create</button>
</div>
</form>
</div>
{% endblock content %}
so, this the models.py file too
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Notes(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=200)
description = models.TextField()
def __str__(self):
return self.title
class Meta:
verbose_name = "notes"
verbose_name_plural = "notes"
in case the problem is not here, please take a look on the inside this forms.py
from dataclasses import fields
from django import forms
from . models import *
class NotesForm(forms.ModelForm):
class Meta:
model = Notes
fields = ['title', 'description']
and .. urls.py
from django.urls import path
from . import views
urlpatterns = [
path('',views.home, name='home'),
path('notes',views.notes, name="notes")
]
There are many minor mistakes in the code:
It is {{form|crispy}} to display the form not {% crispy form %}.
You are also not using HttpResponseRedirect[django-doc] for redirecting, after saving form from POST data, you should always return an HttpResponse, its a good practice.
Try below code:
Notes.html
{% block content %}
{% load crispy_forms_tags %}
<div class="container">
<div class="row">
{% for note in notes %}
<div class="col-md-3">
<a href="#">
<div class="card">
<div class="card-header">{{note.title}}</div>
<div class="card-body">{{note.description|slice:"0:100"}}</div>
<div class="card-footer mt-auto">
<i class="fa fa-trash fa-2x"></i>
</div>
</div>
</a>
</div>
{% endfor %}
<br /><br />
</div>
</div>
<br /><br />
<div class="container">
<form method="POST" action="{% url 'notes' %}" novalidate>
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Create Notes</legend>
</fieldset>
{{form|crispy}}
<input type="submit" value="Create">
</form>
</div>
{% endblock content %}
views.py
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.shortcuts import render
from . forms import *
from django.contrib import messages
from django.urls import reverse
def home(request):
return render(request, 'dashboard/home.html')
def notes(request):
if request.method == "POST":
form = NotesForm(request.POST)
if form.is_valid():
title = form.cleaned_data['title']
descrip = form.cleaned_data['description']
notes = Notes(
user=request.user, title=title, description=descrip)
notes.save()
messages.success(
request, f"Notes Added from {request.user.username} Successfully")
return HttpResponseRedirect(reverse('thanks'))
else:
form = NotesForm()
notes = Notes.objects.filter(user=request.user)
context = {'notes': notes, 'form': form}
return render(request, 'dashboard/notes.html', context)
def thanks(request):
return render(request, 'dashboard/thanks.html')
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.home, name='home'),
path('notes/', views.notes, name="notes"),
path('thanks/', views.thanks, name='thanks')
]
thanks.html
<body>
<h2>The form successfully submitted</h2>
</body>
Your forms.py can be remain same as it is.
Here is my forms.py
from django import forms
class EmailForm(forms.Form):
from_ = forms.EmailField(max_length=50)
Here is my views.py
from django.shortcuts import render
from .forms import EmailForm
def index(request):
return render(request, "base.html")
def emailSender(request):
form = EmailForm()
return render(request, "base.html", {"form" : form})
And finally here is my html template
<form id="form" method="post">
{% csrf_token %}
{{ form }}
<div class="form-outline mb-4">
<label class="form-label" for="from">From:</label>
{{ form.from_ }}
</div>
Any of my {{ form }} does not work. When I check the inspect tab they both are not created so I think this isn't some css problems here.
Tried the form code in shell , seems to be working ,try the following edits:
use a clear name to the field in forms.py
from django import forms
class EmailForm(forms.Form):
email = forms.EmailField(max_length=50)
Fix the html template (don't forget to close the form, I suppose you're taking proper care of other html tags: html, head, body, ...)
<form method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit">
</form>
I am doing a project in django 1.9.9/python 3.5, for exercise reasons I have a blog app, an articles app and a comments app. Comments app has to be genericly related to blog and articles. My problem is that the templates are not showing my comments. Comments are being created and related to their post/article because I can see it in admin, so it is not a comment creation problem. They are simply not showing in my template.
My comments/models.py:
from django.db import models
class Comment(models.Model):
post = models.ForeignKey('blog.Entry',related_name='post_comments', blank=True, null=True)
article = models.ForeignKey('articles.Article', related_name='article_comments', blank=True, null=True)
body = models.TextField()
created_date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.body
My commments/views.py:
from django.utils import timezone
from django.shortcuts import render, get_object_or_404
from django.shortcuts import redirect
from .forms import CommentForm
from .models import Comment
from blog.models import Entry
from articles.models import Article
from blog.views import post_detail
from articles.views import article_detail
def article_new_comment(request, pk):
article = get_object_or_404(Article, pk=pk)
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.article = article
comment.created_date=timezone.now()
comment.save()
return redirect(article_detail, pk=article.pk)
else:
form=CommentForm()
return render(request, 'comments/add_new_comment.html', {'form': form})
def blog_new_comment(request, pk):
post = get_object_or_404(Entry, pk=pk)
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.post = post
comment.created_date = timezone.now()
comment.save()
return redirect(post_detail, pk=post.pk)
else:
form=CommentForm()
return render(request, 'comments/add_new_comment.html', {'form': form})
And here is my post_detail.html, where comments should be. I will not post article_detail.html because they are exactly the same:
{% extends 'blog/base.html' %}
{% block content %}
<div class="post">
{% if post.modified_date %}
<div class="date">
{{ post.modified_date }}
</div>
{% else %}
<div class="date">
{{ post.published_date }}
</div>
{% endif %}
<a class="btn btn-default" href="{% url 'post_edit' pk=post.pk %}"><span class="glyphicon glyphicon-pencil"> Edit Post </span></a>
<h1>{{ post.title }}</h1>
<p>{{ post.text|linebreaksbr }}</p>
<hr>
<a class="btn btn-default" href="{% url 'new_blog_comment' pk=post.pk %}"><span class="glyphicon glyphicon-pencil"> Add Comment </span></a>
{% for comment in post.comments.all %}
<div class="comment">
<div class="date">{{ comment.created_date }}</div>
<p>{{ comment.body|linebreaksbr }}</p>
</div>
{% empty %}
<p>No comments here yet</p>
{% endfor %}
</div>
{% endblock %}
Let me know if any other file would help you to help me, like blog/models, views, although I don't think the problem is there.
You've explicitly set the related name of comments on your post to post_comments. So you would have to access them like:
{% for comment in post.post_comments.all %}
This is assuming post in your template refers to an instance of the Entry model.