How to override FileField and automatically delete previous file in Django? - django

im django beginner (django 1.2.5)
I have that model:
class Document(models.Model):
file = models.FileField(upload_to='documents/%Y/%m/%d', null=True, blank=True)
title = models.CharField(max_length=30)
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
author = models.ForeignKey(User)
#other fields
#other fields
and model form to this:
class DocumentForm(ModelForm):
file = forms.FileField(required=True, error_messages={'required' : 'required!','empty': "empty!"})
title = forms.CharField(widget = forms.TextInput(attrs={'size': 93,}), error_messages={'required': 'required!'})
#other fields
#other fields
class Meta:
model = Document
exclude = ('author',)
def save(self, author, commit=True):
document=ModelForm.save(self,commit=False)
document.author = author
if commit:
document.save()
return document
I uploading new documents in using DocumentForm above and it works pretty but when i trying edit some document i cannot put new file in place previous. I may change every field except FileField.
def document_edit(request, document_id):
doc = get_object_or_404(Document, id=document_id)
form = DocumentForm(instance=doc)
if doc.author == request.user:
if request.method == "POST":
form = DocumentForm(request.POST, request.FILES, instance=doc)
if form.is_valid():
if request.POST.get('cancel'):
return HttpResponseRedirect('/')
elif request.POST.get('delete'):
document = Document.objects.get(id=document_id)
document.file.delete()
document.delete()
return HttpResponseRedirect('/')
else:
form.save(author=request.user)
return HttpResponseRedirect('/')
else:
# return again form with errors
else:
# return form with doc instance
else:
# return "you can't edit this doc!"
I research django documentation and i only know i should write some custom save method in some class but i completely have no idea how can i do this. It should be save() method in Document() or in DocumentForm()?
Generally i want this: When i put path to new file in form i want override this new file in his place and automatically delete previous file.
Can you help me? Thanks in advance!

You are on the right track, you just want to use the instance keyword, so your form reflects the object being edited. Simplified version:
def edit_upload(request, document_id):
doc = get_object_or_404(Document, id=document_id)
if request.method == 'POST': # If the form has been submitted...
form = DocumentForm(request.POST, request.FILES, instance=doc)
if form.is_valid(): # All validation rules pass
if doc.file: # If document has file already...
doc.file.delete() # delete it
form.save() # Saves object, uses new uploaded file
return redirect('/thanks/') # Redirect after success
else:
form = DocumentForm(instance=doc) # Show form to edit
return render(request, 'edit.html', {
'form': form,
})

Related

Adding a new field to django form

I am totally new in Django and I'm trying to use django forms for the first time. I have searched for this but I still haven't exactly found the answer. Basically I have a view like this:
def pay(request):
if request.method == 'POST':
form = PaymentForm(request.POST)
if form.is_valid():
# I have to calculate the checksum here
myModel = form.save()
else:
print form.errors
else: # The request is GET
form = PaymentForm()
return render_to_response('payment/payment.html', {'form':form})
and I want add an additional field, checksum to the form from the inputs I got from the form So when the user submits the entries the checksum should be added and added to the form and the form should be sent to an external server. But I don't know how to do that (I have defined checksum in my Model). Could anyone help me on this?
My model looks like this:
class PaymentModel(models.Model):
alphanumeric = RegexValidator(r'^[0-9a-zA-Z]*$', 'Only alphanumeric characters are allowed!')
secret_key = '6cd118b1432bf22942d93d784cd17084'
pid = models.CharField(primary_key=True, max_length=50, validators=[alphanumeric])
sid = models.CharField(primary_key=True, max_length=50, validators=[alphanumeric])
amount = models.DecimalField(max_digits=9, decimal_places=2)
success_url = 'http://localhost:8000/success'
cancel_url = 'http://localhost:8000/cancel'
error_url = 'http://localhost:8000/error'
checksum = 0
def calc_checksum(self):
checksumstr = "pid=%s&sid=%s&amount=%s&token=%s"% (self.pid, self.sid, self.amount, self.secret_key)
m = md5(checksumstr)
checksum = m.hexdigest()
return checksum
def __unicode__(self): #returns the unicode representation of the object
return self.name
and my form looks like this:
class PaymentForm(ModelForm):
class Meta:
model = PaymentModel
You can use the commit=False keyword argument to form.save():
def pay(request):
if request.method == 'POST':
form = PaymentForm(request.POST)
if form.is_valid():
# Will not save it to the database
myModel = form.save(commit=False)
# keep your business logic out of the view and put it on the form or model
# so it can be reused
myModel.checksum = form.calculate_checksum()
myModel.save()
else:
print form.errors
else: # The request is GET
form = PaymentForm()
return render_to_response('payment/payment.html', {'form':form})
Django form.save() documentation.

Django model doesn't relate itself to User through ForeignKey

my question is about modelforms, models and instances. After doing some troubleshooting I think my problem is that either the user field from UserFile doesn't associate itself to the auth.User or that the modelform doesn't pass the instance of auth.User. The error is at the dynamic pathing - file_destination - when I try self.user it can't find the user :/
# Model
class UserFile(models.Model):
user = models.ForeignKey('auth.User', related_name='user_file', primary_key=True, unique=True)
user_file = models.FileField(upload_to=file_destination, null=True)
def __unicode__(self):
return self.user_file.name
# View
def login_index(request):
template = 'loginIndex.html'
context = Context()
if request.user.is_authenticated():
if request.method == 'POST':
form = UserUpload(request.POST, request.FILES, instance=request.user)
context.update({'form': form})
if form.is_valid() and form.is_multipart():
instance = UserFile(user_file=request.FILES.get('user_file'))
instance.save()
else:
form = UserUpload()
context.update({'form': form})
return render(request, template, context)
else:
return render(request, template, context)
# Form
class UserUpload(ModelForm):
user_file = forms.FileField(required=False, widget=forms.ClearableFileInput, label='Upload')
class Meta:
model = UserFile
fields = ['user_file']
def clean_user_file(self):
check_user_file = self.cleaned_data.get('user_file')
if check_user_file:
if check_user_file.size > 5120000:
raise ValueError('File is too big for upload')
return check_user_file
# The problem arises when I submit the instance, which saves the file from the form to upload_to=file_destination
# In file_destination I get an error on self.user.username saying || DoesNotExist at "" UserFile has no user.
# My self.user is an None object.
def file_destination(self, filename):
filename = name_generator()
url = "%s/%s/%s" % (self.user.username, 'uploads' ,filename)
return url
You need to manually set the user field on your UserFile instance:
if form.is_valid():
instance = form.save(commit=False)
instance.user = request.user
instanve.save()
form.save_m2m() # add this if you add m2m relationships to `UserFile`
Also, it is a good idea to redirect after the form handling succeeds:
from django.shortcuts import redirect
# ...
return redirect("view-name")

How to upload an image and store its link in database

I read some documents in Django site such as: Basic file uploads and FileField.storage. However, I still don't understand how to upload a file (or an image) to server and store its link in database. I would like to write the files to the following directory such as: 'image/%Y/%m/%d'
Please give me a sample code. Thank you so much.
My code follows as:
#models.py
class Image(models.Model):
imageid = models.AutoField()
title = models.CharField(max_length=100)
imagepath = models.ImageField(upload_to='images/%Y/%m/%d/')
#forms.py
class UploadFileForm(forms.Form):
title = forms.CharField(max_length=100)
image = forms.FileField()
#views.py
def upload_file(request):
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
# How to upload file to folder named 'images/%Y/%m/%d/'
# How to save the link above to database
return HttpResponseRedirect('/success/url/')
else:
form = UploadFileForm()
return render_to_response('upload.html', {'form': form})
I believe if you create the upload form as a model form and then just save it in the view, it will have the effect of saving the file to the filesystem and the path to the model. This is a basic example, but I think it should work.
# forms.py
class UploadFileForm(forms.ModelForm):
class Meta:
model = models.Image
# views.py
...
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return HttpResponseRedirect('/success/url/')

modifying django model forms after post

I would like to modify a user submitted form to automatically insert the project_id, but I keep getting the error that project_id in the Employee model cannot be null;
My model:
class Project(models.Model):
name = models.CharField(max_length=100)
date_started = models.DateTimeField()
class Employee(models.Model):
name = models.CharField(max_length=200)
project = models.ForeignKey(Project)
class AddEmployeeForm(ModelForm):
class Meta:
model = Employee
exclude = ('project',)
My view:
def emp_add(request, project_id):
if request.method == 'POST':
post = request.POST.copy() # make the POST QueryDict mutable
post('project', project_id)
form = AddEmployeeForm(post)
if form.is_valid():
saved = form.save()
Like this?
if form.is_valid():
employee = form.save(commit=False)
employee.project = Project.objects.get(pk=project_id)
employee.save()
#maciag.artur's answer, to save with commit=False will work. Another way is to instantiate an Employee with the required project_id, and use it to construct the form.
This is useful if your model form's custom clean method relies on the Employee.project field.
def emp_add(request, project_id)
if request.method == 'POST':
# create a new employee with the given project id
employee = Employee(project_id) = project_id
form = AddEmployeeForm(request.POST, instance=employee)
if form.is_valid():
saved = form.save()
<snip>
For reference, see the note box below Using a subset of fields on the form in the Django docs.
Add the project ID to the form as a hidden input. When the request comes back as a POST, it will exist in the POST object, from the form.
def emp_add(request, project_id):
if request.method == 'POST':
post = request.POST.copy() # make the POST QueryDict mutable
post('project', project_id)
form = AddEmployeeForm(post)
if form.is_valid():
saved = form.save()
else:
form = AddEmployeeForm(initial={'project_id':'my_id_value'})

Django ModelForms: Trying to save a form with a foreign key

Django will just go to the else condition.
here's the code:
models.py
class StakeholderProfile(models.Model):
types = models.ForeignKey(Stakeholder)
name = models.CharField(blank=False, max_length=50)
forms.py
class SPForm(forms.ModelForm):
class Meta:
model = StakeholderProfile
exclude = ('key_contact_person',)
views.py
def profile(request):
stakeholderprofile = StakeholderProfile.objects.all()
if request.method == 'POST':
form = SPForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/profile/')
else:
form = SPForm()
return render_to_response('profile.html',{'form':form,'sp':stakeholderprofile})
I really need your help sir/maam.
You are excluding a field that doesn't exist in StakeHolderProfile.
Also be sure you added method='POST' in your form tag.