Django display a photo from a model - python

I've tried several of methods on how to retrieve an image from a model with no luck, this is where I'm at so far. I'd like to have the image show and when the user clicks on it, it opens a modal showing a projects detail.
models.py
class Project(models.Model):
author = models.ForeignKey('auth.User')
title = models.CharField(max_length=200)
client = models.CharField(max_length=200)
date = models.DateField(timezone.now())
service = models.CharField(max_length=200)
info = models.TextField()
photo = models.ImageField(upload_to='ports/static/img/',
default='ports/static/img/port_photo.png',
height_field='photo_height',
width_field='photo_width',)
photo_height = models.PositiveIntegerField(blank=True, default=900)
photo_width = models.PositiveIntegerField(blank=True, default=650)
created_date = models.DateTimeField(
default=timezone.now)
published_date = models.DateTimeField(
blank=True, null=True)
index.html
<section id="portfolio">
{% for project in projects %}
<div class="row">
<div class="col-lg-12 text-center">
<h2>Portfolio</h2>
<hr class="star-primary">
</div>
</div>
<div class="row">
<div class="col-sm-4 portfolio-item">
<a href="#portfolioModal1" class="portfolio-link" data-toggle="modal">
<div class="caption">
<div class="caption-content">
<i class="fa fa-search-plus fa-3x"></i>
</div>
</div>
<img src="{{ projects.photo.url }}" class="img-responsive" alt="">
</a>
</div>
</div>
</div>
{% endfor %}
</section>
views.py
from django.shortcuts import render
from .forms import ContactForm
from django.utils import timezone
from .models import Project
# Create your views here.
def index(request):
form_class = ContactForm
projects = Project.objects.filter(published_date__lte=timezone.now()).order_by('-published_date')
return render(request, 'ports/index.html', {'form': form_class, 'projects': projects})

Look at your img tag. In the src attribute, you are using {{ projects.photo.url }}. So, you cannot get image from a queryset, you can only do so from an object of Project model. Use {{ project.photo.url }}

Related

How to add "Edit Function" in django

I need to add an edit button to my django app but it only redirects me to the homepage and no edit is saved.
this is my views.py code, i think that's where the issue is coming from
def editPhoto (request, pk):
photo = Photo.objects.get(id=pk)
categories = Category.objects.all()
if request.method == 'POST':
description = request.FILES.get('description')
photo.save()
return redirect ('/')
context = {'categories': categories, 'photo': photo}
return render(request, 'photos/edit.html', context)`
models.py
class Category(models.Model): name = models.CharField(max_length=100, null=False, blank=False)
def __str__(self):
return self.name
class Photo(models.Model): category = models.ForeignKey( Category, on_delete=models.SET_NULL, null=True, blank=True) image = models.ImageField(null=False, blank=False) description = models.TextField()
def __str__(self):
return self.description`
edit.html
<div class="container"> <div class="row justify-content-center"> <div class="col">
Go Back
<form method='POST' action="" enctype="multipart/form-data">
{% csrf_token %}
<div style="height: 90vh;">
<img style="max-width: 100%; max-height: 100%;" src="{{photo.image.url}}" class="center" >
</div>
<div>
<input required name="description" class="input" value="{{photo.description}}" type="text" size="60"></input>
</div>
<div class="center">
<button type="submit" class="btn btn-primary m-3; center">Update</button>
</div>
</div>
</div>
</div>`
The problem is that you are not saving any changes in your model.
description = request.FILES.get('description')
photo.save()
this should be changed to
photo.description = request.POST.get('description')
photo.save()
The problem is You are not passing id of photo you want to edit from your html file.
in Edit.html in form action="{% url photo.id %} , and make changes if needed in urls.py file.
by doing so id would be passed to views.py which acts as pk.

How can I filter out date created task in my task list

I'm trying to show the date-created tasks in my list in HTML.
Models.py:
class Task(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
title = models.CharField(max_length=200)
description = models.TextField(max_length=1000, blank=True, null=True)
complete = models.BooleanField(default=False)
created = models.DateTimeField(auto_now_add=True)
And this is my HTML in Django:
<div class="task-items wrapper">
{% for task in tasks %}
<div class="task-wrapper">
{% if task.complete %}
<div class="task-title">
<div class="task-complete-icon"></div>
<i><s><a class="task" href="{% url 'update-task' task.id %}">{{task}}</a></s></i>
<br></br>
</div>
<a class="delete-link" href="{% url 'delete-task' task.id %}"><i class="fa-solid fa-delete-left"></i></a>
{% else %}
<div class="task-title">
<div class="task-incomplete-icon"></div>
{{task}}
</div>
<a class="delete-link" href="{% url 'delete-task' task.id %}"><i class="fa-solid fa-delete-left"></i></a>
{% endif %}
</div>
<div class="emptylist">
{% empty %}
<h3 style="text-align: center; line-height: 3;">No task in list! Let's create your task</h3>
</div>
{% endfor %}
</div>
For example, for each task I create, it must show the title with the date created, and doesn't matter if it is complete or incomplete. I just can show the title and how do I do that show the date?
You could use DateField()django-doc directly. But if you have defined DateTimeField so you can use #property decorator and show date in the format like 1-7-2022 as you shown in the picture.
Create #property in your Task model like this:
class Task(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
title = models.CharField(max_length=200)
description = models.TextField(max_length=1000, blank=True, null=True)
complete = models.BooleanField(default=False)
created = models.DateTimeField(auto_now_add=True)
#property
def get_only_date(self):
date_object = self.created
year = date_object.year
month = date_object.month
day = date_object.day
return f"{day}-{month}-{year}"
Then, use anywhere in your template file as property in loop:
{% for task in tasks %}
{{task.get_only_date}}
{% endfor %}
created = models.DateTimeField(auto_now_add=True)
please remove auto_now_add=True, then you will get DateTime picker in your template.
<div class="task-items wrapper">
{% for task in tasks %}
<div class="task-wrapper">
{% if task.complete %}
<div class="task-title">
<div class="task-complete-icon"></div>
<i><s><a class="task" href="{% url 'update-task' task.id %}">{{task.title}}-{{task.created}}</a></s></i>
<br></br>
</div>
<a class="delete-link" href="{% url 'delete-task' task.id %}"><i class="fa-solid fa-delete-left"></i></a>
{% else %}
<div class="task-title">
<div class="task-incomplete-icon"></div>
{{task.title}}-{{task.created}}
</div>
<a class="delete-link" href="{% url 'delete-task' task.id %}"><i class="fa-solid fa-delete-left"></i></a>
{% endif %}
</div>
<div class="emptylist">
{% empty %}
<h3 style="text-align: center; line-height: 3;">No task in list! Let's create your task</h3>
</div>
{% endfor %}
</div>
Currently, you are displaying a string representation of you Task model, which, I'm assuming is set to showing the title of your task. You need to
display the title and date separately
change your Task representation to return a string formatted with title and time
I would prefer (1), because it gives you much more control. If you want to go with (2), you'll need to add a __str__ or __repr__ method.
My recommended method is to use your «created» variable on your template to show the date.
Like for example, I have a model called «post_created_on»,
class Profile(models.Model):
post_created_on = models.DateTimeField()
and I want to show it on my template.
<h5>This is a post.</h5>
So then I'm just use use my «post_created_on» variable on your template to show the date.
<h5>This is a post. Created on: {{ task.post_created_on }}</h5>
class Task(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
title = models.CharField(max_length=200)
description = models.TextField(max_length=1000, blank=True, null=True)
complete = models.BooleanField(default=False)
created = models.DateTimeField(auto_now_add=True)
{% for task in tasks %}
{{task.created.date}}
{% endfor %}
You can use this way without coding any other properties.

Reverse for 'Article' with keyword arguments '{'pk': ''}' not found. 1 pattern(s) tried: ['this_is_article_number/(?P<pk>[0-9]+)$']

**my post/urls.py**
from django.urls import path
from . import views
urlpatterns = [
path('', views.HomeView.as_view(), name='home'),
path('<int:post_id>/details',
views.ArticleDetailView.as_view(), name='Article'),
]
**post/models.py**
from django.db import models
from froala_editor.fields import FroalaField
class Post(models.Model):
id = models.BigAutoField(auto_created=True, primary_key=True,
serialize=False, verbose_name='ID'),
title = models.CharField(default='Title of article',
max_length=500)
content = FroalaField()
post_time = models.DateTimeField(auto_now_add=True)
thumbnail = models.ImageField(upload_to='images/', blank=True)
photo_1 = models.ImageField(upload_to='images/', blank=True)
photo_2 = models.ImageField(upload_to='images/', blank=True)
photo_3 = models.ImageField(upload_to='images/', blank=True)
photo_4 = models.ImageField(upload_to='images/', blank=True)
photo_5 = models.ImageField(upload_to='images/', blank=True)
photo_6 = models.ImageField(upload_to='images/', blank=True)
popular = models.BooleanField(default=False)
def __str__(self):
return self.title
post/Views.py
from django import views
from django.shortcuts import render
from django.http import request, HttpResponse
from django.views.generic.base import View
from django.views.generic.list import ListView
from django.views.generic.detail import DetailView
from django import views
from .models import Post
class HomeView(View):
def get(self, request):
posts = Post.objects.all().order_by("-id")
context = {
"posts": posts
}
return render(request, "home.html", context=context)
class ArticleDetailView(View):
def get(self, request, post_id):
detail = Post.objects.get(pk=post_id)
context = {
"detail": detail
}
return render(request, "article.html", context=context)
home.html
{% extends 'base.html' %} {% load static %} {% block content %}
<header>
<div class="header-wrapper">
<div class="hero">
<div class="hero-left">
<h1 class="main-heading">Live Blogger</h1>
<p class="main-subheading">Learn to design websites</p>
Learn More
</div>
<div class="hero-right">
<img src="{% static 'images/hero-image.png' %}" alt="" />
</div>
</div>
</div>
</header>
<div class="wrapper">
<section class="posts-wrapper">
<h2>Latest Blog Posts</h2>
<div class="blogpost-card">
<div class="thumbnail-image">
{% for post in posts %}
<img src="{{post.thumbnail.url}}" alt="" />
</div>
<a href="{% url 'Article' post.id %}">
<h3 class="post-title">{{ post.title }}</h3>
</a>
<div class="post-meta">{{ post.post_time}}</div>
<div class="post-body">
<p>
{{ post.content|safe}}
</p>
<div class="read-more-container">
Read More
</div>
{% endfor %}
</div>
</div>
</section>
<div class="popular-posts-container">
<h2>Popular Posts</h2>
<div class="popular-posts">
<div class="popular-post">
<div class="thumbnail">
<img src="{{post.thumbnail.url}}" alt="" />
<a href="{% url 'Article' post.id %}">
<h3 class="post-title">{{ post.title }}</h3>
</a>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
please help me i tried to solve this problem by watching many videos on youtube and tried watching more wustion on stachowerflow but now i am really stuck please try to help me .
in html
i tried using pk=post.pk it didn't wrok
i tried using post.pk it didn't work
i tried using pk=post.id it didn't wrok
i tried using post.id it didn't work
Do not forget to import View.
Write following code in your HomeView in views.py
class HomeView(View):
def get(self, request):
posts = Post.objects.all().order_by("-id")
context = {
"posts": posts
}
return render(request, "home.html", context=context)
And edit your {% for post in post_list %} to {% for post in posts %} in your home.html
class ArticleDetailView(View):
def get(self, request, post_id):
detail = Post.objects.get(id=post_id)
context = {
"detail": detail
}
return render(request, "detail.html", context=context) # <- I don't know your detail template. Please adjust it by yourself.
instead of using pk use id
class ArticleDetailView(View):
def get(self, request, post_id):
detail = Post.objects.get(id=post_id)
context = {
"detail": detail
}
return render(request, "article.html", context=context)
and in your html
{% for post in posts %}
<img src="{{post.thumbnail.url}}" alt="" />
{% endfor %}
and in your url
path('<int:post_id>/details',Product_detail.as_view(),name='detail'),
change acc to this and you are good to go

How to create a comment-creation page related to a single blog-style post in Django

I am trying to create a comment creation page related to a single post on a blog-style site using Django.
The home page has a list of posts, each with a "comment" button. Ideally this "comment" button would then take you to a page that would have the original post listed at the top with the comment creation form underneath it.
I've been trying to figure out a way to access the data I'm looking for using primary keys but am not sure how to tie everything together.
Here are the 2 models I am trying to access (Post and Comment):
class Post(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
title = models.CharField(max_length=128)
content = models.TextField()
image = models.ImageField(upload_to='post_pics', blank=True)
date_posted = models.DateTimeField(default=timezone.now)
def get_absolute_url(self):
return reverse('home')
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')
user = models.ForeignKey(User, on_delete=models.CASCADE)
comment = models.TextField()
date_created = models.DateTimeField(default=timezone.now)
And the urls.py:
from django.urls import path
from .views import PostCreateView, PostListView, VehicleListView, CommentCreateView
from . import views
urlpatterns = [
path('', PostListView.as_view(), name='home'),
path('comment/new/<int:pk>', CommentCreateView.as_view(), name='comment-create'),
]
This is my current HTML for the home page (currently adds the post id to the end of the HTML on linked "comment-create" page):
{% for post in posts %}
<div class="infinite-item">
<div class="card m-3">
<div class="card-body" style="background-color:#bdcade; padding-bottom:0px">
<div class="media mb-3">
<img src="{{ user.profile.image.url }}" class="d-block ui-w-40 rounded-circle" style="width:40px;height:auto;" alt="">
<div class="media-body ml-3">
<h5 style="color:#ffffff">{{ post.user.username }}</h5>
<div class="small text-muted">Yesterday</div>
</div>
</div>
</div>
<div class="card-body">
<h5 class="card-title">{{ post.title }}</h5>
<p class="card-text">{{ post.content }}</p>
<div class="btn-group" role="group">
<button type="button" class="btn btn-secondary">Like</button>
<a class="btn btn-secondary" href="{% url 'comment-create' post.id %}" role="button">Comment</a>
</div>
</div>
</div>
</div>
This is my current HTML for the comment-creation page:
{% block content %}
<div class="card m-3">
<div class="card-body" style="background-color:#bdcade; padding-bottom:0px">
<div class="media mb-3">
<img src="{{ post.user.profile.image.url }}" class="d-block ui-w-40 rounded-circle" style="width:40px;height:auto;" alt="">
<div class="media-body ml-3">
<h5 style="color:#ffffff">{{ post.user.username }}</h5>
<div class="small text-muted">{{ post.title }}</div>
</div>
</div>
</div>
<div class="card-body">
<h5 class="card-title">{{ post.title }}</h5>
<p class="card-text">{{ post.content }}</p>
<div class="btn-group" role="group">
<button type="button" class="btn btn-secondary">Like</button>
<button type="button" class="btn btn-secondary">Comment</button>
</div>
</div>
</div>
<br>
<div class="container primary-segments">
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<fieldset>
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Post Comment</button>
</div>
</form>
</div>
{% endblock content %}
Here is the view for comment creation page (using get_context_data to access the Post model):
class CommentCreateView(LoginRequiredMixin, CreateView):
model = Comment
template_name = 'home/comment-form.html'
fields = ['comment',]
def get_context_data(self, **kwargs):
context = super(CommentCreateView, self).get_context_data(**kwargs)
pk = self.kwargs['pk']
context['post'] = Post.objects.filter(id=pk)
return context
def form_valid(self, form):
form.instance.user = self.request.user
return super().form_valid(form)
Currently, I can't access any of the data for the post in the comment creation page. I think it has to do with how I'm trying to tie the pk to the post within the -get_context_data` function. The primary key for the desired post is showing up in the URL, just not sure how to get at the right data.
Any help would be much appreciated. Thank you!
So it looks to me like you're using pk wrong here.
The pk in this code segment here:
def get_context_data(self, **kwargs):
context = super(CommentCreateView, self).get_context_data(**kwargs)
pk = self.kwargs['pk']
is the pk of the comment, however you're trying to use it to lookup a Post with context['post'] = Post.objects.filter(id=pk). Remember that pk stands for primary key and references the object that you declared as the model for your view. If you want the Post associated with that Comment you'll need to search for it using Comment.post since that's the declared foreign key inside your model.
After a lot of Googling/trial-and-error, I found a solution that got me what I was looking for.
Updated my View from THIS (note: I was trying to force a specific PK to test if it would filter to the correct data, but for some reason I still couldn't access anything):
class CommentCreateView(LoginRequiredMixin, CreateView):
model = Comment
template_name = 'home/comment-form.html'
fields = ['comment',]
def get_context_data(self, **kwargs):
context = super(CommentCreateView, self).get_context_data(**kwargs)
pk = 7
context['post'] = Post.objects.filter(id=pk)
return context
def form_valid(self, form):
form.instance.user = self.request.user
return super().form_valid(form)
To THIS:
class CommentCreateView(LoginRequiredMixin, CreateView):
model = Comment
template_name = 'home/comment-form.html'
fields = ['comment',]
def get_context_data(self, **kwargs):
context = super(CommentCreateView, self).get_context_data(**kwargs)
context['post'] = Post.objects.get(pk=self.kwargs['pk'])
return context
def form_valid(self, form):
form.instance.user = self.request.user
return super().form_valid(form)
Have a basic, high-level understanding of what this is doing (grabbing the PK from the URL), but am not entirely sure why the original .filter() method wasn't working.
If anyone could provide some context as to what's going on behind the scenes here, I'd love to see it.
Thanks!

How to link a comment to a single post in django?

I have a problem which I want to help me solve.
I have a "Post" with comments included but, when I comment a "Post" the comment I made in "Post 1" appears in "Post 2" and in all "Posts" and I want to link the comment to a single post, I've been looking for solutions but I have not been able to make it work.
EDIT I ADDED MY post/models.py
class Post(models.Model):
owner = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=200)
slug = models.SlugField(unique=True)
autor = models.CharField(max_length=200)
description = models.TextField()
likes = models.PositiveIntegerField(default=0)
created_date = models.DateTimeField(default=timezone.now)
published_date = models.DateTimeField(blank=True, null=True)
files = models.FileField(upload_to=upload_location, validators=
[validate_file_extension])
post_type = models.CharField(max_length=100, choices=Book_Type_Choices)
tags = TaggableManager()
models.py
class Comment(models.Model):
post = models.ForeignKey(Post, related_name='cooments')
user = models.ForeignKey(User, unique=False)
text = models.CharField(max_length=250)
created_date = models.DateTimeField(default=timezone.now)
approved_comment = models.BooleanField(default=False)
views.py
#login_required
def add_comment_to_post(request, pk):
post= 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.user = request.user
comment.save()
return redirect('post_detail', slug=post.slug)
else:
form = CommentForm()
return render(request, 'comments/add_comment_to_post.html', {'form':form})
my add_comment.html, this code fragment is included on my post_detail.html
<form action="{% url 'add_comment_to_post' pk=post.pk %}" method="post">
{% csrf_token %}
{{form.as_p}}
<input type="submit" class="btn btn-primary" value="Comentar">
</form>
my book_detail.html
<div class="container">
<div class="row">
<div class="col-md-6 comment" style="text-align: center;">
<!-- HERE IS WHERE I INCLUDE THE add_comment.html -->
{% include 'comments/add_comment_to_post.html' %}
</div>
{% for comment in comments %}
{% if user.is_authenticated or comment.approved_comment %}
<div class="col-sm-6 col-sm-offset-1">
<div class="media-body">
<div class="well well-lg">
<div class="avatar">
<img src="{{comment.user.profile.pic.thumbnail.url}}" class="img-responsive img-circle" alt="">
</div>
<h4 class="media-heading text-uppercase reviews">{{comment.user.get_full_name}} </h4>
<ul class="media-date text-uppercase reviews list-inline">
<li>{{comment.created_date}}</li>
</ul>
<p class="media-comment">
{{comment.text}}
</p>
<a class="btn btn-info btn-circle text-uppercase" href="#" id="reply"><span class="glyphicon glyphicon-share-alt"></span> Reply</a>
<a class="btn btn-warning btn-circle text-uppercase" data-toggle="collapse" href="#replyOne"><span class="glyphicon glyphicon-comment"></span> 2 comments</a>
</div>
</div>
</div>
{% endif %}
{% empty %}
<p>No hay comentarios que mostrar :(</p>
{% endfor %}
</div>
</div>
Any idea how I can make comments work? Thanks!
In the comment model try to remove the unique=False
Change
class Comment(models.Model):
user = models.ForeignKey(User, unique=False)
to
class Comment(models.Model):
user = models.ForeignKey(User) # remove unique=False
Do the above and take it from there

Categories

Resources