ImageField doesn't work when creating the ModelForm - django

models.py
from PIL import Image
class Award_list(models.Model):
award_id=models.AutoField(primary_key=True)
award_name=models.CharField(max_length=50,blank=False)
award_image = models.ImageField(upload_to='award_pics',default='award.jpg')
def __str__(self):
return f'{self.award_name} award'
def save(self,*args,**kwargs):
super().save(*args,**kwargs)
img = Image.open(self.award_image.path)
if img.height > 300 or img.width > 300:
output_size = (300, 300)
img.thumbnail(output_size)
img.save(self.award_image.path)
class Meta:
verbose_name_plural = 'Award'
forms.py
from django import forms
from movies_list.models import Award_list
class Create_Award_list_form(forms.ModelForm):
class Meta:
model=Award_list
fields=['award_name','award_image']
views.py
from .models import Award_list
from .forms import Create_Award_list_form
def Award_list_create(request):
form=Create_Award_list_form(request.POST,request.FILES or None)
if form.is_valid():
# print(request.POST['award_name'])
form.save()
else:
print(form.errors)
context={
"hell":'sanjeet',
"form":form
}
return render(request,'movies_list/award_list_create.html',context)
urls.py
urlpatterns = [
path('movies/awards/new/',Award_list_create,name="award-list-create"),
]
award_list_create.html
{% extends "users/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">Blog Post</legend>
{{form.as_p}}
{{hell}}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Submit</button>
</div>
</form>
</div>
{% endblock content %}
This all line of code work all fine with admin page and selecting image save into MEDIA_URL/awards_pics file but when i create a models based forms it select the default option even after selecting the image in .html form.

<form method="POST" enctype="multipart/form-data">
add enctype="multipart/form-data" in the form tag so you can upload images from the html

Related

Django upload multiple images with one input Method Not Allowed (POST): /images/

HI I have just built an HTML-form in which the user can upload multiple images but I am getting Method Not Allowed (POST): /images/ all the time. In the image_list.html the images should be shown.
Thanks for your help
models.py
class ImageModel(models.Model):
images = models.ImageField(upload_to='products/')
forms.py
class ImageForm(ModelForm):
class Meta:
model = ImageModel
fields = ['images']
widgets = {
'images': FileInput(attrs={'multiple': True}),
}
views.py
class ImageFormView(FormMixin, TemplateView):
template_name = 'image_form.html'
form_class = ImageForm
def form_valid(self, form):
# Save the images to the database
form.save()
# Redirect to the image list view
return redirect('image_list')
class ImageListView(ListView):
model = ImageModel
template_name = 'image_list.html'
context_object_name = 'images'
image_form.html
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary">Submit
</form>
image_list.html
{% load static %}
{% for image in images %}
<img src="{{image.images.url}}" alt="">
{% endfor %}
urls.py
urlpatterns = [
path('images/', views.ImageFormView.as_view(), name='image_form'),
path('', views.ImageListView.as_view(), name='image_list'),
]
You need to close button tag at HTML form
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary">Submit</button>
</form>

Django "ImageField" form value is None

I'm trying to implement profile picture field for users. The following is the code for each file for the implementation I tried, forms.py, models.py, views.py, and urls.py.
I use a IDE (vscode) to debug django, and I placed a breakpoint on the user.avatar = form.cleaned_data['avatar'] line in views.py below, to quickly check if cleaned_data['avatar'] is filled as user input, as I expect.
However, even after I upload a file on the url, submit, the line shows None while expected a image object, and of course it doesn't save anything so no change to the database either.
#
# forms.py
# accounts/forms.py
#
from accounts.models import UserProfile
# ..
class UserProfileForm(forms.ModelForm):
avatar = forms.ImageField(label=_('Avatar'))
class Meta:
model = UserProfile
fields = [
'avatar',
]
def __init__(self, *args, **kwargs):
super(UserProfileForm, self).__init__(*args, **kwargs)
self.fields['avatar'].required = False
#
# models.py
# accounts/models.py
#
from django.contrib.auth.models import User
from PIL import Image
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
avatar = models.ImageField(upload_to="images", blank=True, null=True)
# note: I also did "python manage.py makemigrations accounts; python manage.py migrate accounts;"
#
# views.py
# accounts/views.py
#
class UserProfileView(FormView):
template_name = 'accounts/profile/change_picture.html'
form_class = UserProfileForm
def form_valid(self, form):
user = self.request.user
user.avatar = form.cleaned_data['avatar']
user.save()
messages.success(self.request, _('Profile picture has been successfully updated'))
return redirect('accounts:change_profile_picture')
#
# urls.py
# accounts/urls.py
#
from .views import UserProfileView
urlpatterns = [
# ..
path('change/profile_picture/', UserProfileView.as_view(), name='change_profile_picture'),
]
What is wrong with the code? Thanks.
edit
as requested, the html accounts/profile/change_picture.html
{% extends 'layouts/html.html' %}
{% load static %}
{% load bootstrap4 %}
{% load i18n %}
{% block content %}
{% include 'head.html' %}
<body>
{% include 'navbar.html' %}
<div id="content" name="content" class="main container">
<div class="w-100 p-3"></div>
<h2>{% trans 'Change profile picture' %}</h2>
<form method="post">
{% csrf_token %}
{% bootstrap_form form %}
<button class="btn btn-success">{% trans 'Change' %}</button>
</form>
<div class="w-100 p-3"></div>
</div>
{% include 'footer.html' %}
</body>
{% endblock %}
Add enctype="multipart/form-data" to the form:
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{% bootstrap_form form %}
<button class="btn btn-success">{% trans 'Change' %}</button>
</form>

Django UpdateView not loading forms with styles

I created a form using Django's UpdateView class, however, when the form loads it seems like the text boxes and text areas are not styled (looks like form.as_p style). Here is an example of exactly what I did.
Views.py
class UpdatePostView(UpdateView):
template_name = 'Post/UpdatePost.html'
model = Post
fields = ['Title', 'Body']
success_url = reverse_lazy('BlogApp:main')
def form_valid(self, form):
form.instance.Title = form.cleaned_data['Title']
form.instance.Body = form.cleaned_data['Body']
form.instance.save()
return super().form_valid(form)
Here is how I loaded the form in UpdatePost.html:
<form id="UpdatePostForm" method="POST">
{% csrf_token %}
<div class="form-group">
<label for="PostTitle">{{form.Title.label}}</label>
{{form.Title}}
</div>
<div class="form-group">
<label for="PostBody">{{form.Body.label}}</label>
{{form.Body}}
</div>
<input class="btn btn-primary" type="submit" for="UpdatePostForm" value="Update">
</div>
</form>
If you use Bootstrap, you also can use django-crispy-forms (version for Bootstrap 4 https://github.com/django-crispy-forms/django-crispy-forms ,version for Bootstrap 5 - https://github.com/django-crispy-forms/crispy-bootstrap5). It is helpful to live DRY (Don't repeat yourself).
And then it will be something like(I use crispy-forms for Bootstrap 5):
pip install crispy-bootstrap5
INSTALLED_APPS = (
...
"crispy_forms",
"crispy_bootstrap5",
...
)
CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5"
CRISPY_TEMPLATE_PACK = "bootstrap5"
class UpdatePostView(UpdateView):
template_name = 'Post/UpdatePost.html'
model = Post
fields = ['Title', 'Body']
success_url = reverse_lazy('BlogApp:main')
def form_valid(self, form):
form.instance.Title = form.cleaned_data['Title']
form.instance.Body = form.cleaned_data['Body']
form.instance.save()
return super().form_valid(form)
template
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<h1 class="text-center">Update Post</h1>
<br />
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{form|crispy }}
<button class="btn btn-outline-primary">
Update
</button>
</form>
{% endblock content %}
Because by default the form.body and form.title render a html input, you can override the class attribut from your UpdateView like that :
def get_form(self, *args, **kwargs):
form = super(UpdatePostView, self).get_form(*args, **kwargs)
form.fields["Title"].widget.attrs["class"] = "form-group"
form.fields["Body"].widget.attrs["class"] = "form-group"
return form

Why don't my entries get saved in the database in Django?

The post requests from the frontend do not get saved in the database, without any error shown. However, when I manually add entries from the admin panel, it shows on the frontend.
My index.html(form part):
<form class="main__input--form" method="POST">
{% csrf_token %}
<p class="main__input--text">
<textarea name="content" id="content" class="main__input--content" cols="35" rows="8" aria-label="Entry content" placeholder="Enter text here..."></textarea>
</p>
<button class="main__input--submit" type="submit">Vent</button>
</form>
My extension of index which loops through the database entries:
{% for obj in all_vents %}
<div>
<h1>{{obj.vent}}</h1>
</div>
<br />
{% endfor %}
My models.py:
class Vents(models.Model):
vent = models.CharField(max_length=10000)
def __str__(self):
return self.vent
My forms.py:
from django import forms
from .models import Vents
class VentForm(forms.ModelForm):
class Meta:
model = Vents
fields = ['vent']
My views.py:
from django.shortcuts import render, redirect
from .forms import VentForm
from .models import Vents
def ventout(request):
if request.method == "POST":
form = VentForm(request.POST or None)
if form.is_valid():
form.save()
return redirect("ventout")
else:
all_vents = Vents.objects.all()
return render(request, "ventout.html", {"all_vents": all_vents})
Views:
def ventout(request):
all_vents = Vents.objects.all()
if request.method == "POST":
form = VentForm(request.POST or None)
if form.is_valid():
form.save()
return redirect("ventout")
else:
form = VentForm()
context = {"all_vents": all_vents, "form":form}
return render(request, "ventout.html", context)
Template:
<form class="main__input--form" method="POST">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="main__input--submit">Vent</button>
</form>
you could install/use "crispy_forms_tags" to make the form look better,
https://django-crispy-forms.readthedocs.io/en/latest/index.html
if you want to go further you could install/use "widget_tweaks"
https://pypi.org/project/django-widget-tweaks/
Your index.html from part should have {{ form }} form tag, as I guess.
Try Using following code
<form class="main__input--form" method="POST">
{% csrf_token %}
{{ form }}
<p class="main__input--text">
<textarea name="content" id="content" class="main__input--content"
cols="35" rows="8" aria-label="Entry content" placeholder="Enter text here...">
</textarea>
</p>
<button class="main__input--submit" type="submit" value="Submit">Vent</button>
</form>

I can't post in Django

I can't post in Django, because when I import an image it doesn't work for me. it tells me that there's no file selected but I selected one.
This is the post model that I created, models.py file:
class Post(models.Model):
publisher = models.ForeignKey(User,on_delete=models.CASCADE)
caption = models.CharField(max_length=100)
date_created = models.DateTimeField(default=timezone.now())
image = models.ImageField(upload_to="post_images")
def __str__(self):
return self.caption
here's the forms.py file for the Post model:
from django import forms
from .models import Post
class CreatePostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['caption','image']
here's the Publish function in views.py file which implements the logic for my publish feature:
#login_required
def Publish(request):
if request.method == "POST":
form = CreatePostForm(request.POST,request.FILES)
if form.is_valid():
form.publisher = request.user
form.save()
return redirect("home")
else:
form = CreatePostForm()
return render(request,"posts/publish.html",{
"form":form,
})
int the urls.py file:
from django.urls import path
from . import views
urlpatterns = [
path('publish/',views.Publish,name="publish"),
path('',views.home,name="home"),
]
and here's in html template:
{% extends "users/base.html" %}
{% load crispy_forms_tags %}
{% block title %}create{% endblock title%}
{% block content %}
<div class="container-fluid">
<div class="row">
<div class="col-sm-6 col-md-5 authentification">
<div class="form-header">
<h1>
publish
</h1>
</div>
<div class="form-body">
<form method="POST">
<fieldset class="form-group" enctype="multipart/form-data">
{% csrf_token %}
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button type="submit" class="btn btn-primary form-control">publish</button>
</div>
</form>
</div>
</div>
</div>
</div>
{% endblock content %}
the Django version used is 2.2 and the Python 3.8. and Windows 10 Pro
You should alter the .publisher attribute of the .instance wrapped in the form, not the form itself, so:
#login_required
def Publish(request):
if request.method == 'POST':
form = CreatePostForm(request.POST,request.FILES)
if form.is_valid():
form.instance.publisher = request.user
form.save()
return redirect('home')
else:
form = CreatePostForm()
return render(request,'posts/publish.html',{
'form': form,
})
Since you are submitting both files and data, you should specify the enctype=… attribute [mdn] in the <form>:
<form enctype="multipart/form-data" method="POST">
…
</form>
Note: Django's DateTimeField [Django-doc]
has a auto_now_add=… parameter [Django-doc]
to work with timestamps. This will automatically assign the current datetime
when creating the object, and mark it as non-editable (editable=False), such
that it does not appear in ModelForms by default.
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.