I did break my head to implement django-hitcount on my blog.
I could do the views count works, but are happening an error to access in my administration page.
Following the code and the error image:
Thank you.
urls.py
from django.contrib import admin
from django.conf import settings
from django.conf.urls.static import static
from django.urls import path, include
from blog.views import index, blog, post
urlpatterns = [
path('admin/', admin.site.urls),
path('', index, name='home'),
path('blog/', blog, name='post-list'),
path('post/<id>/', post, name='post-detail'),
path('ckeditor', include('ckeditor_uploader.urls')),
path('hitcount/', include(('hitcount.urls', 'hitcount'), namespace='hitcount')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
views.py
from django.shortcuts import render, get_object_or_404, redirect, reverse
from .models import Post, Author
from django.db.models.aggregates import Count
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from hitcount.models import HitCount
from hitcount.views import HitCountMixin
...
def post(request, id):
category_count = get_category_count()
most_recent = Post.objects.order_by('-timestamp')[:3]
popular_posts = Post.objects.order_by('-hit_count_generic__hits')[:3]
post = get_object_or_404(Post, id=id)
hit_count = HitCount.objects.get_for_object(post)
hit_count_response = HitCountMixin.hit_count(request, hit_count)
count_hit = True
if request.method == "POST":
return redirect(reverse("post-detail", kwargs={
'id': post.pk
}))
context = {
'post': post,
'hit_count': hit_count,
'category_count': category_count,
'popular_posts': popular_posts,
'views': Post.objects.get(pk=1),
# views.hit_count.hits
# views.hit_count.hits_in_last(days=7)
}
return render(request, 'blog/post.html', context)
post.html
{% extends 'blog/base.html' %}
{% load static %}
{% load hitcount_tags %}
{% block content %}
<body>
<div class="container">
<div class="row">
<div class="col-md-8">
<div>
<div class="" >
<div class="card mb-3">
<img src="{{ post.thumbnail.url }}" class="card-img-top with:"100%"" alt="...">
<div class="card-body">
<h5 class="card-title">{{ post.title }}</h5>
<img src="{{ post.author.profile_picture.url}}" alt="..." class="rounded-circle width="40" height="40"" >
<p>{{ post.author }} | <i class="far fa-clock"></i> {{ post.timestamp|timesince }} ago | <i class="far fa-eye"> {% get_hit_count for post %} views</i></p>
<div>
<hr class="my-4">
<p class="card-text">{{ post.content|safe }}</p>
</div>
<p class="card-text"><small class="text-muted">{{ post.timestamp}}</small></p>
</div>
</div>
</div>
</div>
</div>
<!--Side Bar-->
{% include 'blog/sidebar.html' with most_recent=most_recent category_count=category_count %}
</div>
</div>
</body>
http://127.0.0.1:8000/admin/hitcount/hitcount/
enter image description here
Can you share your admin.py related this model? Because I had the same problem and fixed it in admin.py.
How I fixed my problem in my admin.py file:
class PostAdmin(admin.ModelAdmin):
list_display = ('id', 'baslik', 'kategori', 'slug', 'taslakDurumu', 'formatted_hit_count')
def formatted_hit_count(self, obj):
return obj.current_hit_count if obj.current_hit_count > 0 else '-'
formatted_hit_count.admin_order_field = 'hit_count'
formatted_hit_count.short_description = 'Hits'
it was like this and appered same error so I've added () and worked.
Like this:
def formatted_hit_count(self, obj):
return obj.current_hit_count() if obj.current_hit_count() > 0 else '-'
formatted_hit_count.admin_order_field = 'hit_count'
formatted_hit_count.short_description = 'Hits'
admin.site.register(Post, PostAdmin)
Related
Trying to implement a update post view to my django blog.
It keeps throwing me the error: 'Generic detail view UpdatePostView must be called with either an object pk or a slug in the URLconf.'
I know it is telling me to call it with a PK or slug, but I'm not sure how to do this.
views.py:
class UpdatePostView(UpdateView):
model = Post
template_name = 'update_post.html'
fields = ('title', 'excerpt', 'slug', 'featured_image',
'content', 'author', 'status')
urls.py:
from .views import AddPost, PostList, PostDetail, PostLike, UpdatePostView
from django.urls import path
urlpatterns = [
path('', PostList.as_view(), name='home'),
path('like/<slug:slug>/', PostLike.as_view(), name='post_like'),
path('add_post/', AddPost.as_view(), name='create_post'),
path('edit_post/', UpdatePostView.as_view(), name='update_post'),
path('<slug:slug>/', PostDetail.as_view(), name='post_detail'),
]
update_post.html:
{% extends "base.html" %}
{% block content %}
<header>
<div class="container-fluid" id="image">
<div class="row px-4 text-center">
<img class="img-fluid header-image" id="main-background"
src="https://res.cloudinary.com/dhyy9pzrd/image/upload/v1653761818/header-image_q71tuy.jpg"
alt="blue/pink background image">
<div class="col-lg-6 mx-auto">
<div class="caption">
<div class="text-center-caption">
<h1 class="post-title fw-bolder text-uppercase">Update your post</h1>
<h6 class="post-subtitle fw-bold">blablablabla</h6>
</div>
</div>
</div>
</div>
</div>
</header>
<form class="text-center m-3" action="." method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button class="btn btn-signup right" id="button">Post</button>
</form>
{%endblock%}
answer is in #Waldemar Podsiadio comment
urls.py:
from .views import AddPost, PostList, PostDetail, PostLike, UpdatePostView
from django.urls import path
urlpatterns = [
path('', PostList.as_view(), name='home'),
path('like/<slug:slug>/', PostLike.as_view(), name='post_like'),
path('add_post/', AddPost.as_view(), name='create_post'),
# for edit you should define slug or pk through /<int:pk>/ or /<pk>/
path('edit_post/<slug:slug>/', UpdatePostView.as_view(), name='update_post'),
path('<slug:slug>/', PostDetail.as_view(), name='post_detail'),
]
I want to show the topic title in the website template url link on django 3.
currently opening the topic id number.
for example : http://localhost:8000/detay/4
for example : http://localhost:8000/detay/2
for example : http://localhost:8000/detay/1
but I want to do it this way
for example : http://localhost:8000/detay/1/this-is-topic-title
or
for example : http://localhost:8000/detay/3/this-is-topic-title
.
.
.
views.py
from django.shortcuts import render, get_object_or_404
from django.utils import timezone
from .models import *
# Create your views here.
def index(request):
girdiler = Deneme1Model.objects.filter(yuklemeTarihi__lte=timezone.now()).order_by('-yuklemeTarihi')
context ={
'girdiler':girdiler
}
return render(request, 'deneme1Uygulama/index.html', context)
def ekle(request):
return render(request, 'deneme1Uygulama/ekle.html')
def detay(request, pk):
girdiler = Deneme1Model.objects.filter(pk=pk)
context ={
'girdiler':girdiler
}
return render(request, 'deneme1Uygulama/detay.html', context)
def sayfaYok(request):
return render(request, 'deneme1Uygulama/404.html')
urls.py
from django.urls import path
from .import views
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('', views.index, name='index'),
path('ekle/', views.ekle, name='ekle'),
path('detay/<int:pk>', views.detay, name='detay'),
path('404/', views.sayfaYok, name='sayfaYok'),
]
urlpatterns +=static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
models.py
from django.db import models
from django.utils import timezone
# Create your models here.
class Deneme1Model (models.Model):
baslik = models.CharField(max_length=50, verbose_name='BAŞLIK')
aKaydi = models.CharField(max_length=50, verbose_name='A KAYDI')
dosyaYukle = models.FileField(upload_to='media', verbose_name='DOSYA YÜKLE')
yuklemeTarihi =models.DateTimeField(default =timezone.now)
yayinKontrol = models.BooleanField(default=True)
def __str__(self):
return self.baslik
detay.html
{% block content %}
<div class="row">
{% if girdiler %}
{% for girdi in girdiler %}
<div class="col-12 d-flex justify-content-center">
<div class="card w-100">
<img class="card-img-top img-fluid umaxhe20" src=" {{ girdi.dosyaYukle.url }} " alt="Card image cap">
<div class="card-body">
<h5 class="card-title"> {{ girdi.baslik }} </h5>
<p class="card-text"> {{ girdi.aKaydi }} </p>
{{ girdi.yuklemeTarihi }}
</div>
</div>
</div>
{% endfor %}
{% else %}
{% url 'sayfaYok' %}
{% endif %}
</div>
{% endblock content %}
Not tested but probably something like this
urls.py
urlpatterns = [
path('detay/<int:pk>', views.detay, name='detay'),
path('detay/<int:pk>/<string:topic>', views.detay_topic, name='detay-topic'),
]
views.py
def detay_topic(request, pk, topic):
...
I am trying to link my home page view to other views but it's not working
I also tried to take only a single view but it still not working
I also don't know how to connect multiple views into a single URL
app/views.py
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import redirect
from django.shortcuts import render
from homePage.forms import SignInForm,DropUsaMessage
# Create your views here.
def homePage(request):
sign_in_detail=SignIn
message_detail=DropUsaMessage
return render(request, "index.html",{"form":sign_in_detail,"forms":message_detail})
def SignIn(request):
sign_in_detail=SignInForm()
if request.method == 'POST':
sign_in_detail = SignInForm(request.POST)
if sign_in_detail.is_valid():
return render(request, "index2.html",{"form":sign_in_detail})
else:
sign_in_detail = SignInForm()
# "form":sign_in_detail
return render(request, "index.html",{})
def Contact(request):
message_detail=DropUsaMessage()
if request.method == 'POST':
message_detail = DropUsaMessage(request.POST)
if message_detail.is_valid():
return homePage(request)
else:
message_detail = DropUsaMessage()
# "forms":message_detail
return render(request, "index.html",{"forms":message_detail})
app/urls.py
from django.urls import path
from . import views
urlpatterns=[
path('', views.homePage),
]
app/forms.py
from django import forms
from django.core import validators
class SignInForm(forms.Form):
email=forms.EmailField(widget=forms.EmailInput(attrs={"class": 'form-control',"placeholder":'Enter E-mail',"id": 'exampleInputEmail1'}))
password=forms.CharField(widget=forms.PasswordInput(attrs={"class":'form-control',"placeholder":'Enter Password',"id":'exampleInputPassword1'}))
class DropUsaMessage(forms.Form):
name = forms.CharField(widget=forms.TextInput(attrs={"class":'form-control',"placeholder":'Your Name'}))
email = forms.EmailField(widget=forms.EmailInput(attrs={"class": 'form-control',"placeholder":'Your E-mail',"id": 'exampleInputEmail1'}))
phone = forms.IntegerField(widget=forms.NumberInput(attrs={"class":'form-control',"placeholder":'Your Phone Number'}))
message = forms.CharField(widget=forms.Textarea(attrs={"class":'form-control',"placeholder":'Type Your Message',"style":'width:100%; height: 150px'}))
index.html
<div class="container-fluid">
<div class="row">
<div class="col-md-8">
<img src="{% static 'img/sampleImage.jpg' %}" width="100%" height="100%" class="d-inline-block align-top" alt="">
</div>
<div class="col-md-4">
<form method="POST">
{% csrf_token %}
{{ form }}
<div class="form-check">
<span class="fpswd">Forgot password?</span>
</div>
<button type="submit" class="btn btn-primary" name="SignIn">Submit</button>
</form>
</div>
</div>
</div>
<div class="container contact-form">
<form method="post">
<h3>Drop Us a Message</h3>
{% csrf_token %}
{{ forms }}<br><br>
<div class="form-group">
<input type="submit" name="SendMessage" class="btnContact" value="Send Message" />
</div>
</form>
</div>
the signin field is not showing up. there is a long address is showing in django-debug-toolbar
Give names to your URL patterns like below:
urlpatterns=[
path('', views.homePage, name='home'),
]
Then in your templates you can use Jinja to reference these names like.
Home
You can get a little help from DjangoProject site tutorial with the link.
UPDATE:
You need to create a Navbar (Navigation bar). You can then call all your pages with URLS in your home page. Like
Home | Services | Portfolio
You need to create urlpatterns with name for each page and you can then use it like.
<ul><li>Home</li>
<ul><li>Services</li>
<ul><li>Portfolio</li>.
So then all the pages will link up to your home page and you can navigate.
For that you need to create 3 respective views like below in your urls.py:
urlpatterns=[
path('', views.homePage, name='home'),
path('services/', views.servicePage, name='services'),
path('portfolio/', views.portfolioPage, name='portfolio'),
]
You can not have multiple views on a single URL. One URL maps to a single view.
I am trying use the django generic view for CRUD, but the DeleteView result in error 405, following the guide official Django https://docs.djangoproject.com/en/2.1/ref/class-based-views/generic-editing/ , I don't understand where is my error, so that's my code:
views.py
from django.urls import reverse
from django.views.generic import (
CreateView,
DetailView,
ListView,
UpdateView,
ListView,
DeleteView
)
from .forms import ContatoModelForm
from .models import Contato
class ContatoCreateView(CreateView):
template_name = 'contato/contato_create.html'
form_class = ContatoModelForm
model = Contato
class ContatoListView(ListView):
template_name = 'contato/contato_list.html'
model = Contato
class ContatoDetailView(DetailView):
template_name = 'contato/contato_detail.html'
model = Contato
class ContatoUpdateView(UpdateView):
template_name = 'contato/contato_create.html'
form_class = ContatoModelForm
model = Contato
class ContatoDeleteView(DeleteView):
template_name = 'contato/contato_delete.html'
model = Contato
def get_success_url(self):
return reverse('contato:contato-list')
urls.py
from django.urls import path
from .views import (
ContatoCreateView,
ContatoDeleteView,
ContatoDetailView,
ContatoListView,
ContatoUpdateView,
)
app_name = 'contato'
urlpatterns = [
path('', ContatoListView.as_view(), name='contato-list'),
path('create/', ContatoCreateView.as_view(), name='contato-create'),
path('<int:pk>/', ContatoDetailView.as_view(), name='contato-detail'),
path('<int:pk>/update/', ContatoUpdateView.as_view(), name='contato-update'),
path('<int:pk>/delete/', ContatoDeleteView.as_view(), name='contato-delete'),
]
contato_delete.html
<form action='.' method='post'>{% csrf_token %}
<dialog class="mdl-dialog">
<h6>Deseja excluir {{ object.nome }}?</h6>
<div class="mdl-dialog__actions">
<input type="submit" class="mdl-button mdl-js-button mdl-button--accent" value="Excluir">
<button type="button" class="mdl-button close">Cancelar</button>
</div>
</dialog>
</form>
contato_detail.html
{% extends 'base.html' %}
{% load staticfiles %}
{% block content %}
<div class="mdl-card__title">
<h2 class="mdl-card__title-text">{{ object.nome }}</h2>
</div>
<div class="mdl-layout-spacer"></div>
<a id="show-dialog" class="mdl-button mdl-js-button mdl-button--icon">
<i class="material-icons">delete</i>
</a>
{% include "contato/contato_delete.html" %}
<script type="text/javascript" src="{% static 'js/dialog.js' %}"></script>
<div class="mdl-card__actions mdl-card--border">
<ul class="demo-list-icon mdl-list">
<li class="mdl-list__item">
<span class="mdl-list__item-primary-content">
<i class="material-icons mdl-list__item-icon">call</i>
{{ object.celular }}
</span>
</li>
<li class="mdl-list__item">
<span class="mdl-list__item-primary-content">
<i class="material-icons mdl-list__item-icon">email</i>
{{ object.email }}
</span>
</li>
<li class="mdl-list__item">
<span class="mdl-list__item-primary-content">
<i class="material-icons mdl-list__item-icon">business</i>
{{ object.cargo }} na {{ object.empresa}}
</span>
</li>
</ul>
</div>
<a href="{% url 'contato:contato-update' object.id %}" id="fab" class="mdl-button mdl-js-button mdl-button--fab mdl-button--primary">
<i class="material-icons">create</i>
</a>
{% endblock %}
contato_list.html
{% extends "base.html" %}
{% block content %}
<style>
.demo-list-three {
width: 800px;
margin-left: 30px;
}
#fab {
position: fixed;
display: block;
right: 0;
bottom: 0;
margin-right: 40px;
margin-bottom: 40px;
z-index: 900;
}
</style>
<form method='GET' action=''>
</form>
{% for obj in object_list %}
<ul class="demo-list-three mdl-list">
<li class="mdl-list__item mdl-list__item--three-line">
<span class="mdl-list__item-primary-content">
<i class="material-icons mdl-list__item-avatar">person</i>
<a href='{{ obj.get_absolute_url }}'><span>{{ obj.nome }}</span>
</a>
<span class="mdl-list__item-text-body">
{{ obj.celular }} <br>
{{ obj.email }}
</span>
</span>
<a href="{{ obj.get_absolute_url }}" class="mdl-button mdl-js-button mdl-button--primary">
DETALHES
</a>
</li>
</ul>
{% endfor %}
<a href="{% url 'contato:contato-create' %}" id="fab" class="mdl-button mdl-js-button mdl-button--fab mdl-button--primary">
<i class="material-icons">person_add</i>
</a>
{% endblock content %}
Simplify your code:
class ContatoCreateView(CreateView):
template_name = 'contato/contato_create.html'
form_class = ContatoModelForm
model = Contato # Tell the CBV what object you will create
#** This doesn't make any sense, you are creating a new Contato not retrieving a queryset.
# queryset = Contato.objects.all()
#** Let the ModelForm handle the validation
# def form_valid(self, form):
# print(form.cleaned_data)
# return super().form_valid(form)
class ContatoListView(ListView):
template_name = 'contato/contato_list.html'
model = Contato # This does the work for you
#** You don't need to do this, unless you want a _specific_ queryset filterd
# queryset = Contato.objects.all()
class ContatoDetailView(DetailView):
template_name = 'contato/contato_detail.html'
model = Contato # again, just define the model
#** let CBV handle this logic
# def get_object(self):
# id_ = self.kwargs.get("id")
# return get_object_or_404(Contato, id=id_)
class ContatoUpdateView(UpdateView):
template_name = 'contato/contato_create.html'
form_class = ContatoModelForm
model = Contato # again, just define the model
#** let CBV handle this logic
# def get_object(self):
# id_ = self.kwargs.get("id")
# return get_object_or_404(Contato, id=id_)
#** Let the ModelForm handle the validation
#def form_valid(self, form):
# print(form.cleaned_data)
# return super().form_valid(form)
class ContatoDeleteView(DeleteView):
template_name = 'contato/contato_delete.html'
model = Contato # the class object you want to delete
#** let CBV handle this logic
# def get_object(self):
# id_ = self.kwargs.get("id")
# return get_object_or_404(Contato, id=id_)
def get_success_url(self):
return reverse('contato:contato-list')
You need to set the action on the form to match the route (url) for deleting a contato object.
Basically change the open tag of the <form> to:
<form action='{{ id }}/delete' method='post'>
and pass an id to the view through the context, like this:
class ContatoDetailView(DetailView):
model = Contato
def get(self, request, *args, **kwargs):
self.object = self.get_object()
context = self.get_context_data(object=self.object)
context['id'] = self.object.id
return self.render_to_response(context)
As an additional recommendation, I'd look into making your routes more RESTful. See this gist for info: https://gist.github.com/alexpchin/09939db6f81d654af06b. Something to note though is that HTML5 forms do not have support for delete (or put) requests. To make a delete request with a form you'd have to submit the request manually on submit using javascript.
I have for example the Post with the id 31 after I upload one or more images are displayed in db as:
id (for example: 1,2,3)
url to image(for example: my-images/image.png)
foreing_id (thats is id to post i.e 31)
But I do not know how to display the image in the template for this post (and others of course)
my model:
class Post(models.Model):
title = models.CharField(max_length=20000)
date = models.DateTimeField(editable=True, null=True)
text = models.TextField(max_length=50000)
is_super = models.IntegerField(default=0)
class Image(models.Model):
foreing = models.ForeignKey(Post)
image = models.ImageField(null=True, blank=True, upload_to='my-images')
view where i upload and display all posts(Here i display):
class IndexView(generic.ListView):
paginate_by = 4
template_name = 'home/index.html'
context_object_name = 'all_posts'
def get_queryset(self):
query = self.request.GET.get('q')
if query:
posts = Post.objects.filter(
Q(text__icontains=query.capitalize()) |
Q(title__icontains=query.capitalize()) |
Q(text__icontains=query.lower()) |
Q(title__icontains=query.lower())
).distinct()
return posts
else:
return Post.objects.filter(date__lte=timezone.now()).order_by('-date')
there i create a new post:
def post_new(request):
ImageFormSet = modelformset_factory(Image, form=ImageForm, extra=3)
if request.method == "POST":
form = PostForm(request.POST, request.FILES or None)
formset = ImageFormSet(request.POST, request.FILES, queryset=Image.objects.none())
if form.is_valid() and formset.is_valid():
post = form.save(commit=False)
post.date = timezone.now()
post.save()
for form in formset.cleaned_data:
image = form['image']
photo = Image(foreing_id=post.id, image=image)
photo.save()
return render(request, 'home/page.html')
else:
form = PostForm()
return render(request, 'home/edit_post.html',
{'form': form, 'error_message': 'something error message'})
else:
form = PostForm()
formset = ImageFormSet(queryset=Image.objects.none())
return render(request, 'home/edit_post.html', {'form': form, 'formset': formset})
And here i need to display images for all this posts:
Here is a image displayed
<div class="profile-img-container" style="text-align: center">
<img class="img" src="images">
<a target="_blank" title="****." href="URL to the uploaded image"><span class="fa fa-expand fa-5x" style="color: darkcyan" aria-hidden="true"></span></a>
full index.html if needed:
<div class="content">
{% for post in all_posts %}
<div class="thumbnail">
<p style="text-align: center">{{ post.title }}</p>
<p class="text" style="text-align: center; height: 40px; overflow: hidden">{{ post.text }}</p>
<p><a type="button" class="btn btn-primary" href="{% url 'klass:detail' post.id %}">More...</a></p>
<div class="profile-img-container" style="text-align: center">
<img class="img" src="/media/**display images**" style="height: 150px">
<a target="_blank" title="****." href="**url to images**"><span class="fa fa-expand fa-5x" style="color: darkcyan" aria-hidden="true"></span></a>
</div>
{% if user.is_authenticated %}
<form method="post" style="text-align: right">
<p>
{% csrf_token %}
<a methods="post" role="button" class="btn btn-info" href="{% url 'klass:favorite' post.id %}">
<i class="fa fa-heart" style="color: red" aria-hidden="true"></i>great! {{ post.is_super }}
</a>
</p>
</form>
<span style="margin-left: 90px">Published: {{ post.date }}</span>
{% else %}
<p style="text-align: right">****<br>
<a role="button" class="btn btn-info disabled" style="text-align: right">
<i class="fa fa-heart" aria-hidden="true"></i>great!</a>
{{ post.date }}
</p>
{% endif %}
</div>
{% endfor %}
EDIT
urls:
from django.conf.urls import url, include
from django.contrib import admin
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^home_page/', include('home.urls', namespace='home')),
url(r'^captcha/', include('captcha.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
settings:
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'home/static'),
]
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
another urls in home app:
from django.conf.urls import url
from . import views
app_name = 'home'
urlpatterns = [
***,
url(r'^$', views.IndexView.as_view(), name='index'),
url(r'^(?P<post_id>[0-9]+)/$', views.comments, name='detail'),
url(r'^(?P<post_id>[0-9]+)/addcomment$', views.addcomment, name='comment'),
url(r'^(?P<post_id>[0-9]+)/favorite/$', views.favorite, name='favorite'),
url(r'^(?P<pk>[0-9]+)/edit/$', views.post_edit, name='edit'),
url(r'^post/new/$', views.post_new, name='post_new'),
url(r'^(?P<post_id>[0-9]+)/delete_album/$', views.delete_post, name='delete_post'),
****,
]
You should loop through post.image_set.all and display each image separately, for example:
{% for image in post.image_set.all %}
<div class="profile-img-container" style="text-align: center">
<img class="img" src="{{ image.image.url }}" style="height: 150px">
<a target="_blank" href="{{ image.image.url }}">
<span class="fa fa-expand fa-5x" style="color: darkcyan" aria-hidden="true"></span>
</a>
</div>
{% endfor %}
A few side notes:
You shouldn't include /media in your image url as it will be automatically appended by Django.
Naming your foreign keys as foreign (also check your spelling) is not recommended for readability reasons. Consider renaming it to use the parent model's name in lowercase (such as post) instead so that it becomes post = models.ForeignKey(Post)
Referencing the foreign key using _id is not recommended. Use the model itself instead, for example: photo = Image(post=post, image=image)