3

I've got a model like this:

class MyModel(models.Model):
    name = models.CharField(max_length=255)
    code = models.FileField()

When a new MyModel is submitted, I want to allow for the code field to be left empty, in which case I need Django to create an empty file (with arbitrary name).

Question is: what is the right way to do it?

I couldn't find anything related in the docs, so I was looking at manually editing request.FILES before feeding it to MyModelForm(), but this looks like a dirty hack to me... Any ideas?

Thanks.

letoosh
  • 511
  • 2
  • 6
  • 13
  • How do you plan to use the value submitted to the code field? A FileField doesn't sound like the right fit. – Daniel Rhoden Jul 11 '10 at 18:14
  • It's a file with Python code which then gets executed in a secure runtime environment. It needs to be pre-compiled first, so having it in a separate file looks most convenient. – letoosh Jul 11 '10 at 18:28
  • 1
    the thought of this quite frankly gives me the willies. this is a huge security hole. – eruciform Jul 11 '10 at 19:22
  • I will welcome any other ideas about how to execute untrusted code (provided by site users) securely? – letoosh Jul 11 '10 at 22:50

2 Answers2

2

I would store the code input in a CharField and then create a separate function that accesses the model and if the code does not contain any harmful methods it is then written to a file.

This takes care of creating the file (as a blank CharField will simply be outputted to an empty file) and allows for delegation to a security checker. Your setup would then look something like the following: Model:

class MyModel(models.Model):
    name = models.CharField(max_length=255)
    code = models.CharField(MAX_FILE_LENGTH)

View:

def Submit_Code(request):
     #Create MyModel using POST data
     process_input_file(NEWLY_CREATED_MODEL_NAME)
     return HttpResponse("Upload Successful")

def process_input_file(modelName):
     #assuming unique name. Use "id=" instead if needed.
     mm = MyModel.objects.get(name=modelName)
     if passes_security_checks(mm.code):
          f = open(mm.name, "r")
          f.write(mm.code)
          f.close()

Edit New view:

def Submit_Code(request):
     mm = MyModel()
     mm.name = request.POST.get('name')
     f = open(mm.name,"r")
     f.write(request.POST.get('code')
     f.close()
     #then associate the newly created file with the FileField however you want
     #passing through authentication/checking if need be.
     return HttpResponse("Upload Successful")
Josiah
  • 4,754
  • 1
  • 20
  • 19
  • I would put the process_input_file code in the clean_code method of the form, this way handling all of the form's logic in one place. – Guillaume Esquevin Jul 12 '10 at 06:42
  • I think the code field should be a TextField instead of a CharField. I believe CharField is implemented as a VARCHAR(255) in MySQL, and I imagine you would like the ability to have more than 255 characters of code. – Daniel Rhoden Jul 12 '10 at 13:59
  • It's a nice idea, but having duplicated data in the CharField looks a bit like an overkill to me. For the moment, the submitted code is being checked anyway, so I don't see a reason for storing it separately. I've got all of the stuff implemented already and I just want to let users omit the code field and then edit it in-browser. The secure runtime is completely abstracted from the Django instance, and has no access to the DB or anything. Thus, having the code in a file is by far the best way. Finally, for the sake of other people here it would be nice to know the right solution. – letoosh Jul 12 '10 at 23:54
  • To clarify, are you getting the code from POST data? If so, see my edit :) – Josiah Jul 13 '10 at 00:12
  • Please note that my example is not production worthy (As in, there's no error checking). – Josiah Jul 13 '10 at 00:18
0

Just set the field to allow null and blank. This will make the field optional.

code = models.FileField(null=True, blank=True)
Soviut
  • 88,194
  • 49
  • 192
  • 260