Django: How to access modelform field data in templates - django

I have a page which displays a form that a logged-in user can use to edit their profile.
The first time the user loads the corresponding view, with a GET request, the form should display the values of the users existing profile record.
Because I'd like to have granular control over the markup used for the form fields, I'd like to retrieve the field values only, and manually write the necessary input element markup inserting the retrieved field values as the input elements' 'value' attribute (rather than have django render the entire input elements).
So far I've been trying to use directives like {{ form.myfield.data }} in my template to access the field data, but this is returning "None", instead of the profile details as i expected.
If the user has just posted a valid form though, the form fields do contain the expected profile details.
I hope someone can help me understand what i'm doing wrong here:
Here's my view:
#login_required
def edit(request):
# get logged-in user's profile
obj=Profile.objects.get(user=request.user)
if request.method == 'POST': # If the form has been submitted...
form = ProfileForm(request.POST, request.FILES, instance=obj)
if form.is_valid(): # All validation rules pass
form.save()
request.flash['success'] = "Your profile has been updated." # Puts a string to the flash scope
else:
request.flash['error'] = 'Please correct the problems below and try again' # Puts a string to the flash scope
else:
# if no form was submitted
# derive the form data from the logged-in users existing profile
form = ProfileForm(instance=obj)
return render_to_response('app_profile/edit.html',
{
'form': form,
'user': request.user,
'ancestor_urls': ['app_profile.views.edit',],
},context_instance=RequestContext(request)
)
And here's an excerpt from the corresponding template. This input element deals with a field called 'display_name'.
<input type="text"
class="textInput large {% if form.display_name.errors %}error{% endif %}"
maxlength="50"
size="35"
value="{{ form.display_name.data }}"
id="id_display_name"
name="display_name">

The way to do what you want to do is to write custom form widgets, instead of doing that in the template.
You can either create an entirely custom widget, or you can just add/change the attributes on the form level when you init the ModelForm

I guess you can solve some of your problems without making a custom widget using the widgets attrs argument: http://docs.djangoproject.com/en/dev/ref/forms/widgets/#django.forms.Widget.attrs, also you have some styling options using the input's id!

Related

image not saving to db edit profile django

Hi i have a registration form which contains username and email fields.After the registration is done,the user has an option to edit his profile which contains username,email and two other fields dob and photo(profile picture)..after clicking on the submit button all the fields are stored to the db except photo field.I checked the db the 'photo' column is empty. When i click on 'edit profile' for the second time i am getting data for all fields except photo. Can someone tell me why the photo fields is not stored to the db?
Most likely you forgot to add enctype atrribute to <form> tag. It should be like this:
<form method="POST" enctype="multipart/form-data">
...
</form>
Another possible reason is initiating of form instance without request.FILES argument. Correct form creation is:
form = MyForm(request.POST, request.FILES)

Where is form data handled?? (Django)

I have read a lot of tuts and documentation on form creation and handling in Django but I still am confused on certain aspects of the implementation. Specifically, I cannot understand where I should handle the data sent by the form. Is it on the view that is using the form template or is it on another view?
For example, assume an index template with a single form:
*index.html*
{% load url from future %}
<form action="{% url 'Directories:_results'%}" method="post">
Name: <input type="text" name="txtField" />
<input type="submit" name="submit" />
</form>
So now for my view i have two versions:
#1 version (1 view): The same view displays and handles the form
def index(request):
if request.method == 'POST': # If the form has been submitted...
form = dbForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
field = form.cleaned_data['txtField']
#doSomething
else:
form = dbForm() #unbound form
return render(request, 'Directories/index.html', {'form': form})
#2 version (2 views): One view to display the form and one view to handle the form data
#the view that creates the form (unbound)
def index(request):
form = dbForm()
return render(request, 'Directories/index.html', {'form':form})
#the view that handles the data sent during form submission in the index template.
def results(request):
if request.method == 'POST':
form = dbForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
field = form.cleaned_data['txtField']
#doSomething
else:
form = dbForm() #unbound form
return render(request, 'Directories/index.html', {'form': form})
and here is my urls.py:
from django.conf.urls import patterns, url
from Directories import views
urlpatterns = patterns('',
url(r'^$', views.index, name='_index'),
url(r'^results$', views.results, name='_results'),)
As you can see data handling is performed differently in each version and as a result I want to know if any of these is wrong and if both are correct then which one is considered the best practice.
Generally a form will post to the same view it is being displayed on.
You can simplify the view logic like so:
def index(request):
form = dbForm(data=request.POST or None)
if form.is_valid(): # All validation rules pass
field = form.cleaned_data['txtField']
#doSomething
return redirect(success_url)
return render(request, 'Directories/index.html', {'form': form})
Note that it is usually good if you redirect after a successful form post, even if you redirect back to the same view. This prevents the user from being prompted to 'resend form data' if they refresh the page.
You should look at the docs for rendering a form in the template:
https://docs.djangoproject.com/en/dev/topics/forms/#looping-over-the-form-s-fields
If you don't render the field errors, for example, the user will never know what the problem was.
An example of a form that would post to a different view is if say your base template has a 'search' form which appears on every page. When you post this form you don't want to come back to the current view, you want to go to the 'search results' view.
Generally, one view corresponds to one url. Also, same url should show the form and accept the submitted form. With this logic, your first approach is better. One view shows and accepts the form.
However, there are cases where view to show form is different than the one accepts it. For example, a page that has multiple forms. Each form can be submitted to different view. But a different view can be implemented to handle that url and show such forms.
There's nothing wrong with either, it depends on what you want to do. By default forms send the data to the same request but you can send the data to a different view if that's more convenient
For most cases it's usually simpler to use the same view. Using two views is good if you're using an external tool\app\whatever or if you want tighten your security (having the second view only accept requests with post data for example etc.), but will require extra steps (error handling, succesful redirect)
The first thing to understand is that the view that processes the form is usually also the one that shows the form in the first place -- because it has to show the form again in case of errors.
In your template, you build the form HTML entirely by hand. That's unusual, because in case of errors (usually a required field that wasn't filled in) you want to render the form again, with all the values already entered present, and with a nice error message. Django's form rendering ( {{ form.as_p }} and the like) do that for you, you don't get it if you write the HTML by hand like this. In fact your view misses an else: clause on the is_valid(), leading it to
So usually the view does both, except for the second thing to understand: after a successful POST, you always redirect to a succes page, or possibly to the same page (which will show an empty form again). Mostly so the user can't accidentally re-submit the form with the refresh button then.
So your 1st is typical, except that you also need to finish with returning a ResponseRedirect in the is_valid() case, and should render more of the form in your template. No need for a second view.

Correlate HTML element name with Django form field name

How can I correlate HTML element (input) name and "Django" form field name?
For example, I have HTML file:
...
<input name='some_name'>
...
And I have the Django form with "name" field:
class SomeForm(ModelForm):
name = forms.CharField()
When I create a form, pass data to it and invoke "is_valid":
form = SomeForm(request.data)
form.is_valid()
I have an error for "name" field: "This field is required". So, what I can I do if changing input name in HTML is undesirable?
As you're not rendering your form in template, then you don't even need to define it.
It's not valid in your case simply because it has no data bound to it.
You can always access your POST data in a view like this - request.POST['name']
Docs: https://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpRequest.POST
They are named like your model attributes so it would be 'name' in your case.
And check if passing request.data as the 'data' argument for SomeForm is the proper way for you. I'd rather use request.POST.
Another way to do it:
You can pass your SomeForm instance to view context and render a ready to go form in your template:
def get_context_data(self, **kwargs):
# code
context['form'] = SomeForm() # with data or not
return context
and then in your template:
{{ form }}
or iterate through it:
{% for field in form %}
{{ field }}
{% endfor %}
that's always a way to do it and discover how django is naming your input's.

How to pass a request to a different Django view? (Show summary before submitting)

I am trying to show the user a summary of a form before the form is submitted and saved to the server.
I have a form on index.html and within that form, I have this input button:
<input type="submit" value="Show summary" name="summary"/>
On the summary.html page, I have another input button within a dummy form. I use this input button to get the form data saved.
<input type="submit" value="Save to DB" name="save_db" />
Here are code snippets of my the methods in my views:
def index(request):
form = JobForm(request.POST or None)
if request.method == 'POST':
if form.is_valid():
return summary(request)
return render_to_response('index.html', {'form': form}, context_instance=RequestContext(request))
def summary(request):
if request.method == 'POST':
save_to_db(request) # The problem here is that this is a new request. I lost the previous request with all the data
return render_to_response('thanks.html', context_instance=RequestContext(request))
xml = getxml(request) # form data is serialized
return render_to_response('summary.html', {'xml': xml}, context_instance=RequestContext(request))
From the above, I am able to get a summary of the form data. However, as the inline comment suggests, when I click the "Save to DB" submit button, the previous request with all the form data is lost.
I have looked into Sessions and I could not find a proper of doing the above. I also tried to pass the request as a parameter to the the summary page. However, I think this is not the right way of doing it.
I would appreciate your input!
Thanks.
Have you tried Django Form Preview? Seems that is exactly you are looking for:
Django comes with an optional “form preview” application that helps
automate the following workflow: “Display an HTML form, force a
preview, then do something with the submission.” To force a preview of
a form submission, all you have to do is write a short Python class.
Cheers!

Don't include blank fields in GET request emitted by Django form

On my Django-powered site, I have a search page with several optional fields. The search page is a Django form, and my view function is the typical:
def search(request):
form = SearchForm(request.GET or None)
if form.is_valid():
return form.display_results(request)
return render(request, 'search.html', {'form': form})
Form.display_results() uses the fields that are provided to query the DB and render a response. My search.html includes:
<form action="/search/" method="get">{% csrf_token %}
<!-- Render the form fields -->
<input type="submit" value="Search" />
<input type="reset" value="Reset form" />
</form>
Since most searches will have several blank fields, I'd like not to include them in the GET request emitted by the submit button on search.html. Current searches look something like:
http://mysite/search/?csrfmiddlewaretoken=blah&optional_field1=&optional_field2=&optional_field3=oohIWantThisOne
And I'd like them to look like:
http://mysite/search/?csrfmiddlewaretoken=blah&optional_field3=oohIWantThisOne
Of course, I have a several more fields. This would be nice to have because it would make search URLs more easily human-parsable and sharable.
You could use jQuery with an button trigger. Give the form and submit button ids.
$("#button_id").click(function(){
$("input").each(function(){
if($(this).val() == '') {
$(this).remove();
}
});
$("#form_id").submit();
});
That (or something similar) should remove all the empty fields before the submit.
You could also POST the form. Then build the search url and redirect with empty values removed.
See Hide empty fields from GET form by Bill Erickson:
jQuery(document).ready(function($){
// Remove empty fields from GET forms
// Author: Bill Erickson
// URL: http://www.billerickson.net/code/hide-empty-fields-get-form/
// Change 'form' to class or ID of your specific form
$("form").submit(function() {
$(this).find(":input").filter(function(){ return !this.value; }).attr("disabled", "disabled");
return true; // ensure form still submits
});
// Un-disable form fields when page loads, in case they click back after submission
$("form").find(":input").prop("disabled", false);
}
disclaimer: This is a very old question, and the only one I could find that matches the problem I ran into. It's entirely possible that my solution didn't exist at the time, and an even better way has since been added.
I'm using Django 3.2. I didn't want to use js/jQuery, nor did I want to use a POST form, so here's what I came up with. In a nutshell, it just checks the GET data to see if there are any default values present, and simply redirects to a URL that doesn't have them.
In your view:
from django.shortcuts import redirect
def myView(request):
if not is_clean_form(request.GET):
return redirect(whatever_url_path + clean_url_parameters(request.GET))
else:
# whatever your view does normally
Helper functions (consider making these static methods of your Form class, to keep all that type of stuff together):
from urllib.parse import urlencode
# fields and their default value (eg. empty string)
default_form_values = [
("some_field_name", ""),
# ...
]
def is_clean_form(form_dict):
for field, default_value in default_form_values:
if field in form_dict and form_dict[field] == default_value:
return False
return True
def clean_url_parameters(form_dict):
return "/?" + urlencode([
(field, form_dict[field]) for (field, default_value) in default_form_values
if field in form_dict and form_dict[field] != default_value
])