Django formset:文件上传不起作用

时间:2019-07-13 07:39:46

标签: django

我正在使用Django构建服务台,我希望允许客户端在提交工单时上传多个文件。

我正在尝试通过使用表单集来做到这一点。

我发现了许多与类似问题有关的问题,但是我仍然无法使我的表格正常工作。我会感激朝正确方向的指针。

我在下面发布了相关代码:

# models.py

class Ticket(models.Model):

    PRIORITY_CHOICES = (
        (1, 'Critical'),
        (2, 'High'),
        (3, 'Normal'),
        (4, 'Low'),
        (5, 'Very Low'),        
    )

    STATUS_CHOICES = (
        (1, 'Open'),
        (2, 'Reopened'),
        (3, 'Resolved'),
        (4, 'Closed'),
        (5, 'Duplicate'),        
    )

    ticket_number = models.CharField(max_length=50, blank=True, 
                                        null=True, unique=True) 
    client = models.ForeignKey(settings.AUTH_USER_MODEL, 
                            editable=True, on_delete=models.CASCADE, 
                            related_name="tickets")
    title = models.CharField("Summary", 
                                max_length=200,
                                help_text='Provide a brief description of your request.')
    description = models.TextField(blank=True,
                               help_text='Provide as much detail as possible to help us resolve this ticket as quickly as possible.')
    due_date = models.DateField(blank=True, null=True)
    assigned_to = models.ForeignKey(settings.AUTH_USER_MODEL, 
                                    related_name="assigned", 
                                    blank=True, null=True, 
                                    on_delete=models.CASCADE)
    priority = models.IntegerField(choices=PRIORITY_CHOICES,
                                    editable=True, default=3,
                                    help_text='Please select a priority carefully. If unsure, leave it as "Normal".',
                                    blank=True, null=True)
    status = models.IntegerField(choices=STATUS_CHOICES, 
                                editable=True, 
                                default=1, blank=True, null=True) 
    closing_date = models.DateField(blank=True, null=True) 
    closing_notes = models.TextField(blank=True) 
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    upload = models.FileField(upload_to='uploads/%Y/%m/%d/', blank=True, null=True)


    def get_absolute_url(self):
        return reverse('tickets:ticket-detail', args=[str(self.id)])

    def __str__(self):
        return str(self.ticket_number)


class TicketFile(models.Model):
    attachment = models.FileField(upload_to='attachments/%Y/%m/%d', blank=True, null=True)
    ticket = models.ForeignKey(Ticket, editable=True, on_delete=models.CASCADE)
    description = models.CharField(max_length=200, blank=True)

    def get_image_filename(self):
        if self.docfile:
            return media_url + str(self.docfile)

    def __str__(self):
        return str(self.attachment)


# forms.py

class TicketFormIsStaff(ModelForm):
    class Meta:
        model = Ticket
        exclude = ()


class TicketFileForm(forms.ModelForm):
    attachment = forms.FileField(label='Attachment')    
    class Meta:
        model = TicketFile
        fields = ('attachment', )


TicketAttachmentFormset = modelformset_factory(Ticket,
                                            form=TicketFileForm, extra=2)


# views.py

class TicketCreateView(CreateView):
    model = Ticket
    fields = ['ticket_number', 'client', 'title', 'description', 'status']

    def get_context_data(self, **kwargs):
        data = super(TicketCreateView, self).get_context_data(**kwargs)
        if self.request.POST:
            data['ticketfiles'] = TicketAttachmentFormset(self.request.POST)
            print("data 1 ", data['ticketfiles'] )
        else:
            data['ticketfiles'] = TicketAttachmentFormset()
            print("data 2 ", data)
        return data

    def form_valid(self, form):
        context = self.get_context_data()
        ticketfiles = context['ticketfiles']
        with transaction.atomic():
            self.object = form.save()
            print("CONTEXT:::: ", ticketfiles)

            if ticketfiles.is_valid():
                ticketfiles.instance = self.object
                ticketfiles.save()

        return super(TicketCreateView, self).form_valid(form)
# ticket_form.html

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

<table class="table">
{{ ticketfiles.management_form }}

{% for form in ticketfiles.forms %}
{% if forloop.first %}
<thead>
  <tr>
    {% for field in form.visible_fields %}
    <th>{{ field.label|capfirst }}</th>
    {% endfor %}
  </tr>
</thead>
{% endif %}
<tr class="{% cycle row1 row2 %} formset_row">
  {% for field in form.visible_fields %}
  <td>
    {# Include the hidden fields in the form #}
    {% if forloop.first %}
    {% for hidden in form.hidden_fields %}
    {{ hidden }}
    {% endfor %}
    {% endif %}
    {{ field.errors.as_ul }}
    {{ field }}
  </td>
  {% endfor %}
</tr>
{% endfor %}
</table>
<input type="submit" value="Save" /> 
</form>

与票证模型相关的所有数据均正确上载,但与票证文件模型相关的文件未上载。如果我尝试在管理界面中上传数据,则一切运行正常。我认为这意味着所有媒体设置都是正确的。

如果我将描述字段添加到表单集中,则可以正确保存该字段。不过该文件未保存。

1 个答案:

答案 0 :(得分:0)

我通过更改TicketCreateView中的代码从以下位置解决了文件上传问题:

data['ticketfiles'] = TicketAttachmentFormset(self.request.POST)

收件人:

data['ticketfiles'] = TicketAttachmentFormset(self.request.POST, self.request.FILES, instance=form.instance))