TimeString
TimeString

Reputation: 1798

How should I allow a FileField not need to upload a new file when the existed in Django?

I have a model like this:

class Assignment(models.Model):
    content = models.FileField(upload_to='xxx')
    other_val = models.CharField(...)  # not important

And a form wrapping this model (ModelForm):

class AssignmentForm(ModelForm):
    class Meta:
        model = Assignment
        fields = ['content', 'other_val']

My view looks like this (for simplicity I skip the request.POST/request.FILES. part):

@login_required(login_url='/login/')
def create_assignment(request):
    form = AssignmentForm()
    # render form

@login_required(login_url='/login/')
def update_assignment(request, assignment_id):
    assignment = Assignment.objects.get(id=assignment_id)
    form = AssignmentForm(instance=assignment)

Creating an assignment works just fine - It forces me to upload a file, which is what I want. But when I want to update the content of the assignment (the file), it first shows a link of a previously uploaded file (excellent!) then the upload button, like this:

Currently: AssignmentTask_grading_script/grading_script_firing.py 
Change: [Choose File] no file chosen

But then I assume if I don't want to replace this file, I should simply click the submit button. Unfortunately, when I click the submit button, the form complains that I should upload a file. Is there a way to silent the complaint if a file is already in database?

Upvotes: 0

Views: 1256

Answers (2)

baloersch
baloersch

Reputation: 11

If someone stumbles upon this question again... The easiest pythonic way is to edit the form init method instead: for given example in the Question:

class Assignment(models.Model):
    content = models.FileField(upload_to='xxx')
    other_val = models.CharField(...)  # not important

class AssignmentForm(ModelForm):
    class Meta:
        model = Assignment
        fields = ['content', 'other_val']

    def __init__(self, *args, **kwargs):
        super(AssignmentForm, self).__init__(*args, **kwargs)
        if self.instance.content:
            self.fields['content'].widget.attrs.pop('required', None)

But if the model has following setup (FileField is allowed to be empty):

class Assignment(models.Model):
    content = models.FileField(upload_to='xxx', null=True, blank=True)
    other_val = models.CharField(...)  # not important

class AssignmentForm(ModelForm):
    class Meta:
        model = Assignment
        fields = ['content', 'other_val']

    def __init__(self, *args, **kwargs):
        super(AssignmentForm, self).__init__(*args, **kwargs)
        if not self.instance.content:
            self.fields['content'].widget.attrs['required'] = 'required'
        

In this case the Form Class is rendered by django without an instance (creating a new database entry) so the FileField will be mandatory.

Upvotes: 0

binpy
binpy

Reputation: 4194

As following the previous comments, maybe like this;

1. forms.py

class AssignmentForm(forms.ModelForm):
    # as following @Rohan, to make it optional.
    content = forms.FileField(required=False)

    class Meta:
        model = Assignment
        fields = ['content', 'other_val']

2. yourtemplate.html

<form method="post" enctype="multipart/form-data" action=".">
  {% csrf_token %}
  {{ form.as_p }}
  <button type="submit">Save</button>
</form>

<script> 
{% if not form.content.value %}
  $('#id_content').attr({'required': 'required'});
{% endif %}
</script>

The field of content is under required only if havn't value before...

Upvotes: 1

Related Questions