Custom Django Form Not Saving - python

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 !

Related

how can i get the "post id"(foreign key field connected with comment model) to the django comments form without post_detail page in django

I am creating a single page blog site how can i get the post id to the comments form , I created django forms with necessary field but the problem is ,I have to select the post id from a drop down menu manually while commenting, for that I passed post object as an input value of a form to views.py file but django needs instance to save in database what should I do now
note :I am not using post_detail
models.py
class comments(models.Model):
name=models.CharField(max_length=255)
content=models.TextField()
post=models.ForeignKey(blog,related_name="comments",on_delete=models.CASCADE)
#blog is the model to which comment is related
date=models.DateTimeField(auto_now_add=True)
forms.py
class commentform(ModelForm):
class Meta:
model=comments
fields=('name','content','post')
widgets={
'name' : forms.TextInput(attrs={'class':'form-control','placeholder':'type your name here'}),
'content' : forms.Textarea(attrs={'class':'form-control'}),
'post' : forms.Select(attrs={'class':'form-control'})
}
Html
<form method='POST' action="comment_action" class='form-group'>
{%csrf_token%}
{{form.name}}
{{form.content}}
<input type="text" id="objid" name="objid" value="{{objs.id}}" hidden>
<button class="btn btn-primary btn-sm shadow-none" type="submit">Post comment</button>
views.py
def comment_action(request):
name=request.POST.get('name')
content=request.POST.get('content')
objid=request.POST.get('objid')
to_db=comments.objects.create(name=name,content=content,post=objid)
print(name,content,objid)
return redirect('/homepage')
return render(request, 'index.html')
ERROR :
Exception Type: ValueError
Exception Value:
Cannot assign "'48'": "comments.post" must be a "blog" instance.
-->48 is my blog id
i know that database will only accept instance post field because that was a foreign key
my question is how to pass it ?
You assign it with post_id:
def comment_action(request):
name = request.POST.get('name')
content = request.POST.get('content')
objid = request.POST.get('objid')
to_db = comments.objects.create(name=name, content=content, post_id=objid)
print(name,content,objid)
return redirect('/homepage')
Note: It is better to use a Form [Django-doc]
than to perform manual validation and cleaning of the data. A Form will not
only simplify rendering a form in HTML, but it also makes it more convenient
to validate the input, and clean the data to a more convenient type.
Note: normally a Django model is given a singular name, so Comment instead of comments.

Django : Form Successful but image not uploaded

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!

Automatically login in Django 1.8

This question has been asked a lot on SO, but none of those solutions have worked for me. I'm wondering what I'm missing. I'm using the example from Effective Django. It had me create a "register" form, which redirects to '/' after success. The root page redirects to a login form if the user isn't logged in already. All I want is for the registration form to automatically log the user in upon registration.
I've created a RegisterView() in views.py, which just attempts to authenticate/login users in form_valid():
class RegisterView(CreateView):
template_name = 'register.html'
form_class = forms.UserCreateForm
success_url='/'
def form_valid(self, form):
user = form.save()
user = authenticate(username=self.request.POST['username'], password=self.request.POST['password1'])
login(self.request, user)
return super(RegisterView, self).form_valid(form)
This sort of works. I tried raising an exception if user.is_authenticated() == False, and no exception is raised. However, by the time the browser redirects to success_url, apparently the login information is lost and the #login_required decorator makes the user login before viewing /.
I also tried doing user.backend = 'django.contrib.auth.backends.ModelBackend' before the call to login(...); and I also set AUTHENTICATION_BACKENDS to the same.
Has something changed significantly in 1.8 to prevent this? Everything I've seen online has this as the solution, but it simply doesn't work for me.
Note, after registering, the user can login manually.
I had this problem when I was doing my own website in Django 1.8. It turns out that CreateView inherits from FormMixin, not FormView. Try inheriting from FormView, and that should get the desired results without compromising any other functionality.
https://docs.djangoproject.com/en/1.8/ref/class-based-views/generic-editing/#formview
I mostly prefer class based views to functions based at times, though both will be required somehow.
To answer your question, I'm also learning it, I had the same problem, and that's how it's to be from the Django documentation:
- In your settings.py, you should have something like this:
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
)
LOGIN_URL = 'django.contrib.auth.views.login'
LOGIN_REDIRECT_URL = 'view where to redirect user'
SITE_ID = 1
and in my registration template, my submit button will look something like:
<input class="btn btn-lg btn-primary btn-block" type="submit" value="Login">
<input type="hidden" name="next" value="{% if next %}{{ next }}{% else %}{% url 'template or view where to redirect to' %}{% endif %}">.
So the second tag redirect the user to whatever page you want him to go to after, registration or login. I used for the case you needed to comment on an article which requires you to login first, so once logged in, it's going to be logical to redirect the user to the previous page. So that's how I achieved it.
Hope it's gonna help
Based on the code you shared above, you are supposed to check if user = authenticate(username=self.request.POST['username'], assword=self.request.POST['password1'])
returns a value before invokinglogin_user(user)`
def form_valid(self, form):
user = form.save()
user = authenticate(username=self.request.POST['username'], password=self.request.POST['password1'])
if user is not None:
login(self.request, user)
# this is the only time the user would be logged in.
return super(RegisterView, self).form_valid(form)
check (https://docs.djangoproject.com/en/1.8/topics/auth/default/#django.contrib.auth.login) for more info.
`

Return Django form contents on error

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.

POSTing forms in Django's admin interface

I'm writing a Django admin action to mass e-mail contacts. The action is defined as follows:
def email_selected(self,request,queryset):
rep_list = []
for each in queryset:
reps = CorporatePerson.objects.filter(company_id = Company.objects.get(name=each.name))
contact_reps = reps.filter(is_contact=True)
for rep in contact_reps:
rep_list.append(rep)
return email_form(request,queryset,rep_list)
email_form exists as a view and fills a template with this code:
def email_form(request,queryset,rep_list):
if request.method == 'POST':
form = EmailForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
send_mail(
cd['subject'],
cd['message'],
cd.get('email','noreply#localboast'),['redacted#email.com'],
)
return HttpResponseRedirect('thanks')
else:
form = EmailForm()
return render_to_response('corpware/admin/email-form.html',{'form':form,})
and the template exists as follows:
<body>
<form action="/process_mail/" method="post">
<table>
{{ form.as_table }}
</table>
<input type = "submit" value = "Submit">
</form>
</body>
/process_mail/ is hardlinked to another view in urls.py - which is a problem. I'd really like it so that I don't have to use <form action="/process_mail/" method="post"> but unfortunately I can't seem to POST the user inputs to the view handler without the admin interface for the model being reloaded in it's place (When I hit the submit button with , the administration interface appears, which I don't want.)
Is there a way that I could make the form POST to itself (<form action="" method="post">) so that I can handle inputs received in email_form? Trying to handle inputs with extraneous URLs and unneeded functions bothers me, as I'm hardcoding URLs to work with the code.
You can use django's inbuilt url tag to avoid hardcoding links. see...
http://docs.djangoproject.com/en/dev/ref/templates/builtins/#url
Chances are you'd be better off setting up a mass mailer to be triggered off by a cron job rather than on the post.
Check out the answer I posted here
Django scheduled jobs
Also if you insist on triggering the email_send function on a view update perhaps look at
http://docs.djangoproject.com/en/dev/topics/signals/

Categories