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.
Related
I'm using django parler to translate my models. now i'm creating a custom admin Panel and i have a view for create and update of Contents. I'm using a class based view inherit from "View" for both create and update views so i can't use the TranslatableCreateView and TranslatableUpdateView. I saw in the codes of Django parler that using TranslatableModelFormMixin you can add translation support to the class-based views. I used this mixin but still i don't have access to the language tabs.
Here is Views.py:
class ContentCreateUpdateView(TranslatableModelFormMixin, TemplateResponseMixin, View):
module = None
model = None
obj = None
template_name = 'content-form.html'
def get_model(self, model_name):
if model_name in ['text', 'video', 'image', 'file']:
return apps.get_model(app_label='courses', model_name=model_name)
return None
def get_form(self, model, *args, **kwargs):
Form = modelform_factory(model, exclude=['owner',
'order',
'created',
'updated'])
return Form(*args, **kwargs)
def dispatch(self, request, module_id, model_name, id=None):
self.module = get_object_or_404(Module, id=module_id, course__owner=request.user)
self.model = self.get_model(model_name)
if id:
self.obj = get_object_or_404(self.model,
id=id,
owner=request.user)
return super().dispatch(request, module_id, model_name, id)
def get(self, request, module_id, model_name, id=None):
form = self.get_form(self.model, instance=self.obj,)
return self.render_to_response({'form': form, 'object': self.obj})
def post(self, request, module_id, model_name, id=None):
form = self.get_form(self.model, instance=self.obj, data=request.POST, files=request.FILES)
if form.is_valid():
obj = form.save(commit=False)
obj.owner = request.user
obj.save()
if not id:
# new content
Content.objects.create(module=self.module, item=obj)
return redirect('module_content_list', self.module.id)
return self.render_to_response({'form': form, 'object': self.obj})
Template:
{% extends '_base.html' %}
{% load crispy_forms_tags %}
{% load crispy_forms_filters %}
{% block content %}
<div class="col-md-12">
<!-- Horizontal Form -->
<div class="card card-primary">
<div class="card-header ">
{% if object %}
<h3 class="card-title mb-0 float-left"> Edit Content "{{ object.title }}"</h3>
{% else %}
<h3 class="card-title mb-0 float-left"> Add New Content</h3>
{% endif %}
</div>
<!-- /.card-header -->
<!-- form start -->
<div class="card-body">
<form method="post" enctype="multipart/form-data">
<div class="row">
<div class="col-12">
{% if language_tabs %}
<ul class="nav nav-tabs">
{% for url,name,code,status in language_tabs %}
{% if status == 'current' %}
<input type="hidden" class="language_button selected" name="{{ code }}"/>
<li class="nav-item">
<a class="current nav-link active"
aria-selected="true">{{ name }}</a>
</li>
{% else %}
<li class="nav-item">
<a class="{{ status }} nav-link"
href="{{ url }}"
aria-selected="false">{{ name }}</a>
</li>
{% endif %}
{% endfor %}
</ul>
{% endif %}
</div>
<div class="col-6">
{{ form }}
</div>
</div>
{% csrf_token %}
<div class="col-6">
<button class="btn btn-success">Save Content</button>
</div>
</form>
</div>
</div>
</div>
<!-- /.card -->
{% endblock %}
Here is the source code of django parler:
class TranslatableModelFormMixin(LanguageChoiceMixin):
"""
Mixin to add translation support to class based views.
For example, adding translation support to django-oscar::
from oscar.apps.dashboard.catalogue import views as oscar_views
from parler.views import TranslatableModelFormMixin
class ProductCreateUpdateView(TranslatableModelFormMixin, oscar_views.ProductCreateUpdateView):
pass
"""
def get_form_class(self):
"""
Return a ``TranslatableModelForm`` by default if no form_class is set.
"""
super_method = super().get_form_class
# no "__func__" on the class level function in python 3
default_method = getattr(
ModelFormMixin.get_form_class, "__func__", ModelFormMixin.get_form_class
)
if not (super_method.__func__ is default_method):
# Don't get in your way, if you've overwritten stuff.
return super_method()
else:
# Same logic as ModelFormMixin.get_form_class, but using the right form base class.
if self.form_class:
return self.form_class
else:
model = _get_view_model(self)
if self.fields:
fields = self.fields
return modelform_factory(model, form=TranslatableModelForm, fields=fields)
else:
return modelform_factory(model, form=TranslatableModelForm)
def get_form_kwargs(self):
"""
Pass the current language to the form.
"""
kwargs = super().get_form_kwargs()
# The TranslatableAdmin can set form.language_code, because the modeladmin always creates a fresh subclass.
# If that would be done here, the original globally defined form class would be updated.
kwargs["_current_language"] = self.get_form_language()
return kwargs
# Backwards compatibility
# Make sure overriding get_current_language() affects get_form_language() too.
def get_form_language(self):
return self.get_current_language()
The tabs should look like this:
But now it looks like this:
If someone have a similiar exprience, feel free to write your opinion
In the settings.py file find PARLER_LANGUAGES settings and change None to SITE_ID.
PARLER_LANGUAGES = {
1: (
{'code': 'en', }, # English
{'code': 'ru', }, # Russian
),
'default': {
'fallbacks': ['en'],
'hide_untranslated': False,
}
}
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)
In a Django project, I have used crispy forms to generate a form for a user to enter a title and a comment. For the comment section, I wish the user to be able to format their input (e.g add bold and italics tags, and also embed youtube videos, so use embed snippets). This is typical of a wordpress widget (admin) which allows text formatting for any text entry. Is it possible to do this with Django's Crispy forms, and if so, what is the best way forward? I am looking for suggestions for documentation, imports (any existing libraries compatible with Django?), as I as I couldn't find any, or an idea as to how to implement this manually. e.g. specifically, in which 'file' would it be implemented.
View of the html page (current)
View of the current form and text input on the comment area.
I've looked at the other questions-answers, but none answers this specifically.
This is the sort of functioanlity I would like to add to the form text input (for the content/comment box only)
Desired text input formatting options added
The current post_form.html code is below
{% extends "socialmedia/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Post your message</legend>
{{form|crispy}}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Post</button>
</div>
</form>
</div>
{% endblock content %}
post_detail.html
{% extends "socialmedia/base.html" %}
{% block content %}
<article class="media content-section">
<img class="rounded-circle article-img" src="{{object.author.profile.image.url}}">
<div class="media-body">
<div class="article-metadata">
<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>
{% if object.author == user %}
<div>
<a class="btn btn-secondary btn-sm mt-1 mb-1" href="{% url 'post-update' object.id %}"> Update </a>
<a class="btn btn-danger btn-sm mt-1 mb-1" href="{% url 'post-delete' object.id %}"> Delete </a>
</div>
{% endif %}
</div>
<h2 class="article-title">{{ object.title }}</h2>
<p class="article-content">{{ object.content }}</p>
</div>
</article>
{% endblock content %}
models.py (relevant to the form)
from django.db import models
from django.utils import timezone #don't forget to add this
from django.contrib.auth.models import User
from django.urls import reverse
class Post(models.Model):
title=models.CharField(max_length=100)
content=models.TextField(max_length=300)
date_posted=models.DateTimeField(default=timezone.now)
views.py (again relating to the form)
from django.shortcuts import render,get_object_or_404
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.contrib.auth.models import User
from .models import Post #import the Models Post
from django.views.generic import (
ListView,
DetailView,
CreateView,
UpdateView,
DeleteView
)
from django.http import HttpResponse
# Create your views here.
class PostListView(ListView):
model = Post #what model to query in order to create the list
template_name = 'socialmedia/home.html'
context_object_name = 'posts'
ordering = ['-date_posted']#the minus sign before the -date_posted makes it newest first
paginate_by = 10
class UserPostListView(ListView):
model = Post #what model to query in order to create the list
template_name = 'socialmedia/user_posts.html'
context_object_name = 'posts'
paginate_by = 10
def get_queryset(self):
user = get_object_or_404(User, username=self.kwargs.get('username'))
return Post.objects.filter(author=user).order_by('-date_posted')
class PostDetailView(DetailView):
model = Post
class PostCreateView(LoginRequiredMixin,CreateView):
model = Post
fields=['title','content']
def form_valid(self,form):
form.instance.author = self.request.user #set author to current loggged in user
return super().form_valid(form)
class PostUpdateView(LoginRequiredMixin,UserPassesTestMixin, UpdateView):
model = Post
fields=['title','content']
def form_valid(self,form):
form.instance.author = self.request.user
return super().form_valid(form)
#this only lets the user of the post update the post.....
def test_func(self):
post = self.get_object() #this gets the current post
if self.request.user == post.author:
return True
return False
class PostDeleteView(LoginRequiredMixin,UserPassesTestMixin, DeleteView):
model = Post
success_url = '/'
def test_func(self):
post = self.get_object() #this gets the current post
if self.request.user == post.author:
return True
return False
recently I decide to add a comment block to my template in my django app but when I add it to my app , I faced to this error :
add_comment_to_post() got an unexpected keyword argument 'item_id'
my template.html:
{% block content %}
<form action="#" method="post" novalidate="novalidate">
{% csrf_token %}
{{ form.as_p }}
<div class="row">
<div class="col-md-4">
<p><label>Name*</label><input type="text" name="your-name" value=""
size="60" class=""
aria-required="true"
aria-invalid="false"></p>
</div>
<div class="col-md-4">
<p><label>Email*</label><input type="text" name="your-email"
value=""
size="60" class=""
aria-required="true"
aria-invalid="false"></p>
</div>
<div class="col-md-4">
<p><label>Website</label><input type="text" name="your-website"
value=""
size="60" class=""
aria-required="true"
aria-invalid="false"></p>
</div>
<div class="col-md-12">
<p><label>Message</label><textarea name="your-message" cols="60"
rows="3" class=""
aria-invalid="false"></textarea>
</p>
</div>
</div>
<div class="dividewhite2"></div>
<p>
<button type="button" href="{% url 'add_comment_to_post' pk=item.pk %}"
class="btn btn-lg btn-darker">Post Comment
</button>
</p>
</form>
{% endblock %}
my models.py :
from django.db import models
from datetime import date
from django.utils import timezone
# Create your models here.
class Blogs(models.Model):
main_image = models.ImageField(upload_to='Blogs/', help_text='This Image Is Gonna To Be Show At Blogs Page.',
blank=False, default='')
class Comment(models.Model):
post = models.ForeignKey('Blog.Blogs', on_delete=models.CASCADE, related_name='comments')
author = models.CharField(max_length=200)
text = models.TextField()
created_date = models.DateTimeField(default=timezone.now)
approved_comment = models.BooleanField(default=False)
def approve(self):
self.approved_comment = True
self.save()
def __str__(self):
return self.text
my form.py:
from django.forms import ModelForm
from .models import Blogs, Comment
class CommentForm(ModelForm):
class Meta:
model = Comment
fields = ('author', 'text',)
my views.py :
from django.shortcuts import render, get_object_or_404, redirect
from Blog.forms import CommentForm
from .models import Blogs, Comment
def item(request, items_id):
items = get_object_or_404(Blogs, pk=items_id)
return render(request, 'Blog/Items.html', {'item': items, 'comments': Comment})
def add_comment_to_post(request, pk):
post = get_object_or_404(Blogs, 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, 'blog/Items.html', {'form': form})
and my urls.py:
from django.urls import path
from Blog import views
from Blog import models
urlpatterns = [
path('<int:item_id>/', views.add_comment_to_post, name='add_comment_to_post'),
path('<int:items_id>/', views.item, name='Itemz'),
]
I checked my code many times but I can't understand what is my problem.
is any body know to how can I add comment to my app or what is my problem?
In addition, I'm sorry for writing mistakes in my question.
change this
def add_comment_to_post(request, pk):
To:
def add_comment_to_post(request, item_id):
Then change everywhere inside the function you wrote pk to item_id
views.py
def add_comment_to_post(request, item_id):
post = get_object_or_404(Blogs, pk=item_id)
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, 'blog/Items.html', {'form': form, 'item': post})
and in your template:
<button type="button" href="{% url 'add_comment_to_post' item.pk %}"
class="btn btn-lg btn-darker">Post Comment
</button>
Double check your url patterns maybe? Try:
urlpatterns = [
path('<int:pk>/', views.add_comment_to_post, name='add_comment_to_post'),
The variable name in your view method needs to match the variable name in the url. Therefore you need both to be pk or both to be item_id
The Problem happen because in urls.py there were two subject that was pass to one views.
change views to this :
urlpatterns = [
path('<int:pk>/', views.item, name='Itemz'),
]
then change html part to this :
{% if not user.is_authenticated %}
<p><a href="{% url 'login' %}" class="btn btn-gr btn-xs">Login To Send
A Command.</a></p>
{% endif %}
<div class="dividewhite2"></div>
{% if user.is_authenticated %}
<form method="post" novalidate="novalidate">
{% csrf_token %}
{{ form.as_p }}
<div class="dividewhite2"></div>
<p>
<button href="{% url 'Itemz' item.id %}" type="submit"
class="btn btn-lg btn-darker">Post Comment
</button>
</p>
</form>
{% endif %}
now the Django project will run properly.
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)