Reputation: 55
Using the upload_to
argument of FileField
I want to store the file uploaded by the user in a folder named TestName
ie the test name entered by the user. I've written the following code, but it creates a folder named "models.CharField(max_length=255)" instead. How can I fix this?
from django.core.validators import FileExtensionValidator
from django.db import models
from django.contrib.auth.models import User
class TestInfo(models.Model):
TestName = models.CharField(max_length=255)
MaxMarks = models.IntegerField()
TimeDuration = models.IntegerField()
PosMarks = models.IntegerField()
NegMarks = models.IntegerField()
InputTextFile = models.FileField(upload_to='Tests/{}/'.format(TestName),\
validators[FileExtensionValidator(allowed_extensions['txt'])],blank=False)
def __str__(self):
return self.TestName
Upvotes: 1
Views: 167
Reputation: 1211
I think you just missed an additional function which could help you in this. I have not had time to test this particularly now but you are looking for something like this:
from django.core.validators import FileExtensionValidator
from django.db import models
from django.contrib.auth.models import User
def content_file_name(instance, filename):
return "Tests/{folder}/{file}".format(folder=instance.TestName, file=filename)
class TestInfo(models.Model):
TestName = models.CharField(max_length=255)
MaxMarks = models.IntegerField()
TimeDuration = models.IntegerField()
PosMarks = models.IntegerField()
NegMarks = models.IntegerField()
InputTextFile = models.FileField(upload_to=content_file_name)
validators[FileExtensionValidator(allowed_extensions['txt'])],blank=False)
def __str__(self):
return self.TestName
UPDATE - ON USING THE USERNAME AS FOLDER NAME TO SAVE UPLOADED FILE
If you want to add the username as the subfolder name where the user's uploads will be saved, into different subfolders by usernames. And at the same time you will keep the uploader's user name also in your model, then you should formulate your model a bit more like below. I added an extra field to your model as Uploader_info. It just gets the username at uploads, so it cannot be edited by the uploader user, it is just given always at uploads from your user table via request data.
in models.py:
from django.db import models
from django.conf import settings
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError
def content_file_name(instance, filename):
return "Tests/{subfolder}/{folder}/{file}".format(subfolder=instance.Uploader_info, folder=instance.TestName, file=filename)
def validate_file_extension(value):
if value.file.content_type != 'text/plain':
raise ValidationError('The uploaded file must be a text file')
class TestInfo(models.Model):
Uploader_info = models.CharField(max_length=100, editable=False, null = True)
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='testinfos', on_delete=models.CASCADE, null=True)
TestName = models.CharField(max_length=255)
MaxMarks = models.IntegerField()
TimeDuration = models.IntegerField()
PosMarks = models.IntegerField()
NegMarks = models.IntegerField()
InputTextFile = models.FileField(upload_to=content_file_name, blank=False, validators=[validate_file_extension])
def __str__(self):
template = '{0.TestName} {0.Uploader_info}'
return template.format(self)
Do not forget to migrate.
Important! Register the model in the admin.py too with a short added function which will give the uploader's username to the records:
in admin.py:
from .models import TestInfo
class TestInfoAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
if not change:
obj.Uploader_info = request.user.username
obj.save()
admin.site.register(TestInfo, TestInfoAdmin)
Your current view name is post for the Form submission, which has to be reformulated a bit like this:
in views,py
@login_required
def post(request):
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = TestForm(request.POST, request.FILES)
# check whether it's valid:
if form.is_valid():
fulltest = form.save(commit=False)
fulltest.user = request.user
fulltest.Uploader_info = request.user
TestName = form.cleaned_data.get('TestName')
File = form.cleaned_data.get('InputTextFile')
fulltest.save()
messages.success(request, 'Test {} Posted successfully'.format(TestName))
return redirect('Test-Making')
else:
parameters = {
'form': form,
'error': form.errors.as_ul()
}
return render(request, 'Test/post.html', parameters)
# if a GET (or any other method) we'll create a blank form
else:
form = TestForm()
return render(request, 'Test/post.html', {'form': form})
and your Form in forms.py is simply:
class TestForm(forms.ModelForm):
class Meta:
model = TestInfo
fields = ('TestName', 'MaxMarks', 'TimeDuration', 'PosMarks', 'NegMarks', 'InputTextFile')
And that's about it. If your Form is OK then the above will work as I tested that successfully.
Upvotes: 1