I am trying to do multiple file uploads in Django but am encountering some errors: form.is_valid() returning false. <br>
I have tried printing form.erorrs and it gives me the following:
<ul class="errorlist"><li>uploaded_images<ul class="errorlist"><li>“b'\xbd\x06D\xcd3\x91\x85,\xdf\xa5K\n'” is not a valid value.</li></ul></li></ul>
I am not sure how to interpret this general error. Been searching for quite some time but couldn't find an answer.
Edit:
Im also encountering a "This field is required." error
Perhaps this screenshot may help with debugging:
I must be missing something simple but I just can't find it!!
Another pair of eyes to help me sieve through would be very appreciated!
views.py
from django.shortcuts import render,redirect
from django.views.generic.edit import FormView
from .forms import BRForm
from .models import *
class BRHomeView(FormView):
form_class = BRForm
model = TargetImage
template_name = 'br/br-home.html'
context_object_name = 'bankrecon'
def get(self, request):
form = BRForm(request.POST, request.FILES)
return render(request, self.template_name, {'form': form, 'title': 'Bank Reconcilation'})
def post(self, request, *args, **kwargs):
form_class = self.get_form_class()
form = self.get_form(form_class)
files = request.FILES.getlist('uploaded_images')
print("POST")
print(request.POST)
print("FILES")
print(request.FILES)
print(form.errors)
if form.is_valid():
form.save()
return redirect('br-home')
models.py
from django.db import models
# Create your models here.
class UploadedImages(models.Model):
image_files = models.ImageField(null=True, blank=True, upload_to='images/')
class TargetImage(models.Model):
invoice_date = models.DateTimeField()
recon_date = models.DateTimeField()
uploaded_images = models.ManyToManyField(UploadedImages)
def __str__(self):
return self.invoice_date
forms.py
from django import forms
from django.core.validators import FileExtensionValidator
from .models import *
class BRForm(forms.ModelForm):
class Meta:
model = TargetImage
fields = ('invoice_date', 'recon_date', 'uploaded_images')
widgets = {
'invoice_date': forms.DateInput(attrs={'type': 'date'}),
'recon_date': forms.DateInput(attrs={'type': 'date'}),
'uploaded_images': forms.ClearableFileInput(attrs={'multiple': True, 'accept':'.jpeg, .png, .jpg'}),
}
relevant template code:
<div class="mt-5 d-flex justify-content-center">
<form action="" enctype="multipart/form-data" method="POST">
{% csrf_token %}
{{ form.as_p }}
<div class="d-flex justify-content-center">
<button class="btn btn-success mt-3" type="submit">Submit</button>
</div>
</form>
</div>
Extra info: My request.POST and request.FILES seems to be working fine:
POST
<QueryDict: {'csrfmiddlewaretoken': ['hiding this'], 'invoice_date': ['2021-02-01'], 'recon_date': ['2021-02-01']}>
FILES
<MultiValueDict: {'uploaded_images': [<InMemoryUploadedFile: first_slide (1).jpg (image/jpeg)>, <InMemoryUploadedFile: fourth_slide (1).jpg (image/jpeg)>]}>
Thank you all!!
Some errors that I see in your code:
You're trying to render a POST request in your get method.
You're not passing any data from POST request to your form instance. That's why is_valid() is returning False.
Change your code to something like this and see if it works:
...
def get(self, request):
form = BRForm()
return render(request, self.template_name, {'form': form, 'title': 'Bank Reconcilation'})
def post(self, request, *args, **kwargs):
form = BRForm(request.POST)
if form.is_valid():
form.save()
return redirect('br-home')
I have managed to solve this issue! <br>
Link: https://stackoverflow.com/a/60961015/10732211 <br>
I overhauled the entire thing and followed the above link. Probably the models relations have some issues that does not work. <br>
views.py
class BRHomeView(FormView):
# model = TargetImage
template_name = 'br/br-home.html'
context_object_name = 'bankrecon'
def get(self, request):
form = BRFormExtended()
return render(request, self.template_name, {'form': form, 'title': 'Bank Reconcilation'})
def post(self, request, *args, **kwargs):
form = BRFormExtended(request.POST,request.FILES)
files = request.FILES.getlist('image_files')
if form.is_valid():
print("Form Valid")
print(form.cleaned_data['invoice_date'])
print(form.cleaned_data['recon_date'])
user = request.user
invoice_date = form.cleaned_data['invoice_date']
recon_date = form.cleaned_data['recon_date']
target_image_obj = TargetImage.objects.create(user=user,invoice_date=invoice_date, recon_date=recon_date)
for file in files:
UploadedImage.objects.create(target_image=target_image_obj,image_files=file)
else:
print("Form Invalid")
return redirect('br-home')
forms.py
class BRForm(forms.ModelForm):
class Meta:
model = TargetImage
fields = ['invoice_date', 'recon_date']
widgets = {
'invoice_date': forms.DateInput(attrs={'type': 'date'}),
'recon_date': forms.DateInput(attrs={'type': 'date'}),
}
class BRFormExtended(BRForm):
image_files = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
class Meta(BRForm.Meta):
fields = BRForm.Meta.fields + ['image_files',]
models.py
from django.contrib.auth.models import User
from django.utils import timezone
class TargetImage(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE)
uploaded_date = models.DateTimeField(default=timezone.now)
invoice_date = models.DateTimeField()
recon_date = models.DateTimeField()
def __str__(self):
return self.user.__str__()
class UploadedImage(models.Model):
target_image = models.ForeignKey(TargetImage, on_delete=models.CASCADE)
image_files = models.ImageField(null=True, blank=True, upload_to='images/')
Also, it would be helpful to have a media root folder and edits to urls.py is also required.
urls.py
from django.urls import path
from .views import BRHomeView
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('', BRHomeView.as_view(), name='br-home'),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
settings.py
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
STATIC_URL = '/static/'
STATICFILES_DIRS = (os.path.join(BASE_DIR, "static"),)
Hopefully this will help someone!
Related
I'm running some tests for my app 'ads', but when I try to test the CreateView it fails with the following message:
AssertionError: 'just a test' != 'New title'
Here's the test:
class AdTests(TestCase):
def setUp(self):
self.user = get_user_model().objects.create_user(
username='test_user',
email='test#email.com',
password='secret'
)
self.ad = Ad.objects.create(
title='just a test',
text='Ehy',
owner=self.user
)
def test_ad_create_view(self):
response = self.client.post(reverse('ads:ad_create'), {
'title': 'New title',
'text': 'New text',
'owner': self.user.id,
})
self.assertEqual(response.status_code, 302)
self.assertEqual(Ad.objects.last().title, 'New title')
self.assertEqual(Ad.objects.last().text, 'New text')
So it could be that the test fails in creating a new ad, and then it compares the fields with the first ad in the setUp method.
I upload the rest of the code if it can help:
urls.py
from django.urls import path, reverse_lazy
from . import views
app_name='ads'
urlpatterns = [
path('', views.AdListView.as_view(), name='all'),
path('ad/<int:pk>', views.AdDetailView.as_view(), name='ad_detail'),
path('ad/create',
views.AdCreateView.as_view(success_url=reverse_lazy('ads:all')), name='ad_create'),
...
]
models.py
class Ad(models.Model) :
title = models.CharField(
max_length=200,
validators=[MinLengthValidator(2, "Title must be greater than 2 characters")]
)
price = models.DecimalField(max_digits=7, decimal_places=2, null=True)
text = models.TextField()
"""We use AUTH_USER_MODEL (which has a default value if it is not specified in settings.py) to create a Foreign Key relationship between the Ad model
and a django built-in User model"""
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
comments = models.ManyToManyField(settings.AUTH_USER_MODEL, through='Comment', related_name='comments_owned')
picture = models.BinaryField(null=True, editable=True)
tags = TaggableManager(blank=True)
content_type = models.CharField(max_length=256, null=True, help_text='The MIMEType of the file')
favorites = models.ManyToManyField(settings.AUTH_USER_MODEL, through='Fav', related_name='favorite_ads')
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
views.py
class AdCreateView(LoginRequiredMixin, View):
template_name = 'ads/ad_form.html'
success_url = reverse_lazy('ads:all')
def get(self, request, pk=None):
form = CreateForm()
ctx = {'form': form}
return render(request, self.template_name, ctx)
# Pull data
def post(self, request, pk=None):
form = CreateForm(request.POST, request.FILES or None)
if not form.is_valid():
ctx = {'form': form}
return render(request, self.template_name, ctx)
pic = form.save(commit=False)
pic.owner = self.request.user
pic.save()
form.save_m2m()
return redirect(self.success_url)
forms.py (the view uses it especially to check and save the image)
class CreateForm(forms.ModelForm):
max_upload_limit = 2 * 1024 * 1024
max_upload_limit_text = naturalsize(max_upload_limit)
# Call this 'picture' so it gets copied from the form to the in-memory model
# It will not be the "bytes", it will be the "InMemoryUploadedFile"
# because we need to pull out things like content_type
picture = forms.FileField(required=False, label='File to Upload <= ' + max_upload_limit_text)
upload_field_name = 'picture'
class Meta:
model = Ad
fields = ['title', 'text', 'price', 'picture', 'tags']
# Check if the size of the picture is less than the one specified (see above).
def clean(self):
cleaned_data = super().clean()
pic = cleaned_data.get('picture')
if pic is None:
return
if len(pic) > self.max_upload_limit:
self.add_error('picture', "File must be < " + self.max_upload_limit_text + " bytes")
# Convert uploaded File object to a picture
def save(self, commit=True):
instance = super(CreateForm, self).save(commit=False)
# We only need to adjust picture if it is a freshly uploaded file
f = instance.picture # Make a copy
if isinstance(f, InMemoryUploadedFile): # Extract data from the form to the model
bytearr = f.read()
instance.content_type = f.content_type
instance.picture = bytearr # Overwrite with the actual image data
if commit:
instance.save()
self.save_m2m()
return instance
I hope it is useful, thanks in advance!
According to Django Doc
Create View:
A view that displays a form for creating an object, redisplaying the form with validation errors (if there are any) and saving the object.
This is not a Valid way to do create View based on my experience. Check the doc Doc here.
if i understand what you are talking about You want to submit Ad Model using Create View, if you want to submit it in form You can something like this:
from django.views.generic import CreateView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.urls import reverse_lazy,
class PostCreativeView(LoginRequiredMixin, CreateView):
model = #Your Model
fields = [#Fields of the model You want to submit]
template_name = #html template you want to submit the form
success_url = reverse_lazy(#url for redirected user when the form is submitted)
def form_valid(self, form):
form.instance.user = self.request.user
return super (PostCreativeView, self).form_valid(form)
in the form template you can add:
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Save">
</form>
for styling you can follow this: Answer
I stack. I try many thinks. I want to put 2 forms in my mainpage. Models, forms in index.html, ModelForm, save(), urls.. I think everything ok. But submit button do nothing.
#models.py
from django.db import models
class Iletisim(models.Model):
DURUM = [
('KT', 'Keşif Talebi'),
('AB', 'Arıza Bildirimi'),
('IL', 'İletişimden'),
]
SINIF = [
('Konut', (
('SI', 'Site '),
('DA', 'Apartman Dairesi'),
('VI', 'Yazlık/Bağ/Villa'),
)
),
('İşyeri', (
('OF', 'Ofis/Büro/Dükkan'),
('FA', 'Fabrika/Şantiye/Otel/Okul'),
)
),
('DG', 'Diğer'),
]
name = models.CharField(max_length=100, verbose_name="Ad/Soyad")
phone = models.CharField(max_length=100, verbose_name="Telefon")
address = models.CharField(max_length=250, verbose_name="Adresi")
message = models.CharField(max_length=1000, verbose_name="Mesaj")
email = models.EmailField(max_length=40, verbose_name="E-Posta")
province= models.CharField(max_length=40,verbose_name="Şehir")
tarih = models.DateTimeField(default=None)
basvuru = models.CharField(max_length=2, choices=DURUM)
sinif = models.CharField(max_length=2, choices=SINIF)
class Meta:
ordering = ["tarih", "email"]
verbose_name = "Mesaj"
verbose_name_plural = "Mesajlar"
def __str__(self):
return self.basvuru
My forms folder
from django.shortcuts import redirect, render
from django.forms import ModelForm
from apps.giris.models import Iletisim
class Kesif_Form(ModelForm):
class Meta:
model = Iletisim
fields = '__all__'
def kesif_kayit(request):
if request.method=='POST':
form = Kesif_Form(request.POST)
if form.is_valid():
yeni_kesif = Iletisim()
yeni_kesif.name = request.POST.get("name")
yeni_kesif.phone = request.POST.get("phone")
yeni_kesif.address = request.POST.get("address")
yeni_kesif.message = request.POST.get("message")
yeni_kesif.email = request.POST.get("email")
yeni_kesif.province = request.POST.get("province")
yeni_kesif.tarih = request.POST.get("tarih")
yeni_kesif.basvuru = request.POST.get("basvuru")
yeni_kesif.sinif = request.POST.get("sinif")
yeni_kesif.save()
return redirect('index')
else:
form = Kesif_Form()
context={'form' : form}
return render(request,'index.html',context)
Main class
...
from forms.formlar import Kesif_Form
class Anasayfa_View(TemplateView, Kesif_Form):
template_name = 'index.html'
def get_context_data(self, **kwargs):
...
context['kform'] = Kesif_Form
...
return context
index.html
...
{{ kform.errors }}
<form action="{% url 'kesif' %}" method="POST" class="php-email-form php-email-form animate__animated animate__fadeInRight">
{{ kform.errors }}
{{ kform }}
<input type="submit" value="gir">
</form>
...
urls.py
...
from forms.formlar import kesif_kayit
urlpatterns = [
path('admin/', admin.site.urls),
path('', Anasayfa_View.as_view(), name='grsndx'),
path('kesif/', kesif_kayit, name='kesif'),
path('<str:ktgr>/', Detaylar_View.as_view(), name='dtyndx'),
path('<str:ktgr>/<str:bslk>/', Detay_View.as_view(), name='dtydty'),
]
and submit not work, every fields in form, I want 2 forms but I have not work anyone.
help..
structure
-project
-apps
-giris
-models.py
+detay
...
+env
-fls
-settings
-urls
-forms
-formlar.py
...
-templates
-index.html
...
-manage.py
...
If you are using Django model form than you have to do something like this first create form class
class Kesif_Form(ModelForm):
class Meta:
model = Iletisim
fields = '__all__'#here you to defined specific you field or all the field
than you have to submit it like this
def kesif_kayit(request):
if request.method=='POST':
form = Kesif_Form(request.POST)
if form.is_valid():
form.save()
return redirect('index')
else:
form = Kesif_Form()
context={'form' : form}
return render(request,'index.html',context)
you don't have save it manually Django Model Form will save it for you.
I was trying out ImageField in the models, But Image upload do not work when I try to upload from the forms. But it works when I upload it from the admin page.
Any way to debug is also helpful
My model-
class Inventory(models.Model):
"""docstring for Inventory"""
name = models.CharField(max_length=100,default='Something')
image = models.ImageField(null=True, blank=True)
description = models.CharField(max_length=100, default='Describe Something')
price = models.IntegerField( default=0)
My Form-
class InventoryForm(forms.ModelForm):
class Meta:
model = Inventory
fields = ['name','description','price','image']
widgets = {
'name' : forms.TextInput(attrs={"placeholder":"Name", "onfocus":"this.value = '';","onblur":"if (this.value=='') this.value = this.defaultValue","required":""}),
'description' : forms.TextInput(attrs={"placeholder":"Email", "onfocus":"this.value = '';","onblur":"if (this.value=='') this.value = this.defaultValue","required":""}),
'price' : forms.NumberInput(attrs={"placeholder":"Price","onfocus":"this.value = '';","onblur":"if (this.value=='') this.value = this.defaultValue","required":""}),
}
Settings -
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, "media/")
template -
<form action="" method="post" enctype="multipart/form-data"> {% csrf_token %}
{{form}}
<input type="submit" value="Send">
</form>
url -
from django.contrib import admin
from django.urls import path, include, re_path
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('',include('inventory.urls')),
path('<int:id>',include('inventory.urls')),
path('admin/', admin.site.urls),
]+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
My Views-
def index(request):
form = InventoryForm(request.POST or None)
if form.is_valid():
form.save()
form = InventoryForm()
else:
form = InventoryForm()
inventory = Inventory.objects.all()
context = {'form' : form, 'all_inventory' : inventory}
return render(request, 'inventory/index.html',context)
Regards,
Deepak Dash
In your views.py. Change:
form = InventoryForm(request.POST or None)
to
form = InventoryForm(request.POST, request.FILES or None)
Because, Files in django post request are in request.FILES dictionary. You have to send that to forms as well.
How about adding upload_to in models in image field and add default image also this will come in handy later on or not your choice:
models.py
class Inventory(models.Model):
"""docstring for Inventory"""
name = models.CharField(max_length=100,default='Something')
image = models.ImageField(upload_to='/your_file_name/',default='default.png')
description = models.CharField(max_length=100, default='Describe Something')
price = models.IntegerField(default=0)
I am following a tutorial in which we will create a form to hold simple object parameters.
Here's the code:
forms.py
from django.forms import ModelForm
from .models import Item
class ItemForm(ModelForm):
class Meta:
model = Item
fields = ['item_name', 'item_desc', 'item_price', 'item_image']
models.py
from django.db import models
class Item(models.Model):
def __str__(self):
return self.item_name
item_name = models.CharField(max_length = 200)
item_desc = models.CharField(max_length= 200)
item_price = models.IntegerField()
item_image = models.CharField(max_length=500, default ="https://i.jamesvillas.co.uk/images/jvh/holiday-destinations/resort/food-placeholder.jpg" )
urls.py
from . import views
from django.urls import path
urlpatterns = [
path('', views.index, name = 'index'),
path('item/', views.item, name = 'item'),
path('info/', views.info, name = "info"),
path('<int:item_id>/', views.detail, name = "detail" ),
#add form
path('add', views.create_item, name = "create"),
]
views.py
from django.shortcuts import render, redirect
from django.http import HttpResponse
from .models import Item
from django.template import loader
from .forms import ItemForm
#Some code here
def create_item(request):
form = ItemForm(request.POST or None)
if (form.is_valid()):
form.save()
return redirect('food/index')
return render(request, 'food/item-form.html', {'form': form})
food/item-form.html
<form method = "POST">
{% csrf_token %}
{{ form }}
<button type= "Submit" >Save</button>
</form>
Now when I go to http://localhost:8000/food/add, it displays an empty page! I have followed the tutorial the exact same way then why is My project not working?
correct your views.py
from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import NameForm
def get_name(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = NameForm(request.POST)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
# ...
# redirect to a new URL:
return HttpResponseRedirect('/thanks/')
# if a GET (or any other method) we'll create a blank form
else:
form = NameForm()
return render(request, 'name.html', {'form': form})
processor_for.py
from django import forms
from django.http import HttpResponseRedirect
from mezzanine.pages.page_processors import processor_for
from .models import Book
class BookForm(forms.Form):
name = forms.CharField()
email = forms.EmailField()
#processor_for(Author)
def author_form(request, page):
form = BookForm()
if request.method == "POST":
form =BookForm(request.POST)
if form.is_valid():
# Form processing goes here.
redirect = request.path + "?submitted=true"
return HttpResponseRedirect(redirect)
return {"form": form}
models.py
from django.db import models
from time import time
class Book(models.Model):
book_name= models.CharField(max_length=200, unique = True)
def __unicode__(self):
return self.book_name
views.py
def create_book (request):
if request.POST:
form = BookForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return HttpResponseRedirect('/all/')
else:
form = BookForm()
args= {}
args.update(csrf(request))
args['form'] = form
return render_to_response('create_Book.html', args)
urls.py
urlpatterns += patterns('',
url(r'^/xyz/$', create_book))
create_Book.html
<form action="/xyz/" method="post" enctype="multipart/form-data">{% csrf_token %}
{{form.as_ul}}
<input type="submit" name="submit" value="create"/>
</form>
This is what i am doing but still i am unable to access form. Where i am doing wrong. will be grateful to you. Please mark that what's wrong in code?
as per you code and your explanation in question .please see your code in urls.py
urlpatterns += patterns('',
url(r'^xyz/$', create_book)) # you should write like ^xyz/$
Please follow django doc
Two Syntax Problems:
1) Always define your processor name in " " like #processor_for("Author")
2) urls for page processors like :
url("^xyz/$", "mezzanine.pages.views.page", {"slug": "Author"}, name="Author"),