How to make files available download in Django - django

This is my model
class UploadAssignment(models.Model):
doc=models.FileField()
assignment = models.ForeignKey(AssignAssignment, on_delete=models.CASCADE)
student= models.ForeignKey(Student, on_delete=models.CASCADE)
This is my view to upload.
def upload_assignment(request,pk):
student = get_object_or_404(Student,user_id=request.user)
assign = get_object_or_404(AssignAssignment, pk=pk)
if request.method == 'POST':
form = AssignmentUpload(request.POST, request.FILES)
if form.is_valid():
m=form.save(commit=False)
m.student_id=student.user_id
m.assignment_id=assign.pk
print(m)
m.save()
messages.success(request, 'Assignment upload is successful')
return redirect('home')
else:
form = AssignmentUpload()
return render(request, 'accounts/students/uploadassignments.html', {
'form': form
})
I'd like to write a view function for lecturer to download those files with upload assignment primary key. Any one have any idea?

Based on similar questions (this and this) and the docs you could try:
def download_file(request, pk):
obj = get_object_or_404(UploadAssignment, pk=pk)
response = HttpResponse(
obj.doc,
content_type='application/whatever-the-correct-type-is')
response['Content-Disposition'] = 'attachment; filename="foo.xls"'
return response
Content types and file extensions are always a tricky part with user-submitted files, since there are a lot of thinks that could go wrong or be attack vectors.
Read more: django user-uploaded-content-security.
You could also look into the special FileResponse class.

Related

Get Kwargs through an intermediate page

I have a model (grade) inside another model (homework) which is inside another model (activity) and when I submit the grade of a homework and try to get back to activty I loose the id of the activity. How do I get the right kwargs to get back to activity after submiting a grade? Or any other solution you may think about. Thanks in advance.
Views.py
def grade_homework(request, id):
if not request.user.is_authenticated:
return render(request, "auctions/login.html")
try:
activity = Activity.objects.get(id=id)
except Activity.DoesNotExist:
activity = None
try:
hw_upload = Hw_upload.objects.get(id=id)
except Hw_upload.DoesNotExist:
hw_upload = None
if request.method == 'POST':
form = Hw_gradeForm(request.POST, request.FILES or None)
if form.is_valid():
hw_grade = form.save(commit=False)
hw_grade.grader = request.user
hw_grade.hw_upload = Hw_upload.objects.get(id=id)
hw_grade.save()
url = reverse('activity', kwargs={'id': id})
return HttpResponseRedirect(url)
Urls.py
path("auction/course/module/activity/<str:id>", views.activity, name="activity"),
path("grade_hw/<int:id>", views.grade_homework, name="grade_hw"),

Save and Continue in Django Forms

I have created a django form which at the moment I can only save the POST. Would like to add Save and Add another button in my templates and views function. Has anyone found a solutions.
if request.method == "POST":
form = StktxnsForm(request.POST )
if form.is_valid():
new_txns = form.save(commit=False)
new_txns.created_by = request.user
new_txns.save()
return redirect('pending_transactions')
else:
form = StktxnsForm()
return render(request,'new_transaction.html', {'form': form})
You may think use AJAX function to save and continue without reload. Send 'POST' request to save data in Ajax. It will help you.
I used like this in class-based view (vanilla method)
class PackageCreateView(View):
def get(self,request,*args,**kwargs):
return render(request,'package/create_package.html')
def post(self,request,*args,**kwargs):
if request.user.is_authenticated:
if request.method == 'POST':
data = request.POST
name = data.get('name')
detail = data.get('des')
price = data.get('price')
fname = Package.objects.all().filter(name=name)
if fname:
messages.info (request,'sorry name already exits')
return redirect ('create_package')
elif request.POST.get ('continue') :
pac = Package(name=name, detail=detail, price=price)
pac.save()
return redirect('create_package')
else:
pac = Package(name=name, detail=detail, price=price)
pac.save()
return redirect('packagelist')
else:
return redirect ('create_package')
else:
return redirect('login')
Here's one way to do it.
On your template:
<button type="submit" name="save_add" value="True">Save & Add another</button>
In your view:
if form.is_valid():
new_txns = form.save(commit=False)
new_txns.created_by = request.user
new_txns.save()
if request.POST.get('save_add'):
return redirect('create_transaction')
return redirect('pending_transactions')

Image upload in Django no error

Trying to save images to a specific folder in django. I get no error but the file doesn't show up where its supposed to.
Here is the model:
class FileUploadHandler(models.Model):
title = models.CharField(max_length=100)
file = models.ImageField(upload_to='/wiki/static/')
View:
def image_upload(request):
if request.method == 'POST':
form = UploadImageForm(request.POST, request.FILES)
if form.is_valid():
FileUploadHandler(request.FILES['image'])
form.save
return render_to_response('wiki/gallery.html')
else:
form = UploadImageForm()
return render_to_response('wiki/gallery.html', RequestContext(request, {'form': form}))
Totally stumped since I don't get an error.
don't you need parenthesis at the end of form.save,
i.e. form.save()
FileUploadHandler.objects.create(file=request.FILES['image'])
https://docs.djangoproject.com/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.create
https://docs.djangoproject.com/en/dev/topics/http/file-uploads/#handling-uploaded-files

Django request.POST as an argument of a form

I am having a hard time wrapping my head around what request.POST is doing as a argument in the following example:
def addauthorView(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
first_name = form.cleaned_data['firstname']
last_name = form.cleaned_data['lastname']
user_email = form.cleaned_data['email']
c = AuthorModel(firstname=first_name, lastname=last_name, email=user_email)
c.save()
return HttpResponseRedirect('thanks/')
else:
form = ContactForm(request.POST)
return render(request, 'addauthor.html', {'form': form})
So I know that this works, but for some reason I cannot understand the magic that is happening with form = ContactForm(request.POST). Why does the ContactForm need the request.POST argument? What is happening behind the scenes?
Extra question, why is form = ContactForm(request.POST) then repeated in the else: block. Why is that helpful and when is that useful? Examples?
In a nutshell, request.POST is simply the data that was sent when the form was submitted. It's a dictionary of what the user submitted for firstname, lastname and email in your code sample. For those that come from a PHP background, it's what is provided in $_POST.
form = ContactForm(request.POST) binds the data to the form class so Django can do fun stuff like validate inputs with is_valid().
Why then, would you add request.POST to the else: block? Well, have you ever submitted a form to a website and when there was an error you had to completely fill out the form again? That's a crappy user experience, right? By sending the form back to the user with the data from request.POST, you can re-render what the user inputed - along with helpful extras such as error messages - so they can fix them and resubmit.
EDIT: To expand, here is the init method from the BaseForm class in Django:
def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
initial=None, error_class=ErrorList, label_suffix=None,
empty_permitted=False):
self.is_bound = data is not None or files is not None
self.data = data or {}
self.files = files or {}
self.auto_id = auto_id
self.prefix = prefix
self.initial = initial or {}
self.error_class = error_class
# Translators: This is the default suffix added to form field labels
self.label_suffix = label_suffix if label_suffix is not None else _(':')
self.empty_permitted = empty_permitted
self._errors = None # Stores the errors after clean() has been called.
self._changed_data = None
# The base_fields class attribute is the *class-wide* definition of
# fields. Because a particular *instance* of the class might want to
# alter self.fields, we create self.fields here by copying base_fields.
# Instances should always modify self.fields; they should not modify
# self.base_fields.
self.fields = copy.deepcopy(self.base_fields)
When you pass request.POST to your form class, you're really doing data=request.POST. That in turn triggers the self.is_bound = True

Auto Fill ModelForm with data already stored in database

I got a form as shown below and I want it to be filled with information from the database when its HTML is rendered. I am passing the id of the Coworker as a parameter for the view.
See code below:
view.py
def EditCoworker(request, id):
form = FormEditCoworker(Coworkers.objects.get(id=id))
if request.method == "POST":
form = FormEditCoworker(request.POST)
if form.is_valid():
form.save()
confirmation_message = "Coworker information updated successfully!"
return render(request, "coworkers/coworkers.html", locals())
else:
return render(request, "coworkers/edit_coworker.html", locals())
return render(request, 'coworkers/edit_coworker.html', locals())
forms.py
class FormEditCoworker(ModelForm):
class Meta:
model = Coworkers
urls.py
url(r'^edit_coworker/(?P<id>[\d]+)$', views.EditCoworker),
Of course the code in my views.py is not right.
Can someone help me on this?
Thanks in advance!
This line
form = FormEditCoworker(Coworkers.objects.get(id=id))
Should be
form = FormEditCoworker(instance=Coworkers.objects.get(id=id))
Although you should really handle the case where the Coworker doesn't exist
form = FormEditCoworker(instance=get_object_or_404(Coworkers, id=id))
EDIT: As Alisdair said, you should also pass the instance keyword arg to the bound form also
instance = get_object_or_404(Coworkers, id=id)
form = FormEditCoworker(instance=instance)
if request.method == "POST":
form = FormEditCoworker(request.POST, instance=instance)