Как загрузить файл в поле FileField модели Django OneToOne с помощью формы?
У меня есть одна модель Detail, которая имеет OneToOne отношение с моделью по умолчанию User. У меня есть поле FileField в моей Detail модели, в которое я хочу загружать файлы с помощью форм из frontend/templates.
Я много работал над этим, но у меня ничего не получается. Мне нужна помощь, пожалуйста.
Мой models.py - это:
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 - это:
from django.forms import ModelForm
from .models import Detail
class DetailForm(ModelForm):
class Meta:
model = Detail
fields = ['file', 'file_desc']
Мой views.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)
if form.is_valid():
form.save()
return redirect('user')
context = {'form': form}
return render(request, self.template_name, context)
и мой user.html (template) это:
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Submit</button>
</form>
Каждый раз, когда я перехожу на страницу localhost:8000/user, заполняю форму и нажимаю на кнопку Submit, на фронтенде появляется следующая ошибка:
No File Chosen
а также над кнопкой выбора файла появляется следующее утверждение:
This field is required.
Я буду благодарен за помощь. Спасибо
Я думаю, что ваша форма ничего не сохраняет, потому что строка с form.is_valid() возвращает False.
Вы ничего не увидите в form.errors, потому что этот атрибут показывает только ошибки полей, а не не-полевые ошибки. Неполевая ошибка в данном случае заключается в том, что отсутствует обязательное поле user. Это происходит потому, что вы не указали его в форме модели (также поэтому оно помещается как ошибка, не связанная с полем).
Кроме того, вы не выводите ошибки, не относящиеся к полю, в HTML, поэтому вы не видите их на своей странице после отправки сообщения. Я предлагаю использовать пакет crispy-forms (вот ссылка ). Он обрабатывает такие вещи, как отрисовка формы из коробки.
Более того, указание аргумента ìnstance=request.user является некорректным, поскольку при наличии DetailForm экземпляр должен быть экземпляром модели Detail, а не User. Помните, instance 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)
Чтобы сделать этот ответ полным, я включу комментарий от @raphael, который исправил первую проблему вашего кода:
Убедитесь, что тег вашей формы выглядит следующим образом:
<form method="post" enctype="multipart/form-data">
Некоторые ресурсы для подражания: