after uploading the image to a form when i submit the form it still shows "the field is required" error
in models.py:
class Members(models.Model):
image=models.ImageField(upload_to="images/",default='')
in forms.py:
class CreateOne(forms.Form):
image=forms.ImageField(required=True)
in create.html:
<form class="form-inline" action="create" method="POST"
enctype="multipart/form-data" novalidate>
in views.py:
def create(request):
member = Members(image=request.FILES['image'])
if request.method == 'POST':
form = forms.CreateOne(request.POST)
if form.is_valid():
member.save()
return redirect('/')
else:
form = CreateOne()
I think you understand the way to use a Form the wrong way. The idea of such Form when you write some_form.save() it makes the changes (and for example create a model instance and save it to the database).
Since most forms (like probably this one) are related to a single model, Django has a ModelForm, which offers extra convenience:
class CreateOne(forms.ModelForm):
image=forms.ImageField(required=True)
class Meta:
model = Members
fields = ['image']
Then we can make a view that will create an instance in case of a valid form with:
def create(request):
if request.method == 'POST':
form = forms.CreateOne(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect('/')
else:
form = CreateOne()
return render(request, 'some_template.html', {'form': form}
You probably also do not want to redirect in case the form was not valid, since then you probably want to give the user feedback that the form was not valid (and show the corresponding errors).
Related
I'm trying to show the user the details they entered in an editable format as we can see in
Edit:
Changed the code and tried to explain the question in a better way
view.py
def change_contact(request, contact_id):
try:
form = AddToPhoneBookForm(instance=Contact.objects.get(pk=contact_id))
form.instance.user = request.user
if form.is_valid():
form.save()
form = AddToPhoneBookForm()
context = {
'form': form
}
return render(request, "CallCenter/add_to_phone_book.html", context)
forms.py
class AddToPhoneBookForm(forms.ModelForm):
class Meta:
model = Contact
fields = ['first_name', 'last_name', 'phone_number', 'phone_book']
This view loads the forms as I want it to but the changes made here is not reflected in the database. Where am I going wrong?
For this you need to use get() instead of filter() .Get returns the single object whereas filter will returns the queryset
contact = Contact.objects.get(phone_book__id=phone_book_id)
And in template you don't need to use forloop {{contact.first_name}} will give the result for you
EDIT: you will save the data with POST request so you need to handle for POST request also and there are a lots of things you need to know please read the docs
And change your view like this
def change_contact(request, contact_id):
contact = Contact.objects.get(pk=contact_id)
form = AddToPhoneBookForm(instance=contact)
if request.method == 'POST':
form = AddToPhoneBookForm(request.POST,instance=contact)
if form.is_valid():
obj=form.save(commit=False)
obj.user = request.user
obj.save()
return redirect('some-path')
context = {
'form': form,'contact':contact
}
return render(request, "CallCenter/add_to_phone_book.html", context)
I got the problem with form that is not saving to the datebase.
views.py
...
#login_required
def create_task(request):
if request.method == 'POST':
form = CreateTaskForm(request.POST, instance=request.user)
if form.is_valid():
form.save()
return redirect('index')
else:
form = CreateTaskForm()
context = {'form': form}
return render(request, 'tasks/task_form.html', context)
...
forms.py
from django import forms
from .models import Task
class CreateTaskForm(forms.ModelForm):
class Meta:
model = Task
fields = (
'name',
'end_date',
'description',
)
Is it the problem with a create_task view or CreateTaskForm?
The problem is with the create_task view:
if request.method == 'POST':
form = CreateTaskForm(request.POST)
if form.is_valid():
# if you have user in your model task make commit to false then set the user
form.save(commit=false)
form.user = request.user
#if not save directly you form
form.save()
return redirect('index')
then check if your url is:
path('create_task', create_task, name="create_task")
First off, since you are using POST, which means you are creating, there is no need for instance=request.user - which is used to compare previous data against new data provided by the form. Looking at your form, it does not look like it has anything to do with the user.
Second, you are not displaying or returning form errors. So it may be silently failing validation at the model level without your knowledge. Try adding a return with form errors.
#login_required
def create_task(request):
form = CreateTaskForm()
if request.method == 'POST':
form = CreateTaskForm(request.POST)
if form.is_valid():
form.save()
return redirect('index')
context = {'form': form}
return render(request, 'tasks/task_form.html', context)
You can look in form.errors on the template side to see validation errors.
I'll address this question using a base setup:
# models.py
class MyModel(models.Model):
required_field = models.CharField("some label", max_length=10)
another_required_field = models.CharField("some label", max_length=10)
checkbox = models.BooleanField("some label")
# forms.py
class MyForm(forms.ModelForm):
class Meta:
model = MyModel
# views.py
class MyView(FormView):
form_class = MyForm
template_name = 'some-template.html'
Now suppose I check the checkbox and fill just one of the required fields. The form obviously doesn't pass validation and gets back with errors and all. Problem is, the value of the checkbox comes back unchecked. This is not a big deal with just one BooleanField, but I'm working on a project where I have tons of checkboxes. Check them all from scratch is rather frustrating.
So I had a check on django's documentation and stumbled upon this paragraph regarding BooleanFields:
Since all Field subclasses have required=True by default, the validation condition here
is important. If you want to include a boolean in your form that can be either True or
False (e.g. a checked or unchecked checkbox), you must remember to pass in
required=False when creating the BooleanField.
And I did this:
# forms.py
class MyForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs)
for field in self.fields:
if isinstance(field, forms.CheckboxInput):
self.fields[field].required = False
class Meta:
model = MyModel
but it didn't work. Again, checkboxes lose their state after the form didn't pass validation, so I guess that was not what I was looking for.
So my question is, is there a way to achieve that? I'm pretty sure there should be one, it would be great if some of you could at least drive me in the right direction. Thanks :-)
EDIT
After a bit of debugging, I solved the issue. Turns out I was using a custom template for crispy forms checkboxes, and I found a little bug in there.
Your view would need to populate the form from the request.POST dictionary as such:
def your_view(request):
form = MyForm(request.POST or None)
if request.method == 'POST' and form.is_valid():
form.save()
# do whatever esle
return render(request, 'your-template.html', {'form': form})
Unless you pass the request.POST data, and/or an instance of the model you're editing, your form will be un-bound, and therefore not show any values that exist either in the POST data or from your model. If you're editing an instance, it would look like:
def your_view(request, id):
my_model_instance = MyModel.objects.get(pk=id)
form = MyForm(request.POST or None, instance=my_model_instance)
if request.method == 'POST' and form.is_valid():
form.save()
# do whatever esle
return render(request, 'your-template.html', {'form': form})
maybe the problem is on your view:
view exemple:
def view(request):
if request.method == 'POST':#bound the form wit data from request.Post
form = MyForm(request.POST)
if form.is_valid():
#do somthing
form.save()
#if form not valid render the page.html with form that has request.Post data
return render(request,'some-template.html',{'form': form})
else:
form = MyForm()
return render(request, 'some-template.html',{'form': form})
So, the first part is pretty clear.
customer = Customer.objects.get(pk=1)
customer.pk = None
customer.save() # Saved a new instance.
# But i want to modify it
The problem here is that i want to modify that instance, before saving. for that i have to render it on the form in HTML.
How to achieve that?
Suggestions needed.
Greetings.
You modify the pk after the form has been submitted.
You pass customer as instance to a CustomerForm and let the form save a new object. Something like:
class CustomerForm(forms.ModelForm):
class Meta:
model = Customer
def my_view(request):
customer = Customer.objects.get(pk=1)
customer.pk = None
if request.method == 'POST':
form = CustomerForm(instance=customer)
if form.is_valid():
customer = form.save()
return redirect('...')
else:
form = CustomerForm(instance=customer)
return render(request, 'template', {'form': form})
I've created a model form which is then rendered in a context processor as the form is included on every page. Once the form is submitted it should re-direct to a 'thank you' page. However it just seems to re-load the page and remove the form. I had it all working when rendering on a page via a URL. Since moving the function to my context processor it doesn't redirect correctly.
It also saves the information that's provided into the model, in the admin. So I'm guessing it is something to do with redirect.
Here is my context processor:
from django.conf import settings
from contact_enquiries import forms
from django.shortcuts import render
from django.http import HttpResponseRedirect
def contact(request):
if request.method == 'POST':
form = forms.ContactUsForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/thanks/')
else:
form = forms.ContactUsForm()
return {
'contact_form' : form,
}
forms.py
class ContactUsForm(ModelForm):
class Meta:
model = ContactUs
fields = ['name', 'contact_number', 'email', 'enquiry']
models.py
class ContactUs(models.Model):
name = models.CharField(max_length=200)
contact_number = models.IntegerField(max_length=50)
email = models.EmailField(max_length=300)
enquiry = models.TextField()
class Meta:
verbose_name_plural = "Contact Us"
def __unicode__(self):
return self.name
A context processor should always return a dictionary, it shouldn't return an http response.
One option is to make your contact form post to a different view. You do this by changing the action attribute of the form in your template.
<form action="{% url 'contact' %}" method="post">
Your contact view and url patterns would look something like this:
url('^/contact/$', contact, name="contact"),
def contact(request):
if request.method == 'POST':
form = forms.ContactUsForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/thanks/')
else:
form = forms.ContactUsForm()
return render(request, "contact.html", {
'contact_form' : form,
})
Your context processor then simplifies to:
def contact(request):
form = forms.ContactUsForm()
return {'contact_form' : form}