Django/Python: How to change filename when saving file using models.FileField? - django

I found this example to upload a file using FileField and it works great.
https://simpleisbetterthancomplex.com/tutorial/2016/08/01/how-to-upload-files-with-django.html
Problem is that it saves the original filename of the file being uploaded. I don't want that. I can change the filename within models.py by overriding the save function (see below). For the life of me, I cannot figure out how to pass a filename in when I execute form.save() from views.py. I need to know the filename for another process. I thought about even returning a filename from the models.py save function. I'm a bit of a noob so forgive any missing details. I've searched this site and read loads of documentation, but I'm missing something. Any advice would be appreciated.
Forms.py
class DocumentForm(forms.ModelForm):
message = forms.CharField(widget=forms.Textarea(attrs={'rows': 5, 'cols': 50}))
class Meta:
model = Document
fields = ('description', 'document', )
Models.py
class Document(models.Model):
description = models.CharField(max_length=255, blank=True)
document = models.FileField(upload_to='atlasapp/documents/')
uploaded_at = models.DateTimeField(auto_now_add=True)
def save(self, *args, **kwargs):
randomNum = random.randint(10000,90000)
new_name = str(randomNum) + ".txt"
self.document.name = new_name
super(Document, self).save(*args, **kwargs)
Views.py
def model_form_upload(request):
if request.method == 'POST':
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect('model_form_upload')
else:
form = DocumentForm()
return render(request, 'model_form_upload.html', {'form': form})

Could you perhaps call save() on the form with commit=False, set the name on the Document file, and then save the Document? For example:
def model_form_upload(request):
if request.method == 'POST':
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
document = form.save(commit=False)
document.name = 'some_new_name'
document.save()
return redirect('model_form_upload')
else:
form = DocumentForm()
return render(request, 'model_form_upload.html', {'form': form})

Related

how to upload multiple images properly

I have a simple model which has four different fileFields for uploading different files and images.
this is my models:
class DocumentInfo(models.Model):
id = models.AutoField(primary_key=True)
certificate = models.FileField(upload_to="documents", null=True)
id_card = models.FileField(upload_to="documents", null=True)
service_certificate = models.FileField(upload_to="documents", null=True)
educational_certificate = models.FileField(upload_to="documents", null=True)
users need to simply upload some images in four individual fields so, I created a simple form and passed it to views like this:
class DocumentForm(forms.ModelForm):
class Meta:
model = DocumentInfo
fields = ['certificate','id_card','service_certificate','educational_certificate']
views.py:
def document_info(request):
if request.method == 'POST':
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
form.instance.user = request.user
form.save()
return redirect('document')
if 'delete' in request.GET:
return delete_item(DocumentInfo, request.GET['id'])
else:
form = DocumentForm()
documents = DocumentInfo.objects.filter(user=request.user)
context = {
'form': form,
'documents': documents,
}
return render(request, 'reg/documents.html', context)
it works just fine at first but I cant reupload anything! the uploaded image neither gets saved the second time around nor deleted. what am I doing wrong?
try this.
views.py
def document_info(request):
documents = DocumentInfo.objects.filter(user=request.user).order_by('-pk')
if request.method == 'POST':
if documents:
form = DocumentForm(request.POST, request.FILES,instance=documents[0])
else:
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
if not documents:
form.instance.user = request.user
form.save()
return redirect('document')
else:
if documents:#if the user already has a document.
form = DocumentForm(instance=documents[0])
else:
form = DocumentForm()
context = {
'form': form,
'documents': documents,
}
return render(request, 'reg/documents.html', context)

Django. Populate user name or ID when user saving a model from web pages

My UserImg Model has a user field that has editable=False.
I want this field to be automatically filled in with the user name when the user is saved from web page.
model.py
def upload_myimg_path(instance, filename):
return 'documents/{0}/{1}'.format(instance.created_by.username, filename)
class UserImg(models.Model):
user = models.ForeignKey(User, verbose_name=_('Created by'), on_delete=models.CASCADE, editable=False, null=True, blank=True)
name = models.CharField(max_length=100, default='')
image = models.ImageField(upload_to=upload_myimg_path, verbose_name=_('File'))
def __str__(self):
return str(self.user)
forms.py
class UserImgForm(forms.ModelForm):
class Meta:
model = UserImg
fields = '__all__'
views.py
def createuserimg(request):
if request.method == 'POST':
form = UserImgForm(request.POST or None)
if form.is_valid():
form.save()
return redirect('/accounts/users')
else:
return redirect('/accounts/')
else:
form = UserImgForm
return render(request, 'accounts/user_form.html', {'form': form})
Update your view function to include current logged in user and make use of #login_required decorator to ensure that only logged in users can access this view :
from django.contrib.auth.decorators import login_required
#login_required
def createuserimg(request):
if request.method == 'POST':
form = UserImgForm(request.POST, request.FILES)
if form.is_valid():
obj = form.save(commit=False) # <-- commit=False does not save to database
obj.user = request.user # <-- this allows you to specify the user for your post
obj.save()
return redirect('/accounts/users')
# if the form did not validated, stay on the same page to display errors to your user
else:
form = UserImgForm()
return render(request, 'accounts/user_form.html', {'form': form})
correct answer commit=False allows you to modify the resulting object before it is actually saved to the database. It`s works for me.
Thank you very much for your help
from django.contrib.auth.decorators import login_required
#login_required
def createuserimg(request):
if request.method == 'POST':
form = UserImgForm(request.POST, request.FILES)
if form.is_valid():
link = form.save(commit=False)
link.user = request.user
link.save()
return redirect('/accounts/users')
# if the form did not validated, stay on the same page to display errors to your user
else:
form = UserImgForm()
return render(request, 'accounts/user_form.html', {'form': form})

Django formset: Unable to save

Trying to setup simple formset, but getting errors
'SWDataForm' object has no attribute 'save'
MODEL
class SWData(ValidateOnSaveMixin, models.Model):
model_serial = models.ForeignKey(SWInfo, related_name='serial_items', on_delete=models.SET_NULL, null=True)
hostname = models.CharField(max_length=20, default='', unique=True)
deployed = models.BooleanField()
class Meta:
verbose_name_plural = "SWDATA"
def __str__(self):
return "{0}".format(self.hostname)
VIEW
def display_data(request, data, **kwargs):
return render(request, 'web/posted-data.html', dict(data=data, **kwargs))
def swdata(request, *args, **kwargs):
template = 'web/swdata.html'
SWDataFormset = modelformset_factory(SWData, fields=('__all__'), extra=1)
formset = SWDataFormset(request.POST or None)
if request.method == 'POST':
print(formset.is_valid())
if formset.is_valid():
pprint(formset)
for form in formset.forms:
if form.is_valid():
try:
if form.cleaned_data.get('DELETE') and form.instance.pk:
form.instance.delete()
else:
instance = form.save(commit=False)
#instance.model_serial = model_serial
#print (instance.model_serial)
instance.save()
messages.success(request, "Successfully")
except formset.DoesNotExist:
messages.error(request, "Database error. Please try again")
#data = form.cleaned_data
#return display_data(request, data)
else:
formset = SWDataFormset(request.POST or None)
return render(request, template, {'formset': formset})
Remove the form and used the modelformset_factory, I was able to save only the last entry in the formset. How to loop thru each formset prefix and save each item?
I think that you are trying to save data form from a form, and you can't do that. You need to use the method create of your model. Something like SWDData.objects.create(form).
remove this line
instance = form.save(commit=False)
this line is needed when you wants to edit the form.
Now check if it works
Even I also got similar Problem

IntegrityError:duplicate key value violates unique constraint "login_account_userprofile_user_id_key"

IntegrityError comes when user uploading the profile pic, on form.save() it gives error, here is the code (" ` " it is uses for formality at last of line)
models.py
class UserProfile(models.Model):
user = models.OneToOneField(User)`
image = models.FileField(upload_to ="profile_image")`
def __str__(self):
return self.user.username`
forms.py
class ProfilePicForm(ModelForm):
class Meta:
model = UserProfile
fields = ("image",)`
view.py
def profile_pic(request):
if request.method =="POST":
form = ProfilePicForm(request.POST, request.FILES)
if form.is_valid():
form.instance.user =request.user
form.save()
return redirect('/login/profile')
else:
args = {'form': ProfilePicForm()}
return render(request, 'login_account/profile_pic.html',args)`
You should probably try the following:
user = UserProfile(user=request.user)
form = ProfilePicForm(request.POST, request.FILES, instance=user)
if form.is_valid():
form.save()

Django - How to Save ImageField Even if Form is Not Valid

I have a fairly standard model and form. I have some mandatory fields with an ImageField. When the user choose an image and doesn't field the mandatory fields, the image isn't saved and the user needs to 're-upload' it again.
As the row in the database already exists (because this form is part of a 'wizard'), I don't mind saving the picture in the database even if all the form isn't valid with all the mandatory data.
This is what I have right now in my view, which works when you fill all the mandatory fields:
def my_view(request):
instance = MyModel.objects.get(user=request.user)
form = MyForm(instance=instance)
if request.POST:
form = MyForm(request.POST, request.FILES, instance=instance)
if form.is_valid():
new_instance = form.save(commit=False)
if request.FILES and request.FILES['photo']:
uploaded_photo = request.FILES['photo']
new_instance.photo = uploaded_photo
new_instance.save()
return HttpResponseRedirect(reverse('new_url'))
return render_to_response('current_template.html', locals(), context_instance=RequestContext(request))
Here's what I tried to save the picture in DB even if the other fields aren't filled, but I get the error Django Upload Error - Upload a valid image (either not an image or corrupted):
def my_view(request):
instance = MyModel.objects.get(user=request.user)
form = MyForm(instance=instance)
if request.POST:
form = MyForm(request.POST, request.FILES, instance=instance)
if request.FILES and request.FILES['photo']:
uploaded_photo = request.FILES['photo']
instance.photo = uploaded_photo
instance.save()
if form.is_valid():
new_instance = form.save()
return HttpResponseRedirect(reverse('new_url'))
return render_to_response('current_template.html', locals(), context_instance=RequestContext(request))
Here's my form (fairly simple):
class MyForm(ModelForm):
first_name = forms.CharField(label='First Name', max_length=50, required=True)
last_name = forms.CharField(label='Last Name', max_length=50, required=True)
photo = forms.ImageField(required=False)
def __init__(self, *args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs)
class Meta:
model = MyModel
fields = ('first_name','last_name', 'photo')
Here's my model (again very simple):
class MyModel(models.Model):
first_name = models.TextField(max_length=50)
last_name = models.TextField(max_length=50)
photo = ImageField(upload_to=get_photo_path,null=True,blank=True)
This is how I made it work. Notice that there's no 'request.FILES' as a parameter for the constructor of the form in the 'else' when the form is not valid. This is what made Django display the error message.
if form.is_valid():
instance = form.save(commit=False)
if request.FILES and request.FILES['photo']:
instance = save_photo(instance, request.FILES['photo'])
instance.save()
return HttpResponseRedirect(reverse('url'))
else:
if request.FILES and request.FILES['photo']:
instance = save_photo(instance, request.FILES['photo'])
form = InstanceForm(request.POST, instance=instance)