Force a form field to be populated in Django - django

I'm using Django 1.4 with Python 2.7 and Ubunutu 12.04.
I have a form that will update a user's profile. The last item in the form is the password. I pre-populate the form with the existing user's data. The password field does not get pre-populated - and that's fine.
The problem is that when I "save" the data it overwrites the password to be a null or empty field (I can't tell which). Bad.
What can I do to prevent this?
I've tried to make it a required field (forms.py):
password = forms.CharField(widget = forms.PasswordInput(), required = True)
Didn't work.
I've tried to check that the password is not None before updating it (views.py):
if (request.POST.get('password') is not None):
user.set_password(request.POST.get('password'))
Didn't work.
Does an empty form value come back as None? If not, what does it come back as and how can I check if it's empty?
EDIT 1:
I updated my one of my views to check for validation - maybe I did this wrong?
#login_required
def profile(request):
"""
.. function:: profile()
Provide the profile page, where it can be updated
:param request: Django Request object
"""
if request.user.is_authenticated():
user = User.objects.get(username = request.user.username)
user_dict = createUserProfileDict(user)
form = ProfileForm(initial = user_dict);
data = { 'user' : request.user }
data.update({ 'form' : form })
data.update(csrf(request))
if form.is_valid():
return render_to_response("profile.html", data)
Now I receive the following error:
The view rsb.views.profile didn't return an HttpResponse object.
So, it appears my form is not valid? How can I find out why?
Here is the update_profile view:
#login_required
def update_profile(request):
"""
.. function:: profile()
provide the profile page
:param request: Django Request object
"""
if request.user.is_authenticated():
user = User.objects.get(username = request.user)
user.first_name = request.POST.get('first_name')
user.last_name = request.POST.get('last_name')
user.email = request.POST.get('email')
if (request.POST.get('password') is not None):
user.set_password(request.POST.get('password'))
user.save()
# Update the additional user information tied to the user
user_info = UserProfile.objects.get(user_id = user.id)
user_info.company_name = request.POST.get('company_name')
user_info.client_type = request.POST.get('client_type')
user_info.address1 = request.POST.get('address1')
user_info.address2 = request.POST.get('address2')
user_info.city = request.POST.get('city')
user_info.state = request.POST.get('state')
user_info.country = request.POST.get('country')
user_info.zip_code = request.POST.get('zip_code')
user_info.phone_number = request.POST.get('phone_number')
user_info.save()
return profile(request)

First of all, remember to control if your form "is_valid()"
To theck if your form has been submitted with empty values or not, use
MyForm.has_changed()
too bad this is not a documented functionality :(
If you want a default password, i suggest you check if the field is valid then use something like
''.join([choice(string.letters + string.digits) for i in range(7)])
to generate a new password for the user (range(7) is the length you want). Then use an opt-in method (see: send a user an email with his temporary password)
edit based on new context:
from the django docs:
If a Field has required=False and you pass clean() an empty value,
then clean() will return a normalized empty value
rather than raising ValidationError.
For CharField, this will be a Unicode empty string.
For other Field classes, it might be None. (This varies from field to field.)
That's it, your password field should have required=False, so you can treat that as an empty string
Then in your view you could do:
if input_password != '' and input_password != saved_password:
saved_password = input_password
It's just pseudocode, but it should give you a clear idea

Related

How to update user profile in django properly

i created a form to update a django profile, i use the default user model, when i submit the form and logout and i tried to login again, the new password is not working, but the old one is.
this is my update view :
def edit_profil_to_base(request):
if not request.user.is_authenticated:
return redirect('authentification')
else:
nom_profil_new = request.POST.get('nom_profil')
nom_profil_old = request.user.username
old_mdp = request.POST.get('old_mdp') # type: object
new_mdp = request.POST.get('new_mdp')
final_mdp = request.POST.get('final_mdp')
mdp = request.user.set_password(new_mdp)
if request.user.check_password(old_mdp) and new_mdp == final_mdp:
User.objects.filter(username=nom_profil_old).update(username=nom_profil_new, password=mdp)
logout(request)
return redirect('authentification')
the new_mdp and final_mdp are the new password and the confirmation of the password
You need to use set_password. You can't do this via update, but you don't need to: you already have the actual object, request.user.
user = request.user
if user.check_password(old_mdp) and new_mdp == final_mdp:
user.username = nom_profil_new
user.set_password(mdp)
user.save()
However, you really should be using a ModelForm for all of this.

Django initial value for MultiChoice Field ignored for ModelForm

this is my first post here and I am very new to Django but I just can't seem to find a solution for this problem... I've searched stackoverflow and google but nothing seems to work for me...
I have a wine-app and want to be able to add and remove wines from the user's stock. In the list of wines the user can choose a wine to add and the ID of this wine is passed in the POST data. Since the data is getting lost after the first time the view is rendered I saved the ID in a cookie, which is working, but the problem is when I work with ModelForm de user has to select the foreign key for the user and for the wine, which is bad, so I tried to make it hidden and set the Fk_user and Fk_wine after the user choose the number of bottles to be added but before validation. Here's the problem after google everyone suggested I should use the "initial" and pass that to the form, but this is clearly not working because if I make the fields visible in the form I can see that it is not preselected...
viewy.py:
def addStockView(request):
wineId = request.POST.get('addStock')
if 'addStock' in request.POST:
wine = get_object_or_404(Wine, idwine=int(wineId))
userId = request.user.id
user = get_object_or_404(AuthUser, id=userId)
if request.method == 'POST':
#wineIdNew = request.COOKIES.get('wineIdToAdd')
#wineNew = get_object_or_404(Wine, idwine=wineIdNew)
form = StockForm(request.POST, initial={'fk_wine': wineNew.idwine, 'fk_auth_user': user.id})
if form.is_valid():
form.save()
return redirect('home')
else:
form = StockForm(initial={'fk_wine': wine.id,
'fk_auth_user': user.id})
response = render(request, 'addToStock.html', {'form': form})
response.set_cookie('wineIdToAdd', wineId)
return response
forms.py:
class StockForm(forms.ModelForm):
#fk_wine = ModelChoiceField(queryset=Wine.objects.all(),
# widget=HiddenInput())
#fk_auth_user = ModelChoiceField(queryset=AuthUser.objects.all(),
# widget=HiddenInput())
class Meta:
model = UserWineStock
fields = ['fk_auth_user', 'fk_wine', 'number']
can anyone help me with this..?
Yes, initial data is ignored when a form is bound to submitted data.
Instead of using initial here, you should exclude those two fields from the form and set them on the created object:
form = StockForm(request.POST)
if form.is_valid():
item = form.save(commit=False)
item.fk_wine = wine
item.fk_auth_user = request.user
item.save()
return redirect('home')
(Also, please don't call your fields things like fk_auth_user. Just call it user.)

How to save username which submits the form?

I'm new to django. I'm trying to create a sports betting game as my first django app.
I have form, using which I'm able to save home goals and away goals for particular game to database, but I can't find a way to insert a username there. Hope you can help!
Here is my view:
#login_required
def group_games(request, groupname):
games = Match.objects.filter(groupname=groupname)
template = loader.get_template('C:\djangoenvs\\typer\\typer\\templates\group_games.html')
username = User.get_username()
for game in games:
game_id = get_object_or_404(Match, pk=game)
form = BetForm(request.POST or None)
if form.is_valid():
print ('valid form')
form.save()
else:
print ('invalid form')
print (BetForm.errors)
context = {
'games': games,
'groupname': groupname,
'form': form,
}
User.get_username() raises the following error:
get_username() missing 1 required positional argument: 'self'
I tried to change it to User.get_username(self) but then:
name 'self' is not defined
Thanks for every answer!
User.get_username()
User represents the complete table, not the record. This is why you get an error.
So remove:
username = User.get_username()
A user might be able to change their username in your application, you can save a foreign key to the user instead. When you save the form do this:
if form.is_valid():
print ('valid form')
bet = form.save(commit=False) # the bet isn't saved just yet
bet.user = request.user # you add the user here
print bet.user.username
bet.save() # finally save the bet in the database
In your Bet model, you need to add a field to record the user. For example:
class Bet(models.Model):
...
user = models.ForeignKey(to=User, related_name="bets", blank=True, null=True)
...

django session key error for my simple captcha form

I just write a simple captcha for my login form.
I just add a simple session data.request.session['captcha'].
This is the login views function:
login (request):
if request.method =='GET':
form = LoginForm(auto_id=True)
a = random.randrange(1,10,1)
b = random.randrange(10,20.1)
request.session['captcha1']=a
request.session['captcha2']=b
return render_to_response('login.html',locals(),context_instance=RequestContext(request))
if request.method =='POST':
form = LoginForm(data=request.POST)
if form.is_valid():
captcha= request.POST.get('captcha','')
result = request.session.get('captcha1') + request.session.get('captcha2')
if captcha==result:
data = form.clean()
user=authenticate(username= data['username'],password = data['password'])
if user is not None:
auth_login(request,user)
return HttpResponseRedirect('/')
else:
form = LoginForm(auto_id=True)
return render_to_response('login.html',locals(),context_instance=RequestContext(request))
This is the login form
class LoginForm (forms.Form):
username = forms.CharField(
label='username')
password =forms.CharField(
label='password',widget = forms.PasswordInput())
captcha = forms.CharField(label='spam chercker')
I get keyerror for captcha1, captcha2, and when I add print request.session['captcha1'], it shows None. That means, when POST, I do not get the django session data, there is no data captcha1 and captcha2
How can I store the data in django session, and pass it to the POST method, and in other views function?
thanks
Instead of taking this approach, you might also want to look at existing Django captcha packages:
https://www.djangopackages.com/grids/g/captcha/
If you're looking for something simple, Django-Simple-Captcha is a great option.

Django submit optional forms

I need to create registration form for an event. Each person that register can bring guests. I want to register everything in one page. To do that I use a view with 1 RegistrationForm and X GuestForms. In my models, I have a Registration and Guest class I used to create the two forms with ModelForm.
The problem is that a GuestForm is not required to be filled (you don't have to bring guests).
def register_form(request):
error = False
if request.method == 'POST':
register = RegistrationForm(request.POST, instance=Registration() )
guests = [GuestForm(request.POST, prefix=str(x), instance=Guest()) for x in range(MAXGUESTS)]
if register.is_valid():
print("register is valid")
for guest in guests:
if guest.is_valid():
print("guest is valid")
else:
print("guest is not valid") # always when empty form
error = True
else:
print("register is not valid")
error = True
if not error:
... # save the form in the database
register = RegistrationForm(instance=Registration())
guests = [GuestForm(prefix=str(x), instance=Guest()) for x in range(MAXGUESTS)]
return render_to_response('register.html',{
'form': register,
'max_guests': MAXGUESTS,
'guests': guests,
'error': error,
})
So I need to set a form as optional and be able to differentiate when the whole form is empty and when there is an error. Any idea how ?
Thank you
Solution
def register_form(request):
GuestFormSet = modelformset_factory(Guest, exclude=('register',))
error = False
if request.method == 'POST':
register = RegistrationForm(request.POST, instance=Registration() )
guests = GuestFormSet(request.POST)
if register.is_valid():
print("register is valid")
for guest in guests:
if guest.is_valid():
print("guest is valid") # even if some forms are empty
else:
print("guest is not valid")
error = True
else:
print("register is not valid")
error = True
if not error:
...
# save the form in the database
return something
else:
register = RegistrationForm(instance=Registration())
guests = GuestFormSet(queryset=Guest.objects.none())
return render_to_response('register.html',{
'form': register,
'max_guests': MAXGUESTS,
'guests': guests,
'error': error,
})
You can use a model formset for your guest forms. It can distinguish between empty and invalid forms.
https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#model-formsets
I guess you will need some way to determine if a submitted guest form was actually filled in. When an empty form was submitted, ignore it:
forms_to_save =[]
for form in guest_forms:
if guest_form.is_valid()
forms_to_save.append( form )
else:
if form.contains_data(): # you'll have to implement this
error = True
if not error:
for form in forms_to_save():
form.save()
I have a similar problem in a wedding RSVP application that I'm building. In my case, each Guest has an 'attending' checkbox, and if it is not checked (i.e. the guest isn't attending) then I don't want any errors to be reported to the user.
My Guest model (slimmed down for brevity):
class Guest(models.Model):
email = models.EmailField(max_length=50, unique=True)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
attending = models.BooleanField(default=False)
I have a ModelForm class called RsvpForm that creates a form based on the Guest model. It looks like this:
class RsvpForm(ModelForm):
class Meta:
model = Guest
fields = ('attending', 'email', 'first_name', 'last_name')
def clean(self):
cleaned_data = self.cleaned_data
attending = cleaned_data.get('attending')
if not attending:
#clear the error collection
self._errors['email'] = {}
return cleaned_data
The solution to this problem lies in the clean() method that I've overriden in my RsvpForm class. In it, I check whether or not the guest is attending. If they aren't, then I clear the error messages for each of the other fields.
Originally, I had cleared the errors for the entire form like this:
if not attending:
#clear the error collection
self._errors['email'] = ''
self._errors['first_name'] = ''
self._errors['last_name'] = ''
But for some reason, modifying the values of any of these keys caused the form to fail validation, which in turn prevented Guest data from being saved if they had indicated that they were not attending. A small bug that most would never find, but annoying nonetheless.
At some point along the line, I had also tried to clear the errors collection by calling .clear() on the self._errors dictionary:
if not attending:
#clear the error collection
self._errors.clear()
But for some reason, the errors were still shown, even though I could verify that the dictionary was empty.
The end result is that form validation errors are only shown to my user if the 'attending' checkbox is selected, which is ideal because Guests might want to update their own contact information prior to deciding on who they will bring as a plus one.
There is a simpler solution than Alasdair's: using the empty_permitted keyword argument.
>>> f = MyForm(data={}, empty_permitted=True)
>>> f.is_valid()
True