I cannot seem to find a way to iterate through the files uploaded by the formset, although the files are uploaded as the code indicates.
When I load the page it shows 1-3 "img src=(unkown)" tags. It shows 3 when I upload 2 images and 1 when I upload 1 image.
Template view-post:
{% block body %}
<div class="container">
<div class="col-md-8">
<p>
<h1>{{ post.title }}</h1>
<h4>{{ post.body }}</h4>
<p>
Posted by {{ post.user }} on {{ post.created_date }}
{% if not post.created_date == post.updated_date %}
and updated on {{ post.updated_date }}
{% endif %}
</p>
</p>
{% for img in images %}
<img src="{{ img.url }}" width=360>
{{ img.url }}
<br>
{% endfor %}
</div>
<div class="col-4-md">
{% if post.cover_image %}
<img src="{{ post.cover_image.url }}" width=240>
{% endif %}
</div>
</div>
{% endblock %}
Here I use filter, not get, so it should give me a list of the images connected via foreignkey to the right post. The post here is displayed as it should be, along with the internal cover image and text in the post.
View view-post:
class ViewPost(TemplateView):
template_name = 'posts/view_post.html'
context_object_name = 'view_post'
def get(self, request, pk):
post = Post.objects.get(pk=pk)
images = Images.objects.filter(post=post)
args = {'post': post, 'images': images}
return render(request, self.template_name, args)
Template make-post:
{% block body %}
<div class="container">
<div class="col-md-8">
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
{{ form.errors }}
{% csrf_token %}
{{ formset.management_form }}
{% for form in formset %}
{{ form }}
{% endfor %}
<button type="submit">Submit</button>
</form>
</div>
</div>
{% endblock %}
View make-post:
class MakePost(DetailView):
template_name = 'posts/make_post.html'
ImageFormSet = modelformset_factory(Images, form=ImageForm, extra=3)
def get(self, request):
form = PostForm()
formset = self.ImageFormSet(queryset=Images.objects.none())
args = {'form': form, 'formset': formset}
return render(request, self.template_name, args)
def post(self, request):
form = PostForm(request.POST, request.FILES)
formset = self.ImageFormSet(request.POST, request.FILES,
queryset=Images.objects.none())
if form.is_valid() and formset.is_valid():
post = form.save(commit=False)
post.user = request.user
post.cover_image = form.cleaned_data['cover_image']
post.title = form.cleaned_data['title']
post.body = form.cleaned_data['body']
post.save()
for imgform in formset:
image = imgform.cleaned_data.get('image')
photo = Images(post=post, post_image=image)
photo.save()
return redirect('home_space:home')
else:
return redirect('home_space:home')
Function to name files and image Model:
def get_image_filename(instance, filename):
title = instance.post.title
slug = slugify(title)
return "post_images/%s-%s" % (slug, filename)
class Images(models.Model):
post = models.ForeignKey(Post, default=None, on_delete=models.CASCADE)
post_image = models.ImageField(upload_to=get_image_filename,
verbose_name='Image')
In your template, you are accessing url of Images model instance. But, the url property is in ImageField class instance. Use img.post_image.url.
Example:
{% for img in images %}
<img src="{{ img.post_image.url }}" width=360>
{{ img.post_image.url }}
<br>
{% endfor %}
Related
Nothing i do seems to work out for me. I tired different models and forms but ultimately i get weird errors so all i can provide is the default code.
forms.py
from django import forms
class CommentForm(forms.Form):
author = forms.CharField(
max_length=60,
widget=forms.TextInput(attrs={
"class": "form-control",
"placeholder": "Your Name"
})
)
body = forms.CharField(widget=forms.Textarea(
attrs={
"class": "form-control",
"placeholder": "Leave a comment!"
})
)
views.py
def blogdetail(request, pk):
post = Post.objects.get(pk=pk)
comments = Comment.objects.filter(post=post)
form = CommentForm()
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
comment = Comment(
author=form.cleaned_data["author"],
body=form.cleaned_data["body"],
post=post,
)
comment.save()
context = {"post": post, "comments": comments, "form": form}
return render(request, "blogdetail.html", context)
blogdetail.html
{% extends "base.html" %}
{% block page_content %}
<div class="col-md-8 offset-md-2">
<h1>{{ post.title }}</h1>
<small>
{{ post.created_on.date }} |
Categories:
{% for category in post.categories.all %}
<a href="{% url 'blogcategory' category.name %}">
{{ category.name }}
</a>
{% endfor %}
</small>
<p>{{ post.body | linebreaks }}</p>
<h3>Leave a comment:</h3>
<form action="/blog/{{ post.pk }}/" method="post">
{% csrf_token %}
<div class="form-group">
{{ form.author }}
</div>
<div class="form-group">
{{ form.body }}
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<h3>Comments:</h3>
{% for comment in comments %}
<p>
On {{comment.created_on.date }}
<b>{{ comment.author }}</b> wrote:
</p>
<p>{{ comment.body }}</p>
<hr>
{% endfor %}
</div>
{% endblock %}
i want to relace author with the username of the user who wrote that comment. How so? what do i need to change to make this happen?
I'm making a Post and Comment model by taking reference from internet. i created and Post and Comment model and it looks ok in django admin panel. i can add post and also a comment to any particular post. but getting trouble when I'm trying to display the comment under the post in templates(under post detail views). PLEASE HELP
models.py
class Post(models.Model):
author = models.ForeignKey(User,on_delete=models.CASCADE)
title = models.CharField(max_length=100)
content = RichTextField()
tags = models.CharField(max_length=50,blank=True,null=True)
date_posted = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post-detail',kwargs={'pk':self.pk})
class Comment(models.Model):
post = models.ForeignKey(Post,on_delete=models.CASCADE)
author = models.ForeignKey(User,max_length=50,on_delete=models.CASCADE)
text = models.TextField()
create_date = models.DateTimeField(default=timezone.now)
def get_absolute_url(self):
return reverse('discuss')
views.py
class PostDetailView(DetailView):
model = Post
def add_comment_to_post(request,pk):
return get_object_or_404(Post,pk=pk)
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.post= post
comment.save()
return redirect('post-detail',pk=post.pk)
else:
form = CommentForm()
return render(request, 'discuss/comment_form.html',{'form':form})
def comment_remove(request,pk):
comment = get_object_or_404(Comment,pk=pk)
post_pk = comment.post.pk
comment.delete()
return redirect('post-detail', pk=post_pk)
post_detail.html
{% extends 'index.html' %}
{% block content %}
<article class="media content-section">
<div class="medaia-body">
<img class="rounded-circle article-img" src="{{ object.author.profile.image.url }}" alt="image not found">
<div class="article-metedata">
<a class="mr-2" href="{% url 'user-posts' object.author.username %}">{{object.author}}</a>
<small class="text-muted">{{ object.date_posted|date:"F d, Y"}}</small>
</div>
<h2 class="article-title">{{ object.title }}</h2>
<img class="query-img" src="{{ object.image.url }}" alt="image not found">
<p class="article-content">{{ object.content|safe }}</p>
</div>
</article>
{% if object.author == user %}
<div class="post-update-delete">
<button class="btn btn-outline-primary">Edit Post</button>
<button class="btn btn-outline-primary">Delete Post</button>
</div>
{% endif %}
<hr>
<a class="btn btn-primary btn-comment" href="{% url 'add_comment_to_post' pk=post.pk %}">Add Comment</a>
<!-- ############################### ABOVE CODE IS WORKING ############################# -->
<!-- ########################## GETTING PROBLEM IN BELLOW CODE ######################### -->
{% for comment in object.comments.all %}
{% if user.is_authenticated %}
{{ comment.create_date }}
{{ comment.text|safe|linebreaks }}
{{ comment.author }}
{% endif %}
{% empty %}
<p>No Comment</p>
{% endfor %}
{% endblock %}
in post_deatil.html i also tried {% for comment in post.comments.all %} but it is also not working
Since you did not specify a related_name=… parameter [Django-doc], the related_name is by default comment_set, so you iterate over the comments with:
{% for comment in object.comment_set.all %}
…
{% endfor %}
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.
I have added a user liking system, where a user can like posts. I have added this successfully, however can't seem to display the usernames of the people who liked the post. This is my current implementation.
models.py
class Post(models.Model):
likes = models.ManyToManyField(User, related_name='likes')
#property
def total_likes(self):
return self.likes.count()
views.py
def likepost(request, pk):
if request.method == 'POST':
user = request.user
post = get_object_or_404(Post, pk=pk)
if post.likes.filter(id=user.id).exists():
post.is_liked = True
post.likes.remove(user)
post.save()
else:
post.is_liked = False
post.likes.add(user)
post.save()
return redirect('home')
home.html
{% for post in posts.all %}
<form id="like__post" method="POST" action="{% url 'likepost' post.id %}">
{% csrf_token%}
<input type="hidden">
</form>
<div style="position: absolute; bottom:80px; left: 85px;">
{% if post.is_liked == True %}
<img src="{% static 'heartred.png' %}" width="35px" height="35px">
{% else %}
<img src="{% static 'heart.png' %}" width="33px" height="33px">
{% endif %}
{% endfor %}
<ul> {{ post.likes }} </ul>
So far. In my template i get this: auth.User.None
likes is a many to many field, you need to iterate over it.
<ul>
{% for like in post.likes.all %}
<li>{{ like.username }}</li>
{% endfor %}
</ul>
I have been trying to implement a way to post a project post where the user can upload multiple images. The multiple image upload works but posting the post itself does not work.
I am not sure what to do with the project_form.
It is not valid even tho the fields have correct values.
My code is:
views.py
class CreateProjectsView(View):
def get(self, request):
p_photos = P_Images.objects.all()
#project_form = ProjectsForm(initial=self.initial)
project_form = ProjectsForm
context = {
'p_photos': p_photos,
'project_form': project_form,
}
return render(self.request, 'projects/forms.html', context)
def post(self, request):
project_form = ProjectsForm(request.POST or None, request.FILES or None)
p_formset = P_ImageForm(request.POST, request.FILES)
# Checks if the project_form is valid before save
if project_form.is_valid():
instance = project_form.save(commit=False)
instance.user = request.user
instance.save()
# Checks if multiple image upload is valid before save
if p_formset.is_valid():
#if project_form.is_valid() and p_formset.is_valid():
#instance = project_form.save(commit=False)
#instance.user = request.user
#instance.save()
images = p_formset.save(commit=False)
images.save()
data = {
'is_valid': True,
'name': images.p_file.name,
'url': images.p_file.url
}
else:
data = {
'is_valid': False,
}
return JsonResponse(data)
forms.html
<form action="{% url 'create_post:retrieve_projects' %}" method="POST" enctype="multipart/form-data">
{% csrf_token %}
{% for hidden in project_form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in project_form %}
{{ field.errors }}
{{ field }} <br />
{% endfor %}
<input type="submit" value="OK">
</form>
If the form is not valid, you should provide a way for the user to correct their errors and resubmit the form. Perhaps something like this:
if project_form.is_valid():
instance = project_form.save(commit=False)
instance.user = request.user
instance.save()
else:
return render(request, 'project_form.html', {'form': project_form})
So I actually found a fix for this.
The issue is in the forms.html
I changed the "create_post:retrieve_projects" to "create_post:create_projects" in my form section.
forms.html
<form action="{% url 'create_post:create_projects' %}" method="POST" enctype="multipart/form-data">
{% csrf_token %}
{% for hidden in project_form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in project_form %}
{{ field.errors }}
{{ field }} <br />
{% endfor %}
<input type="submit" value="OK">
</form>
In some of my blog posts using django and markdown2, I am trying to include a form as follows:
views.py:
def post_detail(request, slug=None):
instance = get_object_or_404(Post, slug=slug)
if not instance.published:
raise Http404
return render(request, "posts/post_detail.html", {'instance': instance})
My template post_detail.html contains a {{ instance.get_markdown }} variable:
{% extends "base.html" %}
{% block body_content %}
<div>
{{ instance.get_markdown }}
</div>
{% endblock body_content %}
base.html:
<html>
<body>
{% block body_content %}
{% endblock body_content %}
</body>
</html>
models.py:
import markdown2
class Post(models.Model):
...
text = models.TextField(verbose_name=_("Text"))
...
def get_markdown(self):
return mark_safe(markdown2.markdown(self.text))
Example for a saved text in Post:
### Example
<form method = "POST">
{% csrf_token %}
First name:<input type="text" name="firstname">
<input type="submit" value="Submit">
</form>
This way, the page simply shows the string "{% csrf_token %}" within the form. How can I render the post with csrf protection?
My temporary solution is:
post_detail.html:
{% extends "base.html" %}
{% block body_content %}
<div>
{{ instance.get_markdown_text }}
</div>
{% if instance.form %}
<div>
<form method = "POST">{% csrf_token %}
{{ instance.get_markdown_form }}
</form>
</div>
{% endif %}
{% endblock body_content %}
models.py:
import markdown2
class Post(models.Model):
...
text = models.TextField(verbose_name=_("Text"))
form = models.TextField(verbose_name=_("Form"), blank=True, null=True)
...
def get_markdown_text(self):
return mark_safe(markdown2.markdown(self.text))
def get_markdown_form(self):
return mark_safe(markdown2.markdown(self.form))
I'm not very happy with this solution, because of the unnecessary field "form" and method get_markdown_form in Post and post_detail.html.