I am looking for some assistance in two areas for django forms processing.
I have a class view that overrides post and checks the name of the form in request.POST to determine which form has been submitted. based on the form submitted, I perform the appropriate actions for that form and save to the model. That part works correctly. I am not using a model form, just a custom html form created in the template with input fields. See the below view and html for reference. Is this the correct way to handle this or is there a best practice I should be following that makes use of model forms? Code seems a bit heavy to me and non-standardized, like there should be a better way...
Being that I am not using model forms, the error processing has me a little confused. How do you handle error processing on a normal html form that does not make use of django model forms? See below in the view where notated # ERROR HANDLING FOR FORM NEEDED in code, specifically on the username field which is unique and validated on the model level.
views.py
class ProfileView(View):
def get(self, request, *args, **kwargs):
if request.method == "GET":
# load profile data...
def post(self, request, *args, **kwargs):
if request.method == "POST":
# check if profile_form submitted
if 'profile_form' in request.POST:
# get user form data
profile_data = request.POST.dict()
# get current user profile
user_profile = Profile.objects.get(my_user=request.user)
# check username entry against current
if user_profile.username == profile_data['username']:
user_profile.country = profile_data['country']
user_profile.display_location = profile_data['display_location']
user_profile.organization_name = profile_data['organization']
user_profile.save(update_fields=['country', 'display_location','organization_name'])
#send success message to page
messages.success(request, "Success: Profile was updated.")
else:
try:
user_profile.username = profile_data['username']
user_profile.country = profile_data['country']
user_profile.display_location = profile_data['display_location']
user_profile.organization_name = profile_data['organization']
user_profile.save(update_fields=['username', 'country', 'display_location','organization_name'])
#send success message to page
messages.success(request, "Success: Profile was updated.")
except:
# unique constraint error on username
# ERROR HANDLING FOR FORM NEEDED
# check if user_name_form submitted
if 'user_name_form' in request.POST:
# get user form data
user_data = request.POST.dict()
# get current user
user = MyUser.objects.get(email=request.user)
user.first_name = user_data['first_name']
user.last_name = user_data['last_name']
user.save(update_fields=['first_name', 'last_name'])
# send success message to page
messages.success(request, "Success: Name was updated.")
# Return Profile page view with updated data
return HttpResponseRedirect(reverse('profile'))
html
<!--form-->
<form id="profile" class="small" method="POST" action="{% url 'profile' %}">
{% csrf_token %}
<!--Username-->
<label for="username">Username <span style="font-style: italic;">(create a unique display name that will appear to other users on the site)</span></label>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="username">#</span>
</div>
<input type="text" class="form-control" placeholder="Username" aria-label="Username" aria-describedby="username" name="username" value="{% if profile and profile.username is not None %}{{ profile.username }}{% endif %}">
</div>
<hr>
<p>Tell us where you are from!</p>
<!--Country State/Province City Select-->
<div class="form-group">
<select name="country" class="form-control mb-3" id="country">
<option value="">Select Country...</option>
{% for country in countries %}
{% if profile.country == country.name %}
<option value="{{ country.name }}" id="{{ country.code }}" selected>{{ country.name }}</option>
{% else %}
<option value="{{ country.name }}" id="{{ country.code }}">{{ country.name }}</option>
{% endif %}
{% endfor %}
</select>
</div>
<hr>
<p>Enter your profile display location <i>(ie. City, State, Province, Region...)</i></p>
<input type="text" class="form-control" id="display_location" name="display_location" placeholder="Based in..." value="{% if profile and profile.display_location is not None %}{{ profile.display_location }}{% endif %}">
<hr>
<p>Do you belong to an organization?</p>
<input type="text" class="form-control" id="organization" name="organization" placeholder="Organization Name" value="{% if profile and profile.organization_name is not None %}{{ profile.organization_name }}{% endif %}">
<hr>
<button type="submit" class="btn btn-primary" name="profile_form" value="profile_form">Save</button>
</form>
This can be tricky to do, so at DjangoCon a few years ago, we built a Django app to help. Have a look:
https://github.com/kennethlove/django-shapeshifter
As a solution to this problem I was able to get to, see the post here for a way to do this without a 3rd party app.
Related
Django form is saved but "result" field is showing empty in database.
Even after populating the filed from admin panel, it is saved but it still shows empty.
Models.py
class Result(models.Model):
class Choises(models.TextChoices):
POSITIVE = "POSITIVE", "Positive"
NEGATIVE = "NEGATIVE", "Negative"
user = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=50, default=None)
result = models.CharField(max_length = 100, choices=Choises.choices, blank=False
)
resultDoc = models.ImageField(upload_to='testResults', height_field=None, width_field=None,)
def __str__(self):
return self.user.username
Forms.py
class resultForm(forms.ModelForm):
class Meta:
model = Result
fields = ['name', 'result', 'resultDoc']
views.py
def inputResult(request, pk):
user = User.objects.filter(id=pk).first()
profile = newProfile.objects.filter(user=user).first()
if profile == None:
profile = oldProfile.objects.filter(user=user).first()
rForm = resultForm(request.POST, request.FILES)
if request.method == 'POST':
rForm = resultForm(request.POST, request.FILES)
if rForm.is_valid():
order = rForm.save(commit=False)
order.user_id = pk
order.save()
return redirect('stored_records')
else:
rForm = resultForm()
context = {'user' : user, 'profile':profile, 'rForm': rForm}
return render(request, 'Testing booth End/input-result-customer-info.html', context)
input-result-customer-info.html
<form action="" method = "POST" enctype= "multipart/form-data">
{% csrf_token %}
<div class="mb-3">
<label for="name" class="form-label">Name</label>
<input type="text" class="form-control" id="name" name="name" placeholder="Uploaded By/Doctor Name">
</div>
<div class="mb-3">
<label for="result" class="form-label">Result</label>
<select class="form-select" id="result" name="result" class="form-control">
<option value="POSITIVE">Positive</option>
<option value="NEGATIVE">Negative</option>
</select>
</div>
<div class="mb-3">
<label>Upload Scan File</label>
<div class="upload d-flex justify-content-between">
<div class="file-placeholder">Upload Scan File</div>
<input type="file" class="form-control d-none" id="resultDoc" name="resultDoc" >
<label for="resultDoc" class="form-label cam-img"> <img src="{% static 'user/images/Camera.png' %}"> </label>
</div>
</div>
<button class="btn btn-primary w-50 ms-auto d-block h-100" type="submit">Upload</button>
</form>
enter image description here
I think that the reason this doesnt work is that you created a form (rForm) in the backend but then you don't use it in the frontend.
This is how you should render your form in the the frontend:
<form method="post">
{{ rForm.as_p }} # This is the easiest possible implementation
<button type="submit">Submit</button>
</form>
If you want to take control of how the form is rendered, then you have to make sure that the input fields are named in the way that your backend expects. You can do it entirely manually or semi-manually, but your field names have to be set correctly or nothing will work.
Example of typical approach, say in case you have several similar text inputs
{% for field in rForm %}
<label for="{{ field.auto_id }}">{{ field.name }}</label>
<input type="text" name="{{ field.html_name }}" id="{{ field.auto_id }}" />
{% endfor %}
Example of fully hands-on approach
<select class="form-select" id="{{ rForm.result.auto_id }}" name="{{ rForm.result.html_name }}" class="form-control">
<option value="POSITIVE">Positive</option>
<option value="NEGATIVE">Negative</option>
</select>
In order to make sure that the inputs are being parsed correctly, add a print statement in your view to print the POST request:
print("Post Request : ", request.POST)
From there you will be able to see if the result field is being picked up correctly or if it's being ignored. Usually when fields get ignored is because they are not named correctly or sometimes it's because they fail validation.
If the rest of the data is saved correctly and just result is being left out then it's almost for sure an issue with the field name because if the form failed validation it would have aborted the entire operation.
P.S. I just noticed that you select input has the class attribute declared twice
I have this app and its working but i'm confused whether to use form method or POST.get method. with form i'm getting so many challenges like rendering form on custom html
suppose i have this change password screen, for that i need to create form then use this on html template and with custom html it gets more complicated to use form fields.
forms.py:
class ChangePasswordForm(PasswordChangeForm):
old_password = forms.CharField(label="Old Password", strip=False, widget=forms.PasswordInput(
attrs={'class': 'formField password-genrInput'}))
new_password1 = forms.CharField(label="New Password", strip=False, widget=forms.PasswordInput(
attrs={'class': 'formField password-genrInput'}))
new_password2 = forms.CharField(label="Confirm Password", strip=False, widget=forms.PasswordInput(
attrs={'class': 'formField password-genrInput'}))
class Meta:
model = User
fields = ('old_password', 'new_password1', 'new_password2')
views.py:
# Password Change View
def changePassword(request):
if request.method == 'POST':
form = ChangePasswordForm(request.user, request.POST)
print(form)
if form.is_valid():
print("form valid")
user = form.save()
update_session_auth_hash(request, user)
messages.success(request, "Password Changed Successfully")
return redirect('changePassword')
else:
messages.error(request, "Something Went Wrong, Please Try Again ")
return redirect('changePassword')
else:
form = ChangePasswordForm(request.user)
return render(request, 'admin/user_auth/change_password.html', {
'form': form
})
html:
{% extends "admin/layouts/default.html" %}
{% load static %}
{% block content%}
<div class="row">
<div class="col">
<div class="titleBlock">
<h1><i class="fas fa-chevron-circle-left mr-3"></i>Back</h1>
</div>
<div class="card">
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li {% if message.tags %} class=" {{ message.tags }} " {% endif %}> {{ message }} </li>
{% endfor %}
</ul>
{% endif %}
<form method="post">
{% csrf_token %}
<div class="formBlock">
<div class="row password-genr mt-5">
{% for field in form %}
<div class="col-md-7">
<div class="formControl static ">
<label for="" class="formLabel">{{field.label}}</label>
{{field}}
</div>
</div>
{%endfor%}
<div class="col-md-7">
<div class="btnBlock mt-5">
<button type="submit" class="btn btn-md">Save</button>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
{%endblock content%}
but with simple method i would have checked first if new password and confirm password are matching then
old_password = request.POST.get('old_password')
new_password = request.POST.get('new_password')
check the old password are matching with db then save the new password on db.
so which method should i use and why?
TO do This you can do something like this.
from django.contrib.auth.hashers import check_password
current_password = request.user.password
old_password = request.POST.get('old_password')
matchcheck= check_password(old_password, current_password) #this returns True or False
if matchcheck:
#change your password
else:
#tell the user the password is wrong.
The method above is useful by example if a user wants to delete his account to do so you can use the idea to check whether he knows his password or not ,if he knows it then he can delete his account.
And if you do not want to implement it by yourself you can use the built-in in Django(i really recommend this method for changing password because it well done and less headache).
Am trying to customize my checkbox inputs to look like this [what i want to archive]
so i tried this...
profile.html
<ul class="wt-accountinfo">
{% for key, value in form.interests.field.choices %}
<li>
<div class="wt-on-off pull-right">
<input type="checkbox" id="{{ value }}" value="{{ key }}" name="interests">
<label for="{{ value }}"><i></i></label>
</div>
<span>{{ value | title }}</span>
</li>
{% endfor %}
</ul>
which renders the html fine but highlight the select fields from the database
but using {{ form.interest }} highlights the selected checked boxes from the database
here is the forms.py
class ProfileForm(forms.ModelForm):
interests = forms.ModelMultipleChoiceField(
queryset=JobsCategories.objects.all(), widget=forms.CheckboxSelectMultiple(),
required=False
)
class Meta:
model = Profile
fields = ['interests']
and here is the models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE,
interests = models.ManyToManyField(Categories, related_name='interests', null=True, blank=True)
def __str__(self):
return f'{self.user.first_name} {self.user.last_name}'
in the views.py
def dashboard_profile(request):
if request.method == 'POST':
form = ProfileForm(request.POST, request.FILES, instance=request.user.profile)
account_form = AccountForm(request.POST, instance=request.user)
if form.is_valid() and account_form.is_valid():
f_interests = form.save(commit=False)
for i in request.POST.getlist('interest'):
f_interests.interest.update(i)
f_interests.save()
form.save_m2m()
account_form.save()
return redirect('index')
else:
form = ProfileForm(instance=request.user.profile)
account_form = AccountForm(instance=request.user)
context = {
'form': form,
'account_form': account_form,
}
return render(request, 'dashboard_profile.html', context)
NOTE!!! if i select the options i want and click save, it saves the options i checked to the database
this is it
this is it in the admins section
admin section
admin section 2
and also when i use {{ form.interests }} in the the template it renders fine and highlights the checked option from the database but its not styled
[how it looks like when i use {{ form.interests }}]
i know am missing somtehing in the profile.html so please help me out Thanks.
You're missing logic within your input tag to apply the existing value of the field choice.
<ul class="wt-accountinfo">
{% for key, value in form.interests.field.choices %}
<li>
<div class="wt-on-off pull-right">
<input type="checkbox"
id="{{ value }}"
value="{{ key }}"
name="interests"
{% if value %}checked{% endif %}>
<label for="{{ value }}"><i></i></label>
</div>
<span>{{ value | title }}</span>
</li>
{% endfor %}
</ul>
I'm making an Inventory Management System, which now I'm trying to make my form input more efficient.
I have 2 tables of Arrival and Withdraw
In table Arrival there are prod_cd , prod_nm, ..., withdraw
In table Withdraw there are prod_cd, prod_nm, withdraw
I want to make my form only input the prod_cd and then the field of prod_nm and withdraw would automatically retrieved from the Withdraw table
I've try to make another page so there will be Inquiry first to retrieve the Withdraw.objects, and then Add the record but it throw an error
views.py
def add_cycle(request, model, cls, inquiry):
if request.method == "POST":
form = cls(request.POST)
if form.is_valid():
form.save()
return redirect(inquiry)
else:
form = cls()
return render(request, 'add_new.html', {'form': form})
def add_arrival(request):
return add_cycle(request, Arrival, ArrivalForm, inquiry_arrival)
def inquiry_cycle(request, pk, model, cls):
instance= Withdraw.objects.get(pk=pk)
form = cls(instance=instance)
if request.method == "POST":
form = cls(request.POST,instance=instance)
if form.is_valid():
form.save(commit=True)
return redirect ('index')
else:
form = ArrivalForm(instance=instance)
return render_to_response('add_newInquiry.html', {'form': form})
def inquiry_arrival (request, pk):
return inquiry_cycle(request, pk, Arrival, ArrivalForm)
urls.py
url(r'^add_arrival$', add_arrival, name='add_arrival'),
url(r'^inquiry_arrival$', inquiry_arrival, name='inquiry_arrival'),
forms.py
class ArrivalForm(forms.ModelForm):
class Meta:
model = Arrival
fields = ('prod_cd', 'prod_nm', 'quantity', 'issues', 'location', 'withdraw', 'expired_date', 'sup_sheet')
add_new.html
<form method="POST">
<br>
{% csrf_token %}
<h4>ADDING ITEMS</h4>
<div class="form-group row">
<label for="id_{{ form.prod_cd.name }}" class="col-2 col-form-label"> {{ form.prod_cd.label }} </label>
<div class="col-10">
{{ form.prod_cd }}
</div>
</div>
<button type="submit" class="btn btn-primary" name="button"> Inquiry</button>
</form>
add_newInquiry.html
<form method="POST">
<br>
{% csrf_token %}
<h4>ADDING ITEMS</h4>
{% for field in form %}
<div class="form-group row">
<label for="id_{{ field.name }}" class="col-2 col-form-label"> {{ field.label }} </label>
<div class="col-10">
{{ field }}
</div>
</div>
{% endfor %}
<button type="submit" class="btn btn-primary" name="button"> Add Record</button>
</form>
I expect my form would retrieve some of it fields value from database, but I still got an error
ValueError at /add_arrival
The view inventory.views.add_arrival didn't return an HttpResponse object. It returned None instead.
Let's trace the error together! So, The view inventory.views.add_arrival didn't return an HttpResponse object. It returned None instead. What this means is that when Django attempts to fetch the add_arrival view, no templates are returned.
Let's take a further look at add_arrival view. It calls the function add_cycle. Pay attention to the last parameter inquiry_arrival, which is a method.
Now, in the add_cycle function, if the form is valid, we return redirect(inquiry) where inquiry is the inquiry_arrival method. However, since inquiry is a method, it needs to be called for something to be returned! To call this method, you should have added brackets behind inquiry, like so: redirect(inquiry()). Refer to this link for further information. Good luck!
Below is my code for Form submission .when i submit the form form,is_valid always returning false not sure want went wrong with my code. I am just started learning Django any help is highly appreciated TIA
HTML
{%extends 'base.html'%}
{% block content %}
<div class="container">
<form method="post" class="form-signin" action="/loginvalidation/">{% csrf_token %}
<h2 class="form-signin-heading">Please sign in</h2>
<label for="inputEmail" class="sr-only">Email address</label>
<input type="email" id="inputEmail" class="form-control" placeholder="Email address" required autofocus>
<label for="inputPassword" class="sr-only">Password</label>
<input type="password" id="inputPassword" class="form-control" placeholder="Password" required>
<div class="checkbox">
<label>
<input type="checkbox" value="remember-me"> Remember me
</label>
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
</form>
</div>
{% endblock %}
Html file
view.py
def loginvalidation(request):
print request
form = LoginssForm(request.POST or None)
print form.is_valid()
if form.is_valid():
save_it=form.save(commit=False)
print save_it.email
save_it.save()
user = authenticate(username='john', password='secret')
if user is not None:
# the password verified for the user
if user.is_active:
print("User is valid, active and authenticated")
else:
print("The password is valid, but the account has been disabled!")
else:
# the authentication system was unable to verify the username and password
print("The username and password were incorrect.")
return render(request,"about-us.html",locals(), context_instance=RequestContext(request))]
View. py for my code
Model.py
class LogIn(models.Model):
email=models.EmailField(null=False,blank=False)
password=models.CharField(max_length=1201,null=True,blank=True)
timestamp=models.DateTimeField(auto_now_add=True,auto_now=False)
updated=models.DateTimeField(auto_now_add=False,auto_now=True)
Model of application
Model of applicationModel of application
form.py
class LogInForm(forms.ModelForm):
class Meta:
model=LogIn
fields = '__all__'
Above is my code for Form submission. When I submit the form, form.is_valid always returns False. I just started learning Django any help is highly appreciated.
It appears you're missing a "name" attribute on your fields in the HTML file, thus the value is never actually getting posted to Django. If just add name="email" and name="password", respectively, to the fields, then the values should get passed through and begin properly validating.
However, that being said, I agree with Alasdair's comment above. It would be far more secure and recommended to use Django's built in authentication system.