如何使用表单在 Django OneToOne 模型的 FileField 中上传文件?

发布于 2025-01-18 19:14:13 字数 2680 浏览 2 评论 0 原文

我有一个模型详细信息具有 onetoone 与默认用户模型的关系。我在详细信息模型中有一个字段 filefield ,我想使用Frontend/模板中的表单上传文件。

我一直在努力工作,但我没有完成它。我需要帮助。

我的 model.py is:

from django.db import models
from django.contrib.auth.models import User

class Detail(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    file = models.FileField(verbose_name="CSV File", upload_to='csv_files/')
    file_desc = models.TextField("CSV File Description")

    def __str__(self):
        return ("{} ({} {})".format(self.user.email, self.user.first_name, self.user.last_name))

我的 forms.py is:

from django.forms import ModelForm
from .models import Detail

class DetailForm(ModelForm):
    class Meta:
        model = Detail
        fields = ['file', 'file_desc']

我的 views.pys.py 是:

from django.views import View

class UserAPI(View):
    template_name = 'accounts/user.html'

    def get(self, request):
        form = DetailForm(instance=request.user)

        context = {'form': form}
        return render(request, self.template_name, context)

    def post(self, request):
        form = DetailForm(request.POST, request.FILES, instance=request.user)
        if form.is_valid():
            form.save()
            return redirect('user')

        context = {'form': form}
        return render(request, self.template_name, context)

和我的 user.html(template) is:

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

每次我转到 localhost:8000/user 并填写表格并单击提交按钮,它在前端给我以下错误: 没有选择文件 以及以下语句显示在文件选择按钮上方: <代码>此字段是必需的。

我将感谢您的帮助。谢谢

更新:

urls.py

urlpatterns = [
    path('register', RegisterAPIHTML.as_view(), name='register'),
    path('login', LoginAPIHTML.as_view(), name='login'),
    path('user', UserAPI.as_view(), name='user'),
    path('logout', LogoutAPI.as_view(), name='logout'),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

settings.py

STATIC_ROOT  =   os.path.join(BASE_DIR, 'staticfiles')

STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static'),
)

MEDIA_ROOT = os.path.join(BASE_DIR, 'data/')
MEDIA_URL = '/media/'

I have one model Detail which has OneToOne relation with default User Model. I have a field FileField in my Detail model, where I want to upload the files using forms from frontend/templates.

I have been working around it a lot but I am not getting it done. I need help, please.

My models.py is:

from django.db import models
from django.contrib.auth.models import User

class Detail(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    file = models.FileField(verbose_name="CSV File", upload_to='csv_files/')
    file_desc = models.TextField("CSV File Description")

    def __str__(self):
        return ("{} ({} {})".format(self.user.email, self.user.first_name, self.user.last_name))

My forms.py is:

from django.forms import ModelForm
from .models import Detail

class DetailForm(ModelForm):
    class Meta:
        model = Detail
        fields = ['file', 'file_desc']

My views.py is:

from django.views import View

class UserAPI(View):
    template_name = 'accounts/user.html'

    def get(self, request):
        form = DetailForm(instance=request.user)

        context = {'form': form}
        return render(request, self.template_name, context)

    def post(self, request):
        form = DetailForm(request.POST, request.FILES, instance=request.user)
        if form.is_valid():
            form.save()
            return redirect('user')

        context = {'form': form}
        return render(request, self.template_name, context)

and my user.html (template) is:

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

Every time I go to localhost:8000/user and fill the form and click on Submit Button, it gives me following error on frontend:
No File Chosen
and also the following statement appears above the File Selection Button:
This field is required.

I shall appreciate for the help. Thanks

UPDATE:

urls.py

urlpatterns = [
    path('register', RegisterAPIHTML.as_view(), name='register'),
    path('login', LoginAPIHTML.as_view(), name='login'),
    path('user', UserAPI.as_view(), name='user'),
    path('logout', LogoutAPI.as_view(), name='logout'),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

settings.py

STATIC_ROOT  =   os.path.join(BASE_DIR, 'staticfiles')

STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static'),
)

MEDIA_ROOT = os.path.join(BASE_DIR, 'data/')
MEDIA_URL = '/media/'

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

一紙繁鸢 2025-01-25 19:14:13

我认为您的表格没有保存任何内容,因为使用 form.is_valid()返回 false

您不会在 form.errors 中看到任何内容,因为该属性仅显示字段错误,而不是非场错误。在这种情况下,非场错误是缺少所需的字段用户。这是因为您尚未以模型形式指定它(也是为什么将其作为非场错误放置)。

另外,您不会在html中呈现非场错误,这就是为什么在提交后发布后页面中不会在页面中看到它们的原因。我建议使用 crispy-forms 软件包(这是 link < /a>)。它处理诸如开箱即用的形式之类的事情。

此外,指定参数„ nstance = request.user 是不正确的,因为如果您有一个 detail formform ,则实例应为详细信息>详细信息模型,不是用户模型。请记住,实例 kwarg仅在要使用此表单进行更新时才有必要。

我建议实现与以下几点类似的实现:

forms.py

class DetailForm(ModelForm):
    class Meta:
        model = Detail
        fields = ['user', 'file', 'file_desc']

        widgets = {
            # I'm guessing you don't want to see the User field
            'user': HiddenInput()
        }

views.py 的相关部分

def get(self, request):
    form = DetailForm()

    context = {'form': form}
    return render(request, self.template_name, context)

def post(self, request):
    form = DetailForm(request.POST, request.FILES, initial={'user': request.user.id})
    if form.is_valid():
        form.save()
        return redirect('user')


    context = {'form': form}
    return render(request, self.template_name, context)

要使这是一个完整的答案,我将包括

确保您的表单标签如下:
&lt; form方法=“

遵循的一些资源:

I think your form is not saving anything because the line with form.is_valid() returns False.

You won't see anything in the form.errors because that attribute only shows field errors, not non-field errors. The non-field error in this case is that the required field user is missing. This is because you haven't specified it in the model form (also why it gets placed as a non-field error).

Also, you're not rendering the non-field errors in the HTML which is why you don't see them in your page after the post submission. I suggest using crispy-forms package (here's the link). It handles things like form rendering out of the box.

Moreover, specifying argument ìnstance=request.user is incorrect because if you have a DetailForm the instance should be a model instance of the Detail model, not User model. Keep in mind, instance kwarg is only necessary if you want to use this form for updating.

I suggest an implementation similar to the following:

forms.py

class DetailForm(ModelForm):
    class Meta:
        model = Detail
        fields = ['user', 'file', 'file_desc']

        widgets = {
            # I'm guessing you don't want to see the User field
            'user': HiddenInput()
        }

Relevant part of views.py

def get(self, request):
    form = DetailForm()

    context = {'form': form}
    return render(request, self.template_name, context)

def post(self, request):
    form = DetailForm(request.POST, request.FILES, initial={'user': request.user.id})
    if form.is_valid():
        form.save()
        return redirect('user')


    context = {'form': form}
    return render(request, self.template_name, context)

To make this a complete answer, I will include a comment from @raphael which fixed the first issue of your code:

Make sure your form tag is as follows:
<form method="post" enctype="multipart/form-data">

Some resources to follow:

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文