MODELS.PY
class Campaign(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
campaign_image = models.ImageField(default="profilepic.jpg",upload_to="campaign_pictures")
FORMS.PY
class RaiseFundsFrom3(forms.ModelForm):
class Meta:
model = Campaign
fields = ['campaign_image']
VIEWS.PY
#login_required
def raise_funds_medical_3(request):
if request.method == 'POST':
form = RaiseFundsFrom3(request.POST, request.FILES or None, instance=request.user)
if form.is_valid():
check = form.save(commit=False)
check.save()
return HttpResponse('form worked')
else:
form = RaiseFundsFrom3()
return render(request,'funds/raise_funds_medical_3.html',{'form':form})
URLS.PY
path('raise/medical/photo', views.raise_funds_medical_3, name="raise_funds_medical_3"),
raise_funds_medical_3.html
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="form-group pt-2">
<small>Photo formats must be PNG / JPG / JPEG</small>
<input type="file" name="campaign_image" />
</div>
<button class="btn btn-lg button_bfg_blue" type="submit"> <small><b> NEXT </b></small> </button>
</form>
on form submit, i do not get any error, but image is not uploaded to the required folder.
however, in the raise_funds_medical_3 function within views.py, if i remove instance=request.user, the image gets uploaded but i get following error : NOT NULL constraint failed: funds_campaign.user_id
Your form is a ModelForm for a Campaign, so its instance needs to be a Campaign. Don't assign request.user as its instance!
Now, your form isn't including the user field which is required to save a Campaign, so you should assign that yourself in the view before saving to the database:
campaign = form.save(commit=False) # this gives your the form's instance
campaign.user = request.user # this assigns the user
campaign.save() # this commits to the database
Also you should handle the case where the form isn't valid. This is quite simple, just un-indent the last return in your view function, so that return render(...) is also called in case the form isn't valid.
Finally, instead of returning a response when the form is valid, it's good practice to redirect to another view. This way, when the user refreshes the page, the form isn't submitted again. Your final code should look like this:
#login_required
def raise_funds_medical_3(request):
if request.method == 'POST':
form = RaiseFundsFrom3(request.POST, request.FILES or None)
if form.is_valid():
check = form.save(commit=False)
check.user = request.user
check.save()
return redirect(<url_pattern>)
else:
form = RaiseFundsFrom3()
return render(request,'funds/raise_funds_medical_3.html',{'form':form})
Supplementary answer to dirkgroten's one
I have come to completely hate the conventional structuring of a Django Function-based View. They can be re-factored by inverting the validity test and adding one line so that one and only one instantiation of a form is present. The result is IMO far easier to read, and easily generalizes for a view displaying two or more forms.
def raise_funds_medical_3(request):
args = [request.POST, request.FILES or None] if request.method == "POST" else []
form = RaiseFundsFrom3(*args)
if request.method != "POST" or not form.is_valid():
# unbound form or form not valid
return render(request,'funds/raise_funds_medical_3.html',{'form':form})
# form is valid so do the processing and redirect
check = form.save(commit=False)
check.user = request.user
check.save()
return redirect(<url_pattern>)
If you want to process >1 form, the test becomes
if request.method != "POST" or any(
[ not form.is_valid(), not form2.is_valid(), ...]):
which forces evaluation of .is_valid() for all forms, even if the first was not valid, so that all the error messages are shown to the user.
In a complex business application, the processing of a successful form submission may be quite a few more lines of code than this simple example. Having it at the end, not indented, isolated from all the boilerplate save the return redirect(...), makes things much easier!
Related
I looked at other similar questions on Stackoverflow, but those situations do not apply to me.
I have a form with a Queue field that is a required field. This form is used in multiple places and in one such instance, I don't want the Queue field to be shown to the user. So, I simply did not render it on the template. But because this a required field, the form won't submit. How do I pre-populate this field while at the same time hiding it from the user?
I cannot make changes to the model or the form's save methods because this form is also used at other places.
forms.py
class PublicTicketForm(CustomFieldMixin, forms.Form):
queue = forms.ChoiceField(
widget=forms.Select(attrs={'class': 'form-control'}),
label=_('Queue'),
required=True,
choices=()
)
views.py:
def no_queue(request):
if request.method == 'POST':
form = PublicTicketForm(request.POST, request.FILES)
form['queue'] = 9 # Tried to assign queue value to field, did not work
if form.is_valid():
if text_is_spam(form.cleaned_data['body'], request):
# This submission is spam. Let's not save it.
return render(request, template_name='helpdesk/public_spam.html')
else:
form.save()
else:
form = PublicTicketForm(initial={'queue': 9}) # tried this one too, did not work either
return render(request, 'helpdesk/no_queue.html', {'form': form})
The choices for this form were populated in the views, but because I'm not rendering it in the template, I did not do it.
You can use formsets to be able to assign a specific value and show specific inputs to the user like this
Don’t make a hidden field. Create another form class that doesn’t contain the field (subclassing will prevent repetition), then set the value in the view.
instance = form.save(commit=False)
instance.queue = 9
instance.save()
You can override POST data.
if request.method in ('POST', 'PUT'):
data = request.POST.copy()
data['queue'] = 9
form = PublicTicketForm(data, request.FILES)
I was able to do something like this in the template and that worked!
<input type="hidden" name="queue" value="9" />
I just did this last night!
In forms.py declare the field with the HiddenInput widget (be sure to render it):
scope = CharField(max_length=60,widget=HiddenInput())
Then, in views.py you can apply the initial value:
form = MyForm(initial={'scope': 'public'})
Or using a CBV:
initial = {'scope':'public'}
I am trying to assign a session variable based on a model or database table on my Django site. In other words, on the first use, I want the user to select a county from a dropdown list and write the name of that county or pk to a session variable. From therek, that data gets pulled into context_processor before hitting the template. Right now, the error I'm getting is
(1062, "Duplicate entry '1' for key 'county_id'")
I'm not sure if it is trying to write multiple entries into the database, but I don't really want anything databased as you would other data. I just want a session variable stored. I am sure my problem is my view, but I can't seem to get it right. In case you couldn't tell, I'm pretty new at this.
I have a model.py defined that accesses another table of counties.
class NonUserCounty(models.Mdel):
county = models.ForeignKey(County)
def __unicode__(self):
return self.county
I have defined a form.py
class NonUserCountyForm(forms.ModelForm):
class Meta:
model = NonUserCounty
And a views.py
def Welcome(request):
if request.method == 'POST':
form = NonUserCountyForm(request.POST)
if form.is_valid():
mycounty = form.cleaned_data['county']
request.session['mycounty'] = mycounty
form.save()
return HttpResponseRedirect('/')
else:
form = NonUserCountyForm()
context = {'form': form}
return render_to_response('welcome.html', context, context_instance=RequestContext(request))
A Context processor
def mynews(request):
now = datetime.now()
if not request.user.is_authenticated():
if not "mycounty" in request.GET:
MyNews = News
county = County
else:
return HttpResponseRedirect('/welcome/')
else:
user = request.user.get_profile()
county = user.county.all()
MyNews = News
And my template....
<form action="" method="post">
{% csrf_token %}
{{ form }}
<p><input type="submit" alt="register" value="Sign Up" /></p>
Why are you calling form.save() if you don't want to save anything in the database? Just remove that line and it should work.
I have created a Class view in views.py of the django application.
class HelloTemplate(TemplateView):
template_name = "index.html"
def get_context_data(self, **kwargs):
context = super(HelloTemplate, self).get_context_data(**kwargs)
return context
Now I have a form defined in the html page:
<form method="get">
<input type="text" name="q">
<input type="text" name="q1">
<input type="submit" value="Search">
</form>
As you can see, I am submitting the form on the same page.
Now I want to get the form submitted values in my HelloTemplate class. I don't want to create another class or methods outside the existing class.
Also, I would like to send an error message to the html form if data is not validated in the django.
I don't know how to do this, please help me out.
You need to define get (because your form defined with get method <form method="get">) method in view class:
class HelloTemplate(TemplateView):
template_name = "index.html"
def get_context_data(self, **kwargs):
context = super(HelloTemplate, self).get_context_data(**kwargs)
return context
def get(self, request, *args, **kwargs):
q = request.GET.get('q')
error = ''
if not q:
error = "error message"
return render(request, self.template_name, {'error': error})
More information in django docs here Introduction to Class-based views
There's only one value, and it's in request.GET['q'].
Quick response, I can show you what I did a while ago for a review form (for people to create a new review, one of my models):
def review_form_view(request):
c = {}
c.update(csrf(request))
a = Review()
if request.method == 'POST':
review_form = Review_Form(request.POST, instance=a)
if review_form.is_valid():
a = review_form.save()
return HttpResponseRedirect('../dest_form_complete')
pass
else:
review_form = Review_Form(instance=a)
return render_to_response('../review_form.html', {
'review_form': review_form,
}, context_instance=RequestContext(request))
If you have a user model, comment model, etc. you can probably use something similar to this. Very (very) roughly put, the request is the input that the user fills out in the form, 'POST' is the method called that lets the server know you are adding entries to your database, and is_valid() validates the data according to your models.py parameters (can name be NULL? Is age an integer? etc).
Take a look at https://docs.djangoproject.com/en/dev/topics/forms/ as well for more examples and explanation.
I am trying to use customize the output of my form by this method. For example:
<div class="fieldWrapper">
{{ form.message.errors }}
<label for="id_message">Your message:</label>
{{ form.message }}
</div>
If I render the form as form.as_p, everything works fine, but rendering the fields individually does not work.
I have some fields that I want to be hidden so am trying to render each individually. The fields I am trying to hide are given null=True, blank=True attributes in the model class, and are therefore not required.
No errors are being shown, rather the page is refreshed and the data is not updated. I'm not sure what I could be missing given these factors. Here is the view:
The view is from userena:
#secure_required
#permission_required_or_403('change_profile', (get_profile_model(), 'user__username', 'username'))
def profile_edit(request, username, edit_profile_form=EditProfileForm,
template_name='userena/profile_form.html', success_url=None,
extra_context=None, **kwargs):
"""
Edit profile.
Edits a profile selected by the supplied username. First checks
permissions if the user is allowed to edit this profile, if denied will
show a 404. When the profile is successfully edited will redirect to
``success_url``.
:param username:
Username of the user which profile should be edited.
:param edit_profile_form:
Form that is used to edit the profile. The :func:`EditProfileForm.save`
method of this form will be called when the form
:func:`EditProfileForm.is_valid`. Defaults to :class:`EditProfileForm`
from userena.
:param template_name:
String of the template that is used to render this view. Defaults to
``userena/edit_profile_form.html``.
:param success_url:
Named URL which will be passed on to a django ``reverse`` function after
the form is successfully saved. Defaults to the ``userena_detail`` url.
:param extra_context:
Dictionary containing variables that are passed on to the
``template_name`` template. ``form`` key will always be the form used
to edit the profile, and the ``profile`` key is always the edited
profile.
**Context**
``form``
Form that is used to alter the profile.
``profile``
Instance of the ``Profile`` that is edited.
"""
user = get_object_or_404(get_user_model(),
username__iexact=username)
profile = user.get_profile()
user_initial = {'first_name': user.first_name,
'last_name': user.last_name}
form = edit_profile_form(instance=profile, initial=user_initial)
if request.method == 'POST':
form = edit_profile_form(request.POST, request.FILES, instance=profile,
initial=user_initial)
if form.is_valid():
profile = form.save()
if userena_settings.USERENA_USE_MESSAGES:
messages.success(request, _('Your profile has been updated.'),
fail_silently=True)
if success_url:
# Send a signal that the profile has changed
userena_signals.profile_change.send(sender=None,
user=user)
redirect_to = success_url
else: redirect_to = reverse('userena_profile_detail', kwargs={'username': username})
return redirect(redirect_to)
if not extra_context: extra_context = dict()
extra_context['form'] = form
extra_context['profile'] = profile
return ExtraContextTemplateView.as_view(template_name=template_name,
extra_context=extra_context)(request)
I am including the html to render the forms using {% include 'my-template.html' %}. What could be preventing me from updating the profile object? Thanks for any ideas!
Try adding
{{ form.errors }}
somewhere to your template to see if there are any non-field errors !
All,
I have a template page say x.html
i have 3 text fields name(varchar2) ,age(int),school(varchar2) in it.
If the users enters values in the form in x.html(say values name="a" ,age="2" ,school="a") and submit it.I need to return the same values back to x.html indicating an error.
My question is how to return the same values to x.html.
Thanks.....
from docs:
The standard pattern for processing a form in a view looks like this:
def contact(request):
if request.method == 'POST': # If the form has been submitted...
form = ContactForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
# Process the data in form.cleaned_data
# ...
return HttpResponseRedirect('/thanks/') # Redirect after POST
else:
form = ContactForm() # An unbound form
return render_to_response('contact.html', {
'form': form,
})
Django will write the submitted values back as long as you provide the form object to the rendered template. For example, in your view, something like:
# handle POST
form = MyForm(request.POST)
if form.is_valid():
# do something and redirect
else:
# render the template with the invalid form
return render_to_response('mytemplate.html', {'form': form})
and in your template, something like:
{{ form.myfield.label_tag }}
{% if form.myfield.errors %} indicate error message/icon here {% endif %}
{{ form.myfield }}
Note that {{ form.myfield }} will show an HTML widget for myfield with the previous submitted values based on the view code above. And it will be blank when you render it with a blank form in response to a GET (e.g. form = MyForm()).
If you are using django forms, it would do validation itself and then return the values you need. Here you can read about using forms and how they validate values. Basically, when you pass some values into the form and it's not valid, you just render the site again, but django will automagically fill fields. Don't bother writing your own forms, unless you really, really need them. And in your example you really don't ;-)
I'm not sure how you are processing your form information. However if you use the Form API built into Django, it takes care of much of this for you. For details take a look at the Django Docs for Forms http://docs.djangoproject.com/en/dev/topics/forms/#topics-forms-index
If you use the Form API and the submission is not valid, Django provides the template with a bound copy of the form with the user supplied data already in it. Again you will have to read the details of the API for how to implement it in your situation.