how to fix Form validation 'unknow' in django - python

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">

Related

Error: Django model form data not being saved in the database

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>

Reason for form not showing although I added it in the template

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

Django 2 request.POST not saving to database with instance=request.user

I have a form where a user can submit some text, which then gets saved to the model TextSubmission.
However, it only saves when I take out instance=request.user from views.py and it does not save with the instance of the user who submitted it.
If I leave instance=request.user in, the request.POST object does not get saved but does get posted. (I can see from print(request.POST)
Can someone help me figure out why this is and how to get the text to save along with the user?
models.py
class TextSubmission(models.Model):
text_submission = models.CharField(max_length=50, null=True, blank=True)
user = models.OneToOneField(User, on_delete=models.CASCADE)
class Meta:
ordering = ['text_submission']
def __str__(self):
return self.text_submission
forms.py
class TextSubmissionForm(forms.ModelForm):
class Meta:
model = TextSubmission
fields = ['text_submission']
views.py
def profile_view(request):
if request.method == 'POST':
p_form = ProfileUpdateForm(request.POST, instance=request.user)
t_form = TextSubmissionForm(request.POST, request.FILES, instance=request.user.profile)
if p_form.is_valid() and t_form.is_valid():
p_form.save()
t_form.save()
messages.success(request, f'Your account has been updated!')
return redirect('profile')
else:
p_form = ProfileUpdateForm(instance=request.user.profile)
t_form = TextSubmissionForm(instance=request.user.textsubmission)
context = {
'p_form': p_form,
't_form': t_form,
}
return render(request, 'profile.html', context)
profile.html
<form method="POST" enctype="multipart/form-data">
<div class="profile-form">
{{ p_form }}
{{ t_form }}
</div>
<button type="submit" value="submit">Update Profile</button>
</form>
You're passing the TextSubmission form an instance of User, when you want to be passing it an instance of TextSubmission. Try
try:
t_form = TextSubmissionForm(request.POST, instance=request.user.textsubmission)
except TextSubmission.DoesNotExist:
t_form = TextSubmissionForm(request.POST)
Override the __init__() method and save() method of the form as
class TextSubmissionForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user')
super().__init__(*args, **kwargs)
def save(self, commit=True):
self.instance.user = self.user
return super().save(commit)
class Meta:
model = TextSubmission
fields = ['text_submission']
Then, in your views,
def profile_view(request):
if request.method == 'POST':
u_form = UserUpdateForm(request.POST) # change is here
t_form = TextSubmissionForm(request.POST, user=request.user) # change is here
if u_form.is_valid() and t_form.is_valid():
u_form.save()
t_form.save()
messages.success(request, f'Your account has been updated!')
return redirect('profile')
else:
u_form = UserUpdateForm() # change is here
t_form = TextSubmissionForm() # change is here
context = {
'u_form': u_form,
't_form': t_form,
}
return render(request, 'profile.html', context)
Reference
Passing a user, request to forms
The instance require the instance of the referenced model in form definition. In your case it is TextSubmission, so you have first get object of this model and then pass it to the TextSubmissionForm
user = User.objects.get(id = request.user)
txtSubmsn = TextSubmission.objects.get(user)
u_form = TextSubmissionForm(instance=txtSubmsn)
Same case for UserUpdateForm

Django model formset factory and forms

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.

Save Uploaded Image to exisitng Model in Django

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})

Categories

Resources