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)
Related
i am trying to assign a freelancer to a particular gig but it shows get() returned more than one Freelancers -- it returned 3!. I have tried getting the logged in freelancer to is trying to create the git like this freelancer = get_object_or_404(Freelancers, user=user) and before i save the form i assign the value like this new_form.creator = freelancer .
views.py
#login_required
def create_gig(request):
user = request.user
freelancer = get_object_or_404(Freelancers, user=user)
if request.method == "POST":
form = CreateGig(request.POST, request.FILES)
if form.is_valid():
new_form = form.save(commit=False)
new_form.user = request.user
new_form.creator = freelancer
new_form.slug = slugify(new_form.title)
new_form.save()
messages.success(request, f'Gig Created Successfully, Would be Live Soon')
return redirect('freelance:listings')
else:
form = CreateGig()
context = {
'form': form
}
return render(request, 'freelance/create.html', context)
models.py
class Gigs(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='gig_user')
creator = models.ForeignKey(Freelancers, on_delete=models.CASCADE, related_name='gig_creator')
title = models.CharField(max_length=1000, null=True, blank=True, verbose_name="Enter what you will do", default=" I will ")
In my code, it is getting a logged-in user instance and then creating the gig by assigning the freelancer to the created form.
#login_required
def create_gig(request):
freelancer = Freelancers.objects.get(user = request.user )
if request.method == "POST":
form = CreateGig(request.POST, request.FILES)
if form.is_valid():
new_form = form.save(commit=False)
new_form.creator = freelancer
new_form.slug = slugify(new_form.title)
new_form.save()
messages.success(request, f'Gig Created Successfully, Would be Live Soon')
return redirect('freelance:listings')
else:
form = CreateGig()
context = {
'form': form
}
return render(request, 'freelance/create.html', context)
You also don't need this line in your view:
new_form.user = request.user
Info: I want to upload multiple files while creating new customer. I want to use formset_factory for file update. when i try to submit the form i am getting this error CustomerFileFormFormSet object has no attribute save. can anybody tell me how tell me how can i update multiple files while adding new customer in database?
models.py
class FileData(models.Model):
"""Files Model"""
customer = models.ForeignKey(Customer, null=True, on_delete=models.SET_NULL, blank=True)
title = models.CharField(max_length=100)
file = models.FileField(upload_to='data', blank=True)
def __str__(self):
return self.title
views.py
def CustomerCreate(request):
"""Customer Create View"""
customer_form = CustomerForm()
customer_file = formset_factory(CustomerFileForm, extra=1)
if request.method == 'POST':
customer_form = CustomerForm(request.POST)
formset = customer_file(request.POST, request.FILES)
if customer_form.is_valid() and formset.is_valid():
customer = customer_form.save(commit=False)
customer.dealer = request.user
customer.save()
file = formset.save(commit=False)
file.customer = customer
file.save()
return redirect('/')
context = {
'customer_form': customer_form,
'formset': customer_file,
}
return render(request, "customer/customer-create.html", context)
This is the code which is work for me maybe it's good or not but it's working to save the formset_factory instance. i can use forloop for each formset and save...!
views.py
if customer_form.is_valid() and formset.is_valid():
customer = customer_form.save(commit=False)
customer.dealer = request.user
customer.save()
for form in formset:
# extract name from each form and save
title = form.cleaned_data.get('title')
docs = form.cleaned_data['doc']
file_data = FileData(title=title, doc=docs, customer=customer)
# save file data instance
file_data.save()
I have a form(EditProfileForm) which I created to edit the profile details. My issue is that whenever I go to the EditProfileForm page in the browser the fields are not filled with previous values which I gave while making the profile for the first time, I have to fill the entire form however if I make some change in the value then the change is being made successfully.
my Profile model:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(default='profile_pic.jpg', upload_to='profile_pictures')
location = models.CharField(max_length=100, blank=True, null=True)
bio = models.CharField(max_length=500, blank=True, null=True)
def __str__(self):
return self.user.username
my EditProfileForm in forms.py:
class EditProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ['image', 'location', 'bio']
my two views regarding profile and edit profile:
#login_required
def profile_page(request):
user = request.user
posts = Post.objects.filter(author=user)
posts_count = posts.count()
profile = Profile.objects.get(user=user)
return render(request, 'blog_app/profile.html', {'user': user, 'posts_count': posts_count, 'profile': profile})
def edit_profile(request, id):
profile = Profile.objects.get(id=id)
if request.method == 'GET':
form = EditProfileForm(request.FILES, instance=profile)
else:
form = EditProfileForm(request.POST, request.FILES, instance=profile)
if form.is_valid():
# deleting old uploaded image.
image_path = profile.image.path
if os.path.exists(image_path):
os.remove(image_path)
# the `form.save` will also update the newest image & path.
form.save()
return redirect('profile')
return render(request, 'blog_app/edit_profile.html', {'profile': profile, 'form': form})
my two urls about profile and edit profile:
path('profile', user_views.profile_page, name='profile'),
path('edit_profile/<int:id>', user_views.edit_profile, name='edit_profile')
By the way I used django signals to automatically create profile for the first time.
The way I work with ModelForm is:
form = EditProfileForm(request.POST or None, request.FILES or None, instance=profile)
I don't know what is actually the difference between these two statements:
form = EditProfileForm(request.POST or None, request.FILES or None, instance=profile)
and
form = EditProfileForm(request.FILES, instance=profile)
But, You can try with this.
You can replace the edit_profile(request, id) function with this:
def edit_profile(request, id):
profile = Profile.objects.get(id=id)
form = EditProfileForm(request.POST or None, request.FILES or None, instance=profile)
if request.method =='POST':
if form.is_valid():
# deleting old uploaded image.
image_path = profile.image.path
if os.path.exists(image_path):
os.remove(image_path)
# the `form.save` will also update the newest image & path.
form.save()
return redirect('profile')
return render(request, 'blog_app/edit_profile.html', {'profile': profile, 'form': form})
When I trying to save detail, I have this error: KeyError: 'image'. I can't understand, why? Error in views.py. I want to upload multiple photos at once
views.py:
#user_passes_test(lambda u: u.is_superuser)
def new_detail(request):
ImageFormSet = modelformset_factory(DetailImage,
form=ImageForm, extra=10)
if request.method == 'POST':
form = DetailForm(request.POST)
formset = ImageFormSet(request.POST, request.FILES,
queryset=DetailImage.objects.none())
if form.is_valid() and formset.is_valid():
detail_form = form.save()
detail_form.save()
for form in formset.cleaned_data:
images = form['image'] # HERE IS THE PROBLEM
photo = DetailImage(detail=detail_form, image=images)
photo.save()
return redirect('/new_detail/')
else:
form = DetailForm(request.POST)
formset = ImageFormSet(queryset=DetailImage.objects.none())
return render(request, 'shop/new_detail.html',
{'form': form,'formset': formset})
forms.py
...
class ImageForm(forms.ModelForm):
image = forms.ImageField()
class Meta:
model = DetailImage
fields = ('image',)
models.py
...
class DetailImage(models.Model):
detail = models.ForeignKey(Detail, related_name='images',
on_delete=models.CASCADE)
image = models.ImageField(upload_to='details', null = True, blank = True)
KeyError: 'image' in your case means that there is no 'image' key in one of the forms in your formset cleaned data. You should perform a check. Something like this:
for form in formset.cleaned_data:
if 'image' in form:
image = form['image']
photo = DetailImage(detail=detail_form, image=image)
photo.save()
I'm trying to make a simple image upload form, which works until I try to save the Model called User_Image using the posted data. The error I get is this: int() argument must be a string or a number, not 'QueryDict' and I receive it at the line marked *****. Thanks for the help.
models.py:
class User_Image(models.Model):
image = models.ImageField(upload_to="img")
user_profile = models.ForeignKey(UserProfile)
title = models.CharField(max_length=10)
forms.py:
class User_ImageForm(ModelForm):
class Meta:
model = User_Image
views.py:
def upload_image(request):
if request.method == 'POST':
HttpResponseRedirect("/accounts/profile")
form = User_ImageForm(request.POST, request.FILES)
if form.is_valid():
im = User_Image(request.POST, request.FILES)
******im = im.save()
HttpResponseRedirect("/accounts/profile")
else:
form = User_ImageForm()
return render_to_response('uploadimage.html', {'form':form}, context_instance=RequestContext(request))
Why are you saving it to the model class directly? Try:
form = User_ImageForm(request.POST, request.FILES)
if form.is_valid():
im = form.save()
HttpResponseRedirect("/accounts/profile")
You don't need to following lines.
im = User_Image(request.POST, request.FILES)
im = im.save()
Enough to save the form,
.....
if form.is_valid():
form.save()
HttpResponseRedirect("/accounts/profile")
.....