I am using a modelformset_factory method with forms containing only an ImageField. The Model the forms are based on contains a user field that has a many-to-one relationship with a User Model that extends AbstractUser(See Extending User Model with Abstract User). Currently, each instance of a user has a correlating User Profile, but I would also like to allow the user to upload a gallery of images to their profile.
models.py
class Gallery(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
image = models.ImageField(upload_to='user_gallery', blank=True, null=True)
def create_gallery(sender, **kwargs):
if kwargs['created']:
user_gallery = Gallery.objects.create(user=kwargs['instance'])
user_gallery.save();
post_save.connect(create_gallery, sender=User)
forms.py
class GalleryForm(forms.ModelForm):
image = forms.ImageField(label='FormImage')
class Meta:
model = Gallery
fields = ['image']
views.py
def EditProfile(request):
GalleryFormSet = modelformset_factory(Gallery, form=GalleryForm, extra=3, max_num=3)
if request.method == "POST":
formset = GalleryFormSet(request.POST, request.FILES)
if formset.is_valid():
for form in formset.cleaned_data:
my_image = form['image']
photo = Gallery(user=request.user, image=my_image)
photo.save()
return render(request, 'user_handler/editprofile.html', {'formset': formset})
else:
formset = GalleryFormSet()
return render(request, 'user_handler/editprofile.html', {'formset': formset})
Template
<form id="post_form" method="post" action="" enctype="multipart/form-data">
{% csrf_token %}
{{ formset.management_form }}
{% for form in formset %}
{{form.image}}
<img src="{{form.image.url}}"/>
{% endfor %}
<input type="submit" name="submit" value="Submit" />
</form>
The problem I'm have is that using {{ form.image }} produces this result:
... and using {{ form.image.url }} within an image's source tag produces absolute nothing at all. When I inspect the element I contain it in, it states the source is unknown. Obviously, the images are being saved in the DB as I'd like, but I can't get the .url functionality to work. And YES, I do have the media root an all defined:
settings.py
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
STATIC_URL = '/static/'
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'HighlightPage_Project/media')
urls.py
urlpatterns = [
url(r'^$', views.Login_Redirect),
url(r'^account/', include('user_handler_app.urls')),
url(r'^admin/', admin.site.urls),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Try to replace your code with the following code:
<img src="{{form.image.url}}"/>
with:
<img src="{{form.instance.image.url}}"/>
Try to replace your code with the following code:
views.py
def EditProfile(request):
GalleryFormSet = modelformset_factory(Gallery, form=GalleryForm, extra=3, max_num=3)
if request.method == "POST":
formset = GalleryFormSet(request.POST, request.FILES)
if formset.is_valid():
for form in formset.cleaned_data:
my_image = form['image']
photo = Gallery(user=request.user, image=my_image)
photo.save()
return render(request, 'user_handler/editprofile.html', {'formset': formset})
else:
user_images = Gallery.objects.filter(user=request.user)
initial_images = [{'image': i.image, 'image_url': i.image.url} for i in user_images if i.image]
formset = GalleryFormSet(initial=initial_images)
return render(request, 'user_handler/editprofile.html', {'formset': formset})
Template
<form id="post_form" method="post" action="" enctype="multipart/form-data">
{% csrf_token %}
{{ formset.management_form }}
{% for form in formset %}
{{form.image}}
<img src="{{form.initial.image_url}}"/>
{% endfor %}
<input type="submit" name="submit" value="Submit" />
Related
I was getting that same error while click the like button, But the error was solved..
again after creating comment view and its other staff I'm getting that error again...When I click the comment button then the error appears..I'm very new to Django,,, help me please..
My project models.py, template page, urls.py, views.py are attached herewith
**models.py**
from email.policy import default
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Blog(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=200, verbose_name="Put a Title")
blog_content = models.TextField(verbose_name="What is on your mind")
blog_image = models.ImageField(upload_to="blog_images", default = "/default.png")
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
return self.title
class Comment(models.Model):
blog = models.ForeignKey(Blog, on_delete=models.CASCADE, related_name = "blog_comment" )
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name = "user_comment")
comment = models.TextField()
comment_date = models.DateField(auto_now_add=True)
def __str__(self):
return self.comment
class Like(models.Model):
blog = models.ForeignKey(Blog, on_delete=models.CASCADE, related_name = "blog_liked")
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name = "user_liked")
class Unlike(models.Model):
blog = models.ForeignKey(Blog, on_delete=models.CASCADE, related_name = "blog_unliked")
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name = "user_unliked")
**blog_page.html**
{% extends "main.html" %}
{% load static %}
{% load crispy_forms_tags %}
{% block content %}
<div style="text-align:center;">
<h2>{{blog.title}}</h2>
<img src="{{blog.blog_image.url}}" alt="" width="630px" height="300px">
</div>
<div style="text-align:center;">
{{blog.blog_content|linebreaks}}
</div>
{% if not liked and not unliked %}
<h4> Like </h4>
<h4>Unlike</h4>
{% elif unliked %}
<h4> Like </h4>
{% elif liked %}
<h4>Unlike</h4>
{% endif %}
<div>
<h4>
Comments:
</h4>
{% for comment in comments %}
<div>
{{ user }} <br>
<h5>{{ comment }}</h5>
</div>
{% endfor %}
<!-- <h6>Add your comment:</h6> -->
<form action="" method="POST">
{% csrf_token %}
{{form|crispy}} <br>
<a class="btn btn-sm btn-info" href="{% url 'comment' %}">Comment</a>
</form>
</div>
{% endblock content %}
**urls.py**
from django.urls import path
from blog_app import views
urlpatterns = [
path("", views.home, name='home'),
path("blog_page/<str:pk>/", views.blog_view, name='blog_page'),
path("like/<str:pk>/", views.like, name="like"),
path("unlike/<str:pk>/", views.unlike, name="unlike"),
path("comment/", views.comment, name="comment"),
]
**views.py**
from django.shortcuts import render
from . models import Blog, Comment, Like, Unlike
from . forms import CommentForm
# Create your views here.
def home(request):
blogs = Blog.objects.all()
context = {'blogs': blogs}
return render(request, 'blog_app/home.html', context)
def blog_view(request, pk):
blog = Blog.objects.get(id=pk)
form = CommentForm()
comments = Comment.objects.filter(blog=blog)
context = {"blog": blog, "comments": comments, "form":form}
return render(request, 'blog_app/blog_page.html', context)
def like(request, pk):
blog = Blog.objects.get(id=pk)
user = request.user
liked, like = Like.objects.get_or_create(blog=blog, user=user)
context = {"liked" : liked, "blog": blog }
return render(request, "blog_app/blog_page.html", context)
def unlike(request, pk):
blog = Blog.objects.get(id=pk)
user = request.user
unliked, unlike = Unlike.objects.get_or_create(blog=blog, user=user)
context = {"unliked" : unliked, 'blog': blog}
return render(request, "blog_app/blog_page.html", context)
def comment(request):
form = CommentForm()
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
form.save()
context = {}
return render(request, "blog_app/blog_page.html", context)
Your comment button is just a link, is it normal ? I think, you want to submit your form when you click on?
<div>
<h4>
Comments:
</h4>
{% for comment in comments %}
<div>
{{ user }} <br>
<h5>{{ comment }}</h5>
</div>
{% endfor %}
<!-- <h6>Add your comment:</h6> -->
<form action="{% url 'comment' %}" method="POST">
{% csrf_token %}
{{form|crispy}} <br>
<button type="submit" class="btn btn-sm btn-info">Comment</button>
</form>
</div>
And i think, your problem occured because you dispolay this template from comment view without set blog in context data.
def blog_view(request, pk):
blog = Blog.objects.get(id=pk)
form = CommentForm()
comments = Comment.objects.filter(blog=blog)
context = {"blog": blog, "comments": comments, "form":form}
return render(request, 'blog_app/blog_page.html', context)
def comment(request):
form = CommentForm()
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
form.save()
return redirect("blog_page", pk=form.instance.blog.pk)
return HttpResponse(status_code=400) # error case
else:
return HttpResponse(status_code=501) # try to GET page
Better solution is to pass blog pk in the url for being able to render page with error:
path("blog/<int:pk>/comment/", views.comment, name="comment")
<form action="{% url 'comment' blog.pk %}" method="POST">
{% csrf_token %}
{{form|crispy}} <br>
<button type="submit" class="btn btn-sm btn-info">Comment</button>
</form>
def comment(request, pk):
blog = get_object_or_404(Blog, pk=pk)
form = CommentForm()
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
form.save()
return redirect("blog_page", pk=blog.pk)
return render(request, "...", {"blog": blog, "form": form})
Good afternoon all,
One of my form does not seem to save when submitted. I cannot see why, in particular as I have a similar form working just fine using the same code.
For some reason it work just fine using the admin panel.
My assumption is that I am missing something that tells the form it needs to be saved. But cannot find what.
Any ideas?
Models
RATING=(
(1,'1'),
(2,'2'),
(3,'3'),
(4,'4'),
(5,'5'),
)
class ProductReview(models.Model):
user=models.ForeignKey(User, on_delete=models.CASCADE)
product=models.ForeignKey(Product,related_name="comments", on_delete=models.CASCADE)
review_text=models.TextField(max_length=250)
review_rating=models.IntegerField(choices=RATING,max_length=150, default=0)
date_added = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now_add=True)
Views
def add_review(request, product_id):
product = Product.objects.get(pk=product_id)
form = ReviewAdd(request.POST or None, instance=product) #instance=product (populate field with existing information)
if form.is_valid():
form.save()
return redirect('product')
return render(request, 'main/add_review.html',{'form':form})
URL
from django.urls import path
from . import views
urlpatterns = [
...
path('product/add_review/<product_id>', views.add_review,name="add_review"),
]
Forms
class ReviewAdd(forms.ModelForm):
class Meta:
model = ProductReview
fields = ('review_text', 'review_rating')
labels ={
'review_text': '',
'review_rating': '',
}
widgets = {
'review_text': forms.TextInput(attrs={'class':'form-control', 'placeholder':'Enter Review'}),
}
Admin
from django.contrib import admin
from .models import Venue, User, Product, ProductReview
from django.urls import path
admin.site.register(User)
admin.site.register(ProductReview)
class ProductReview(admin.ModelAdmin):
list_display=['user','product','review_text','get_review_rating']
HTML Page
{% extends 'main/base.html' %}
{% load crispy_forms_tags %}
{% block title %}
{% endblock %}
{% block content %}
<center>
<h1>Add ReviewTo Database</h1>
<br/><br/>
{% if submitted %}
Success!
{% else %}
<form action="" method="post">
{% csrf_token %}
{{ form|crispy }}
<input type="Submit" value="Submit" class="btn btn-secondary">
</form>
{% endif %}
</center>
{% endblock %}
I detect 2 fixes
On your url, the parameter product_id might need the type of data it will going to receive
path('product/add_review/<int:product_id>', views.add_review,name="add_review"),
And in your view, you are sending an instance, and no data for a new rating.
In your view:
from django.contrib.auth.decorators import login_required
from django.shortcuts import get_object_or_404
#login_required
def add_review(request, product_id):
product = get_object_or_404(Product, pk=product_id)
form = ReviewAdd(request.POST or None)
if form.is_valid():
new_rating = form.save(commit=False)
new_rating.product = product
new_rating.user = request.user
new_rating.save()
return redirect('product')
return render(request, 'main/add_review.html',{'form':form})
In my app, I have created a context_proccessors.py to show the form to base.html file.
I am able to show the form in the base.html file. But the problem I am facing is I have no idea how to save that form data from base.html since there is no view for the base.html. Below is my code:
models.py
class Posts(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='user_posts')
post_pic = models.ImageField(upload_to='post_pic', verbose_name="Image")
post_caption = models.TextField(max_length=264, verbose_name="Caption")
created_date = models.DateTimeField(auto_now_add=True)
edited_date = models.DateTimeField(auto_now=True)
def __str__(self):
return f"{self.user.username}"
forms.py
from django import forms
from post_app.models import Posts
class PostForm(forms.ModelForm):
class Meta:
model = Posts
exclude = ('user',)
context_proccessors.py
from post_app.forms import PostForm
def post_form(request):
form = PostForm
return {
'post_form': form,
}
base.html
<form method="POST" enctype="multipart/form-data">
{{ post_form|crispy }}
{% csrf_token %}
<button type="submit" class="btn btn-primary">Post</button>
</form>
I want the form to be displayed on every page so that the user can submit data from anywhere
def PostView(request):
form = PostForm()
if request.method == 'GET':
return render(request, 'base.html', {form:form})
elif request.method == 'POST':
form.save(request.data)
In the views.py of your app you can define this view, and the you have to provide it an url in the urls.py of the root directory. So evere time there is a request on that url, if the method is GET, the form will be rendered on base.html file, if the method is POST, the post will be saved.
By following the answer by N T I have implemented this. So, I had to make a URL pattern for the view and use that URL pattern in the action in the form of base.html.
view.py
#login_required
def postsaveview(request):
form = PostForm()
if request.method == 'POST':
form = PostForm(request.POST, request.FILES)
if form.is_valid():
user_obj = form.save(commit=False)
user_obj.user = request.user
user_obj.slug = str(request.user) + str(uuid.uuid4())
user_obj.save()
return HttpResponseRedirect(reverse('profile_app:profile'))
urls.py
urlpatterns = [
path('post-save/', views.postsaveview, name='post-save'),
]
base.html
<form action="{% url "post-save" %}" method="POST" enctype="multipart/form-data">
{{ post_form|crispy }}
{% csrf_token %}
<button type="submit" class="btn btn-primary">Post</button>
</form>
Not able to upload image in Django Model.
I have installed Pillow , added MEDIA_URL and MEDIA_ROOT to my settings, added
static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) to my urls.py .
forms.py:
class PostForm(forms.ModelForm) :
class Meta :
model = Post
fields = ['name', 'image', 'description', 'age', 'cost', 'address', 'seller', 'phone', ]
post_edit.html:
{% extends 'blog/base.html' %}
{% block content %}
<h2>New post</h2>
<form method="POST" class="post-form">{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="save btn btn-default">Save</button>
</form>
{% endblock %}
models.py:
image = models.ImageField(upload_to='images/', null=True, blank=True)
urls.py:
path('edit/', views.post_edit, name='post_edit'),
views.py:
#login_required
def post_edit(request, pk) :
post = get_object_or_404(Post, pk=pk)
if request.method == "POST" :
form = PostForm(data=request.POST, files=request.FILES, instance=post)
if form.is_valid() :
post = form.save(commit=False)
post.save()
return redirect('post_detail', pk=post.pk)
else :
form = PostForm(instance=post)
return render(request, 'blog/post_edit.html', {'form' : form})
If I add an image to a new object , the image is not uploaded to media/images/ .
With my modest level of understanding ,I'm not able to find the mistake . Can anyone help me please?
You need to add enctype="multipart/form-data" form attribute to your template:
<form method="POST" class="post-form" enctype="multipart/form-data">{% csrf_token %}
From the doc:
Note that request.FILES will only contain data if the request method
was POST and the that posted the request has the attribute
enctype="multipart/form-data"
model.py
class Venue(models.Model):
venue_Name = models.CharField(max_length=100)
place = models.CharField(max_length=50)
rent = models.IntegerField()
parking_area = models.IntegerField()
class Decoration(models.Model):
rate = models.IntegerField()
I have printed the values in database as radio buttons what i want to do is that i want to get the total sum i.e venue.rent + decoration.rate and print it in another page What shoud i give in form action I'm not that familiar with forms.
html
<form action="{% %}" method="post">
{% for venue in venues %}
<input type="radio" name=venue value=venue.rent />{{ venue.venue_Name}}
{% endfor %}
{% for decoration in decorations %}
<input type="radio" name=decor value=decoration.rate />{{ decoration.rating }}
{% endfor %}
<input type="submit" value=" " />
</form>
what should i write in view and urls to get the sum
You can use Django's form for validation and parsing. For that you would set up a form like so:
forms.py
from django import forms
class TotalSumForm(forms.Form):
venue = forms.ModelChoiceField(queryset=Venue.objects.all(), required=True)
decoration = forms.ModelChoiceField(
queryset=Decoration.objects.all(), required=True)
def get_total(self):
# send email using the self.cleaned_data dictionary
return self.cleaned_data['venue'].rent +\
self.cleaned_data['decoration'].rate
And then using a class based view, add the result to context upon submission.
views.py
from myapp.forms import TotalSumForm(
from django.views.generic.edit import FormView
class TotalCost(FormView):
template_name = 'your_template.html'
form_class = TotalSumForm
success_url = '/thanks/'
def form_valid(self, form):
# This method is called when valid form data has been POSTed.
total_result = form.get_total()
# return back to your_template.html with the total in context
return self.render_to_response(self.get_context_data(
form=form, total=total_result))
The urls are pretty simple:
urls.py
from django.conf.urls import patterns, url
import myapp.views
urlpatterns = patterns(
'',
url(r'^total_calc/$', myapp.views.TotalCost.as_view(), name='calculate_total'),
)
Your html could be modified like so
your_template.html
<html>
<body>
<h1>TEST SUCCESFULL!</h1>
{% if total %}
<p>Total cost for venue and decoration: {{ total }}</p>
{% endif %}
<form action="{% url 'calculate_total' %}" method="post">
{{ form.as_p }}
<input type="submit" value="Calculate Total" />
</form>
</body>
</html>