I am using a Form to Upload a picture via dropzone.js. The picture gets saved and uploaded fine. But it's creating a new model with empty fields.. I want to save the picture to that existing model I'm referencing to. But I can't seem to find a solution to reference it. Here's my code:
views.py (I guess the error is in here)
def client_view(request, pk):
client = get_object_or_404(Client, pk=pk)
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
picture = form.save()
else:
form = UploadFileForm()
data = {'form': form}
return render_to_response('client_view.html', locals(), RequestContext(request), {"img": picture})
return render(request, 'client_view.html', {'client': client})
urls.py
url(r'^client/(?P<pk>\d+)/$', client_view, name='client_view'),
forms.py
class UploadFileForm(forms.ModelForm):
class Meta:
model = Client
fields = ('image',)
models.py
class Client(models.Model):
customer_nr = models.IntegerField(null=True)
last_name = models.CharField(max_length=30, null=True)
first_name = models.CharField(max_length=30, null=True)
birthdate = models.DateField(null=True)
address = models.CharField(max_length=50, null=True)
image = models.ImageField("Image", upload_to='files/%Y/%m', null=True, blank=True)
client_view.html
<form action="{% url 'client_view' pk=client.pk %}" class="dropzone" id="myDropzone">
{% csrf_token %}
<div class="fallback">
<input name="file" type="file" multiple/>
</div>
</form>
<script type="text/javascript">
Dropzone.options.myDropzone = {
paramName: "image",
autoProcessQueue : true,
parallelUploads: 1,
init: function() {
this.on("success", function(file, responseText) {
console.log(responseText);
});
}
};
</script>
Any help would be really appreciated! Thanks!
The Django specified way is to instantiate the ModelForm using an existing model:
In your views.py:
client = get_object_or_404(Client, pk=pk)
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES, client)
if form.is_valid():
picture = form.save()
else:
form = UploadFileForm(client)
For a POST request, this will automatically save the image to the correct model.
For a GET request, this will attach the image currently associated with the model, if any, to the form field before it is sent to be rendered on a browser.
In my opinion, don't use
form.save()
Because it is creating a new instance in the model. Rather I would like to suggest something like-
def client_view(request, pk):
client = get_object_or_404(Client, pk=pk)
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
client.image = form.cleaned_data.get('image', None)
picture = client.save()
else:
form = UploadFileForm()
data = {'form': form}
return render_to_response('client_view.html', locals(), RequestContext(request), {"img": picture})
return render(request, 'client_view.html', {'client': client})
Related
I'm trying to create a blog model but the form data is not being saved in the database after submitting the form.
views.py
def postsform(request):
if request.method == "POST":
form = BlogForm(request.POST)
if form.is_valid():
form.save()
return redirect('blog')
else:
form = BlogForm()
messages.warning(request, "Opps! Something went wrong.")
return render(request, 'blog/postform.html', {'form':form})
else:
form = BlogForm()
return render(request, 'blog/postform.html', {'form':form})
forms.py
from django_summernote.widgets import SummernoteWidget
class BlogForm(ModelForm):
class Meta:
model = BlogPost
widgets = {
'blog': SummernoteWidget(),
}
fields = ['title', 'featureImg', 'blog', 'meta_description', 'keyword', 'author']
models.py
class BlogPost(models.Model):
title = models.CharField(max_length=999)
featureImg = ProcessedImageField(upload_to = 'blog/', format='JPEG',options={'quality':60}, null=True)
slug = models.CharField(max_length=999, blank=True,null= True)
blog = models.TextField()
meta_description = models.TextField()
keyword = models.TextField()
author = models.CharField(max_length=255)
created_on = models.DateField(auto_now_add=True)
updated_on = models.DateField(auto_now=True)
def save(self, *args, **kwargs):
if BlogPost.objects.filter(title=self.title).exists():
extra = str(randint(1, 1000000))
self.slug = slugify(self.title) + "-" + extra
else:
self.slug = slugify(self.title)
super(BlogPost, self).save(*args, **kwargs)
html
<form method="POST">
{% csrf_token %}
{{form.as_p}}
<button type="submit">Publish</button>
</form>
I've tried finding where I made the mistake but couldn't find it. After submitting the form the warning message pops up and the form doesn't get submitted.
You should not construct a new form, since then it will not render the errors. Likely you did not pass request.FILES, and the enctype="…" [mdn-doc] is also missing in the <form> tag:
def postsform(request):
if request.method == 'POST':
form = BlogForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect('blog')
else:
# no new BlogForm
messages.warning(request, 'Oops! Something went wrong.')
else:
form = BlogForm()
return render(request, 'blog/postform.html', {'form': form})
and in the HTML form:
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{form.as_p}}
<button type="submit">Publish</button>
</form>
I have made a new Comment Model in my Django Project but the form is not showing in the browser although I added the form in the template.
Here is the models.py
class Comment(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
body = models.TextField(max_length=300)
def __str__(self):
return str(self.pk)
Here is the views:
def comment_create(request, self):
post = get_object_or_404(Post, slug=self.kwargs['slug'])
user = User.objects.get(user=request.user)
c_form = CommentModelForm()
context = {
'post': post,
'user': user,
'c_form': c_form,
}
return context
Here is the forms.py
class CommentModelForm(forms.ModelForm):
body = forms.CharField(label='',
widget=forms.TextInput(attrs={'placeholder': 'Add a comment...'}))
class Meta:
model = Comment
fields = ('body',)
Here is the urls.py
path('blogs/comment', comment_create, name='comment-post'),
Here is the template:
<form action="" method="POST"class='ui fluid form'>
{% csrf_token %}
<input type="hidden" name="post_id" value={{post.id}}>
{{ c_form }}
<button type="submit" name="submit_c_form" class="">Send</button>
</form>
First, you have to get the type of request, I added a if/else for GET and POST requests. Added form.is_valid check.
In your function you are trying to get a kwarg form the url but you don't have a kwarg in your path.
path('blogs/<slug:slug>/comment', comment_create, name='comment-post'),
views.py
def comment_create(request, self):
post = get_object_or_404(Post, slug=self.kwargs['slug'])
if request.method == 'POST': # If user submitted form
c_form = CommentModelForm(request.POST) # Get form response
if c_form.is_valid(): # Chekc if form is valid
c_form.user = User.objects.get(user=request.user) # Get user and add it to form
c_form.post = post # Add post to form
c_form.save() # Save form
else:
c_form = CommentModelForm() # Pass form
context = {
'post': post,
'c_form': c_form,
}
return render(request, 'app/comment.html', context) # change template
forms.py
class Meta:
model = Comment
fields = ['body'] # When I set tuples it normally gives me an error
When I use single form there is no problem but when I used multi-forms in a class based view it's getting validation failed with image field. I tried to fix with previous solution provided in stack overflow but couldn't able to solve it.
views.py
codes in views
class ProfileEditView(View):
profile_class = ProfileForm
profile_image_class = ProfileImageForm
template_name = 'user/profile_edit.html'
def get(self,request,pk):
if pk:
user = User.objects.get(pk=pk)
profile = Profile.objects.get(user = user)
profile_image = ProfileImage.objects.get(user = user)
profile_form = self.profile_class(instance = profile)
profile_image_form = self.profile_image_class(instance = profile_image)
context = {
'profile_form':profile_form,
'profile_image_form':profile_image_form
}
return render(request, self.template_name, context)
else:
profile_form = self.profile_class(None)
profile_image_form = self.profile_image_class(None)
context = {
'profile_form':profile_form,
'profile_image_form':profile_image_form
}
return render(request, self.template_name, context)
def post(self,request,pk=None, **kwargs):
profile_form = self.profile_class(request.POST,instance=Profile())
profile_image_form = self.profile_image_class(request.POST,instance=ProfileImage())
if profile_image_form.is_valid(): #and profile_image_form.is_valid():
profile = profile_form.save(commit=False)
profile_image = profile_image_form.save(commit=False)
profile.user = self.request.user
profile_image.user = self.request.user
profile.save()
profile_image.save()
return redirect('music:album_list')
context = {
'profile_form':profile_form,
'profile_image_form':profile_image_form,
'error_message':'Something went wrong',
}
return render(request, self.template_name, context)
models.py
codes in model
def get_profile_upload_to(instance,filename):
new_filename = '{}.{}'.format(uuid4,filename.split('.')[-1])
return "profile/{}/{}".format(instance.user.id, new_filename)
class ProfileImage(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE)
image = models.ImageField(upload_to=get_profile_upload_to)
uploaded = models.DateTimeField(auto_now=True)
class Profile(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE)
bio = models.TextField(max_length=500,null=True, blank=True)
location = models.CharField(max_length=50,null=True, blank=True)
birth_date = models.DateField(null=True, blank=True)
email_confirmed = models.BooleanField(default=False)
form.py
codes in form.py
class ProfileImageForm(forms.ModelForm):
class Meta:
model = ProfileImage
fields = ['image']
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ['birth_date']
profile_edit.html
code in html page.
<form method="post" enctype="multipart/form-data">{% csrf_token %}
{{error_message}}
{{profile_form}}
{{profile_image_form}}
<button type="submit">Submit</button>
</form>
Error code
when I print the form.is_valid I got below lines.don't know Why image field is validating false
[21/Oct/2019 08:24:24] "POST /user/profile/46/ HTTP/1.1" 200 2861
profile_form is : True
profile_image_form is : False
profile_form is : <bound method BaseForm.is_valid of <ProfileForm bound=True, valid=True, fields=(birth_date)>>
profile_image_form is : <bound method BaseForm.is_valid of <ProfileImageForm bound=True, valid=False, fields=(image)>>
There are quite a few things wrong here. For example, your profile_form doesn't even seem to be a form.
But your immediate error is that you're not passing the FILES data to the image form. It should be:
profile_image_form = self.profile_image_class(request.POST, request.FILES)
(Note there's no point passing an empty instance, just leave that out.)
Also make sure that in your template the form has the right enctype:
<form action="" method="post" enctype="mulitpart/form-data">
Hi everyone I am new to Django and I am going bald pulling my hair. Can someone help me with this.
I'm trying to add multiple images to my post and I am having issues. I have 2 models. One post model and One image model. My post model already has 1 imagefield. Then I have another related model which allows multiple images. Below is how my models look like
class Post(models.Model):
user = models.ForeignKey(User, related_name='posts')
title = models.CharField(max_length=250, unique=True)
slug = models.SlugField(allow_unicode=True, unique=True)
message = models.TextField()
post_image = models.ImageField()
class Image (models.Model): #(Images)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
image = models.ImageField(upload_to='images/', blank=True, null=True)
image_title = models.CharField(max_length=100)
image_description = models.CharField(max_length=250)
def __str__(self):
return self.post.title + " Image"
Below is how my views look like. When the form loads. It has the multiple image fields. Its just not saving those images when my post is created. I get a post that completely ignores the formsets and multiple images. It only shows the Post model aspects and 1 image of the Post model. Even in the Admin there are no multiple images.
Can someone point me to what is the error in my code?
VIEWS.py 1st try
#login_required
def post_create(request):
ImageFormset = modelformset_factory(Image, fields=('image', 'image_title', 'image_description'), extra=7)
if request.method == 'POST':
form = PostForm(request.POST, request.FILES)
formset = ImageFormset(request.POST or None, request.FILES or None)
if form.is_valid() and formset.is_valid():
post = form.save(commit=False)
post.user = request.user
post.save() ## It seems as if my code just plays till here and then disconnects
for f in formset:
try:
photo = Image(post=post, image=f.cleaned_data['image', 'image_title', 'image_description'])
photo.save()
return redirect('posts:single', username=request.user.username, slug=post.slug)
except Exception as e:
break
else: ## This part works too as it shows the correct empty form
form = PostForm()
formset = ImageFormset(queryset=Image.objects.none())
context = {'form': form, 'formset': formset}
return render(request, 'posts/post_form.html', context)
below is my forms.py
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ('title', 'message', 'post_image' )
Changed the views like user3054319 suggested see below. It works fine but saves only 1 image in the image folder. Is everything correct my indents
VIEWS.py 2nd try
#login_required
def post_create(request):
ImageFormset = modelformset_factory(Prep, fields=('image', 'image_title', 'image_description'), extra=7)
if request.method == 'POST':
form = PostForm(request.POST, request.FILES)
formset = ImageFormset(request.POST or None, request.FILES or None)
if form.is_valid() and formset.is_valid():
post = form.save(commit=False)
post.user = request.user
post.save()
for f in formset:
try:
photo = Prep(post=post, image=f.cleaned_data['image'], image_title=f.cleaned_data['image_title'],
image_description=f.cleaned_data'image_description'])
photo.save()
return redirect('posts:single', username=request.user.username, slug=post.slug)
except Exception as e:
break
Then I tried removing the try and except statement and getting the redirect outside the loop It saves all 7 images but in the end gives a error (see error image attached below)
VIEWS.py 3rd try
#login_required
def post_create(request):
ImageFormset = modelformset_factory(Prep, fields=('image', 'image_title', 'image_description'), extra=7)
if request.method == 'POST':
form = PostForm(request.POST, request.FILES)
formset = ImageFormset(request.POST or None, request.FILES or None)
if form.is_valid() and formset.is_valid():
post = form.save(commit=False)
post.user = request.user
post.save()
for f in formset:
photo = Prep(post=post, image=f.cleaned_data['image'], image_title=f.cleaned_data['image_title'], image_description=f.cleaned_data['image_description'])
photo.save()
return redirect('posts:single', username=request.user.username, slug=post.slug)
error image below
If this can be achieved by CBV I can add a video of me dancing like I won a lottery. but I won't get too greedy even a solution to this can save some hair on my head
I went through your post create view and found that you are trying to access multiple keys of a dictionary with one call which is f.cleaned_data[‘image’, ‘image_title’] which is syntactically wrong
If you print(f.cleaned_data) it will give dictionary and you should know how to access dictionary.
You must use
photo = Image(post=post, image=f.cleaned_data['image'], image_title=f.cleaned_data['image_title'])
Below are the correct Views.py thanks to user3054319
def post_create(request):
ImageFormSet = modelformset_factory(Images, fields=('image','image_title', 'image_description'), extra=7)
if request.method == "POST":
form = PostCreateForm(request.POST or None)
formset = ImageFormSet(request.POST or None, request.FILES or None)
if form.is_valid() and formset.is_valid():
instance = form.save(commit=False)
instance.author = request.user
instance.save()
print(formset.cleaned_data)
for f in formset.cleaned_data:
try:
photo = Images(post=instance, image=f['image'], image_title=f['image_title'], image_description=f['image_description'])
photo.save()
except Exception as e:
break
return redirect('posts:single', username=instance.user.username, slug=instance.slug)
else:
form = PostCreateForm()
formset = ImageFormSet(queryset=Images.objects.none())
context = {
'form': form,
'formset': formset,
}
return render(request, 'blog/post_create.html', context)
I'm trying to user Django model formset factory to render a template where a user can add images and change the images they have uploaded(very similar to what can be done in the admin). I currently can render the template and its correct fields to the template. What I cannot do is have the user preselected(want currently logged in) and when I refresh the page the image will be posted again(not sure if this is preventable). Below is my code. Thanks!
Model:
class Image(models.Model):
user = models.ForeignKey(User)
image = models.ImageField(upload_to=content_file_name, null=True, blank=True)
link = models.CharField(max_length=256, blank=True)
Form:
class ImageForm(forms.ModelForm):
image = forms.ImageField(label='Image')
class Meta:
model = Image
fields = ('image',
'link',
)
View:
#login_required
def register(request):
user_data = User.objects.get(id=request.user.id)
ImageFormSet = modelformset_factory(Image,
fields=('user', 'image', 'link'), extra=3)
if request.method == 'POST':
print '1'
formset = ImageFormSet(request.POST, request.FILES, queryset=Image.objects.all())
if formset.is_valid():
formset.user = request.user
formset.save()
return render(request, 'portal/register.html', {'formset': formset, 'user_data': user_data})
else:
print '2'
formset = ImageFormSet(queryset=Image.objects.all())
return render(request, 'portal/register.html', {'formset': formset, 'user_data': user_data})
Template:
<form id="" method="post" action=""
enctype="multipart/form-data">
{% csrf_token %}
{{ formset.management_form }}
{% for form in formset %}
{{ form }}
{% endfor %}
<input type="submit" name="submit" value="Submit" />
let me explain the way you can do it.
MODELS
from django.utils.text import slugify
from django.db import models
from custom_user.models import AbstractEmailUser
# User model
class UserModel(AbstractEmailUser):
full_name = models.CharField(max_length=255)
def __str__(self):
return str(self.id)
# Function for getting images from instance of user
def get_image_filename(instance, filename):
title = instance.id
slug = slugify(title)
return "user_images/%s-%s" % (slug, filename)
# Save images with user instance
class UserImages(models.Model):
user = models.ForeignKey('UserModel', db_index=True, default=None)
image = models.ImageField(upload_to=get_image_filename, verbose_name='Image', db_index=True, blank=True, null=True)
In forms it's a just a two form, one for model User, other for UserImages model.
# Images forms
class ImageForm(forms.ModelForm):
image = forms.ImageField(label='Image', required=False)
class Meta:
model = UserImages
fields = ('image',)
# User form
class UserForm(forms.ModelForm):
full_name = forms.CharField(required=True)
class Meta:
model = UserModel
fields = ('full_name','email','password',)
And in Views for post you can do something like this
# View
from models import *
from forms import *
#csrf_protect
def post_view(request):
template = 'some_template.html'
ImageFormSet = modelformset_factory(UserImages, form=ImageForm, extra=15)
if request.method == 'POST':
user_form = UserForm(request.POST, prefix='form1')
formset = ImageFormSet(request.POST, request.FILES, queryset=UserImages.objects.none(), prefix='form2')
if user_form.is_valid() and formset.is_valid():
# Save User form, and get user ID
a = user_form.save(commit=False)
a.save()
images = formset.save(commit=False)
for image in images:
image.user = a
image.save()
return HttpResponseRedirect('/success/')
else:
user_form = UserForm(prefix='form1')
formset = ImageFormSet(queryset=UserImages.objects.none(), prefix='form2')
return render(request, template, {'form_user':user_form,'formset':formset})
In template you are doing the right thing.