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/'
CodePudding user response:
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: