Django - 如何将用户输入从views.py传输到models.py?

时间:2017-08-21 11:20:36

标签: django django-models django-forms

我正在尝试创建一个Django应用程序,允许用户从下拉菜单中选择文件名并上传文件。无论用户将其文件命名为什么,我都会收到该文件,保存为在下拉列表中选择的任何内容以及日期。我似乎无法得到我的下降显示。阅读文档的时间,多个堆栈溢出帖子以及反复试验都没有帮助。 *有没有人知道如何将用户选择的下拉值从views.py到models.py插入上传文件的路径? *

另一方面,我确信我的代码存在其他问题,例如Django newb,所以如果你看到它们,请指出它们。

models.py

from django.db import models
from datetime import datetime
import os

def update_filename(instance, filename):
    path = "documents/"
    format = '{0}_{1}.csv'.format(vc, datetime.today().strftime('%Y%m%d')) 
    #note that vc is defined in views.py but I am not sure how to transfer this to models.py 
    #*************************************************************
    return os.path.join(path, format)

class Document(models.Model):
    docfile = models.FileField(upload_to= update_filename) #/%Y/%m/%d')
    #value_chains = (('coffee', 'coffee'),('tea', 'tea'),)
    dropdown = models.CharField(max_length=20, choices=(('coffee', 'coffee'),('tea', 'tea'),))

forms.py

from django import forms
from .models import Document


def validate_file_extension(value):
        if not value.name.endswith('.csv'):
            raise forms.ValidationError("Only CSV file is accepted")

class DocumentForm(forms.ModelForm):
    docfile = forms.FileField(label='Select a file', validators=[validate_file_extension])
    value_chains = (('coffee', 'coffee'),('tea', 'tea'),)
    dropdown = forms.ChoiceField(choices=value_chains, required=True)

    class Meta:
        model = Document
        fields = ['dropdown']

views.py

from django.shortcuts import render_to_response
from django.template import RequestContext
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from django.views.generic.edit import CreateView

from .models import Document 
from .forms import DocumentForm 

def list(request):
    # Handle file upload
if request.method == 'POST':
    #bind the data to the form
    form = DocumentForm(request.POST, request.FILES)
    if form.is_valid():
        #**** vc is defined here ************************************
        vc = form.cleaned_data['dropdown']
        newdoc = Document(docfile = request.FILES['docfile'])
        newdoc.save()

        # Redirect to the document list after POST
        return HttpResponseRedirect(reverse('file_upload_app.views.list'))

# if a GET (or any other method) we'll create a blank form:
else:
    form = DocumentForm() # A empty, unbound form. This is what we can expect to happen the first time we visit the URL.

# Load documents for the list page
documents = Document.objects.all()

# Render list page with the documents and the form
return render_to_response(
    'file_upload_app/list.html',
    {'documents': documents, 'form': form},
    context_instance=RequestContext(request)
)

list.html

<form action="{% url "list" %}" method="post" enctype="multipart/form-data">
                    {% csrf_token %}
                    {{ form.dropdown }}
                    <p>
                        <h6>
                            Note: the uploaded file must be in
                            <b>.CSV</b>
                            format and contain a column labeled "A" which contains
                            <em>only</em>
                            numbers.
                        </h6>
                    </p>

                    <p>{{ form.non_field_errors }}</p>

                    <p>{{ form.docfile.label_tag }} {{ form.docfile.help_text }}</p>

                    <p>
                        {{ form.docfile.errors }}
                        {{ form.docfile }}
                    </p>

                    <p><input type="submit" value="Upload"/></p>
                </form>

                <!-- List of uploaded documents -->
                <p>
                    {% if documents %}
                        <div class="col-sm-12" align="center" >
                            <ul>
                                <p>Files on server:</p>
                                {% for document in documents %}
                                    <li><a href="{{ document.docfile.url }}">{{ document.docfile.name }}</a></li>
                                {% endfor %}
                            </ul>
                        </div>
                    {% else %}
                        <div class="col-sm-12" align="center" >
                            <p>No documents.</p>
                        </div>

2 个答案:

答案 0 :(得分:0)

我建议您使用Djano的CreateView作为视图。在你的情况下你会有

Class UploadDocumentView(CreateView):
    model = Document

当您在表单上单击“提交”并且操作指向正确的视图时,它将创建一个包含您提供的字段的新文档。

您的模板应该包含此内容,网址应该是您为网址指定的名称。我建议不要使用“list”作为你的url,因为这是python中的一个特殊名称,Django有自己的ListView概念。

<form id="upload_document" method="POST" action="{% url 'document:upload' %}">
  {{ form }}
   <input class="btn btn-primary" id="upload_document_button" type="submit" value="Upload Document"/>
</form>

有时看到一个有用的例子很有用。下面的一个使用Django的UpdateView。 UpdateView将使用get_object方法确定要修改的数据库中的哪个对象。它知道要查看哪个模型,因为它设置为model = UserProfile,并且它知道要保存哪些值,因为您在表单中设置它们。

models.py

class UserProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE,
                                primary_key=True)
    company_identifier = models.CharField(max_length=5, blank=False)
    employee_id = models.CharField(max_length=20, null=True, blank=False)

forms.py

def get_company_choices():
    company_list = [('','-------')]
    companies = models.Company.objects.values_list('id', 'name').order_by('name')
    company_list = list(chain(company_list, companies))
    return company_list

class EmployerForm(forms.ModelForm):
    employee_id_confirm = forms.CharField(label="Confirm Employee ID", required=True)
    company_identifier = forms.ChoiceField(choices=get_company_choices, label="Company")

    class Meta:
        model = models.UserProfile
        fields = ('company_identifier', 'employee_id')
        labels = {
            'employee_id': "Employee ID",
            }

views.py

@method_decorator(login_required, name='dispatch')
class EmploymentUpdate(SuccessMessageMixin, UpdateView):
    model = UserProfile
    template_name = 'employee/update_employment.html'
    form_class = forms.EmployerForm
    success_url = reverse_lazy('employee:home')
    success_message = "Employment Updated."

    def get_object(self):
        return self.model.objects.get(pk=self.request.user.userprofile.pk)

答案 1 :(得分:0)

我找到了解决方案,由下面的****表示:

models.py:

from django.db import models
from datetime import datetime
import os

value_chains = (
    ('coffee', 'coffee'),
    ('tea', 'tea'),
    )

def update_filename(instance, filename):
    path = "documents/"
    #*************************************************************
    #use instance to access the instance of Document's CharField function, which is defined below
    format = '{0}_{1}.csv'.format(instance.dropdown, datetime.today().strftime('%Y%m%d'))
    #*************************************************************
    return os.path.join(path, format)

class Document(models.Model):

    docfile = models.FileField(upload_to= update_filename) 
    dropdown = models.CharField(max_length=20, choices=value_chains)      

    class Meta:
        permissions = (("access_file_upload_app", "Access file upload tool."),)

views.py:

from django.shortcuts import render_to_response, redirect
from django.template import RequestContext
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from django.contrib.auth.decorators import login_required
from django.conf import settings

from .models import Document
from .forms import DocumentForm

@login_required
def doc_upload_view(request):
    if request.user.has_perm('file_upload_app.access_file_upload_app') and settings.VC_ENABLED == 'Y':
        # Handle file upload
        if request.method == 'POST':
            form = DocumentForm(request.POST, request.FILES)
            if form.is_valid():
                #********************************************************
                # make sure to pass the dropdown value to the Document call:
                newdoc = Document(docfile = request.FILES['docfile'], dropdown = form.cleaned_data['dropdown'])
                #********************************************************

                newdoc.save()

                # Redirect to the document list after POST
                return HttpResponseRedirect(reverse('file_upload_app.views.doc_upload_view'))
        else:
            form = DocumentForm() # An empty, unbound form

        # Load documents for the list page
        documents = Document.objects.all()

        # Render list page with the documents and the form
        return render_to_response(
            'file_upload_app/doc_upload_view.html',
            {'documents': documents, 'form': form},
            context_instance=RequestContext(request)
        )
    else:
        return redirect('/home/')

forms.py:

from django import forms
from .models import Document

def validate_file_extension(value):
        if not value.name.endswith('.csv'):
            raise forms.ValidationError("Only CSV file is accepted")

class DocumentForm(forms.ModelForm):

    value_chains = (('coffee', 'coffee'),('tea', 'tea'),)

    docfile = forms.FileField(label='Select a file', validators=[validate_file_extension])
    dropdown = forms.ChoiceField(choices=value_chains, required=True )

    class Meta:
        model = Document 
        fields = ('dropdown',)

doc_upload_view.html:

 <!-- Upload form. Note enctype attribute! -->
                <form action="{% url "doc_upload_view" %}" method="post" enctype="multipart/form-data">
                    {% csrf_token %}


                    {{ form.dropdown }}

                    <p>{{ form.non_field_errors }}</p>

                    <p>{{ form.docfile.label_tag }} {{ form.docfile.help_text }}</p>

                    <p>
                        {{ form.docfile.errors }}
                        {{ form.docfile }}
                    </p>

                    <p><input type="submit" value="Upload"/></p>
                </form>
                <!-- List of uploaded documents -->
                <p class="top-space">
                    {% if documents %}
                        <div class="col-sm-12" align="center" >
                            <ul>
                                <p>Files on server:</p>
                                {% for document in documents %}
                                    <li><a href="{{ document.docfile.url }}">{{ document.docfile.name }}</a></li>
                                {% endfor %}
                            </ul>
                        </div>
                    {% else %}
                        <div class="col-sm-12" align="center" >
                            <p>No documents.</p>
                        </div>
                    {% endif %}
                </p>