How to transfer some variable to django form? - django

I want to make a custom form field validation to check if entered string is an email of user variable. Smth like this:
class FullEmailOrPhoneForm(forms.Form):
entered_string = forms.CharField()
class Meta:
model = User
fields = ('entered_string',)
def clean_entered_string(self):
email = self.cleaned_data['entered_string']
if email == user.email: # I need user variable for this comprasion
ans = email
else:
raise ValidationError('Incorrect email')
return ans
My view:
def reset_password_with_username(request, user):
if request.method == 'POST':
form = FullEmailOrPhoneForm(request.POST)
if form.is_valid():
pass
else:
form = FullEmailOrPhoneForm()
return render(request, 'registration/password_reset_with_username.html')
So how can I transfer user variable from view to form validation function?

You can override the __init__() method of your form so it can receive an extra argument, the user:
# inside FullEmailOrPhoneForm
def __init__(self, user, *args, **kwargs):
self.user = user # now you can use self.user anywhere in your form
super().__init__(*args, **kwargs)
def clean_entered_string(self):
...
if self.user and email == self.user.email:
...
# inside your view you have to specify `data=` since the first init arg is now the user.
form = FullEmailOrPhoneForm(user=request.user, data=request.POST)
# or with no data
form = FullEmailOrPhoneForm(user=request.user)
Note that you created a Form, not a ModelForm, so your Meta class is completely useless. If in fact, you wanted to have a ModelForm that models the user being edited (and the user you want to pass to the form is the same user as the one being edited), you should do this using the instance of the form:
class FullEmailOrPhoneForm(forms.ModelForm): # <-- note the ModelForm here
...
class Meta:
model = User
fields = ...
def clean_entered_string(self):
...
if self.instance and email == self.instance.email:
...
# then in your view:
form = FullEmailOrPhoneForm(request.POST, instance=user)

Related

How to access form object before and after saving in django-bootstrap-modal-forms

I have following code in my view of adding a new Item. Some fields are filled via user some fields are filled in the background. If form is valid then user is redirected to a url with a parameter (slug) from added object. How can I convert this code to django-bootstrap-modal-forms way?
def category_view(request, slug, *args, **kwargs):
...
if request.POST:
form = CreateItemForm(request.POST)
if form.is_valid():
if not request.user.is_authenticated:
raise PermissionDenied()
obj = form.save(commit=False)
obj.created_country = Constants.country_code
obj.created_by = request.user
obj.save()
return redirect('category:item_detail', slug=obj.slug)
I used django-bootstrap-modal-forms in the below way. but country and user fields are not null and must be filled. These fields are not part of the form.
class add_person(BSModalCreateView):
template_name = 'add_item.html'
form_class = CreateItemForm
success_message = 'Success: Item was created.'
success_url = reverse_lazy('category:item_detail') # slug needed
You are asking, how to modify the form and the only code you do not provide is the form. But try something like this:
forms.py
class BaseForm(forms.BaseForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for field in self.fields.values():
if isinstance(field.widget, widgets.RadioSelect):
continue
elif isinstance(field.widget, widgets.Select):
field.widget.attrs.update({'class': 'form-select'})
continue
field.widget.attrs.update({'class': 'form-control'})
class CreateItemForm(BaseForm):
# your code
This itereates over your FormFields and adds the bootstrap class form-select, or much more important form-control to the widget of your field.

Setting user kwargs as field vales in Django Form with Class-based View

I have a Django application (1.11) to track referrals (referred by a user). I want to pass the id of the authenticated user to the ModelForm 'referrer' field (and since it's from the current logged in user the field shouldn't be editable).
class Referral(models.Model):
name = models.CharField(max_length=100)
referrer = models.ForeignKey('users.User', on_delete=models.SET_NULL, related_name='referrals', null=True, blank=True)
View:
class ReferralFormView(FormView):
form_class = ReferralForm
template_name = "refer.html"
success_url = reverse_lazy('thanks')
def get(self, request):
if request.user.is_authenticated():
return super(ReferralFormView, self).get(request)
else:
return redirect('login')
def get_form_kwargs(self):
user = self.request.user
form_kwargs = super(ReferralFormView, self).get_form_kwargs()
form_kwargs['referrer'] = user.id
return form_kwargs
def form_valid(self,form):
...
form.save()
return super(ReferralFormView, self).form_valid(form)
I override get_form_kwargs in the view, then modify form init
class ReferralForm(forms.ModelForm):
class Meta:
model = Referral
def __init__(self, *args, **kwargs):
referrer = kwargs.pop('referrer', None)
super(ReferralForm, self).__init__(*args, **kwargs)
self.fields['referrer'].disabled = True
self.fields['referrer'].queryset = User.objects.filter(id=referrer)
However all I see is a blank referrer field, what am I missing to make the user the value of that field (which can't be edited)? I also tried self.fields['referrer'].initial = User.objects.filter(id=referrer). I don't want the user to have to select their own username from a queryset of one.
I can print a <QuerySet [<User: username>]> for user = User.objects.filter(id=referrer), so why isn't it setting that user as the field value?
Update: I can assign the user value with
self.fields['referrer'].initial = User.objects.filter(id=referrer).first()
self.fields['referrer'].disabled = True
However, on form submit Referral obj is not saving with the referrer field value (that value's still blank)
thanks
what I needed to do was select the user obj in the queryset:
self.fields['referrer'].initial = User.objects.filter(id=referrer).first()
but using self.fields['referrer'].disabled = True disabled the field so I was still getting a blank value on submit (disabled doesn't do what the docs say it does). Using self.fields['referrer'].initial = User.objects.filter(id=referrer).first() with that field set as readonly allows the form to submit with the initial value

Troubles making a user update view

I have a custom user model, subclass of AbstractBaseUser.
I'm currently having troubles making an update view, so user could change his profile. Changing user through admin interface works fine.
This is a form that I use to change user objects in both admin and app`s interface.
class UserChangeForm(forms.ModelForm):
password = ReadOnlyPasswordHashField(
label=_("Password"),
help_text=_(
"Raw passwords are not stored, so there is no way to see this "
"user's password, but you can change the password using "
"this form."
),
)
class Meta:
model = User
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
password = self.fields.get('password')
if password:
password.help_text = password.help_text.format('../password/')
user_permissions = self.fields.get('user_permissions')
if user_permissions:
user_permissions.queryset = user_permissions.queryset.select_related('content_type')
def clean_password(self):
return self.initial["password"]
I'm using fields = '__all__' to be able to change all the fields through admin interface. But in app's intreface I want user to change only some fields.
This in my view:
def update_user(request):
form = UserChangeForm(request.POST or None, instance=request.user, fields=('email', 'first_name'))
if request.method == 'POST':
if form.is_valid():
form.save()
return redirect('home')
return render(request, 'update_user.html', {'form': form})
return render(request, 'update_user.html', {'form': form})
If I pass fields parameter like that UserChangeForm(request.POST or None, request.user, fields=('email', 'first_name')) I get __init__() got an unexpected keyword argument 'fields' error.
If I don't pass it I get exacty same form with all the fileds as in the admin inface.
How can I get this form show only fields I want?
One solution would be to create a subclass of the UserChangeForm so that you can choose fields you want in the Meta class:
class MyUserChangeForm(UserChangeForm):
class Meta(UserChangeForm.Meta):
model = User
fields = ['email', 'first_name]
And then in your view you use the new form you made:
def update_user(request):
form = MyUserChangeForm(request.POST or None, instance=request.user)
# and so on ...

Remove option from ModelChoiceField

I just got my hands on an user account create view that looks like this:
#login_required
def user_create(request):
template_name = 'user/User_Create.html'
if request.method == 'POST':
#this part is not important
pass
else:
form = UserCreateForm()
user_error = ''
context = {'form': form, 'user_error': user_error}
return render(request, template_name, context)
with the UserCreateForm written like this:
class UserCreateForm(forms.ModelForm):
def save(self, commit=True):
user = super(UserCreateForm,self).save(commit=False)
username = self.cleaned_data['username']
username = username.replace(".", "")
username = username.replace("-", "")
user.username = username
if commit:
user.save()
return user
class Meta:
model = User
fields = ['username', 'name', 'profile', 'redefine_password', 'name_created']
widgets = {
'username': forms.TextInput(),
'name': forms.TextInput(),
'profile': forms.Select(),
'redefine_password': forms.CheckboxInput(),
'name_created': forms.TextInput(),
}
My problem is that we have different types of users(Admin, Supervisor, Support, Normal) and currently, Supervisors are able to create Admin accounts...
My initial approach was to pass the user from the view to the form, like this:
form = UserCreateForm(user=request.user)
and in the form, I'm trying to delete the option if the user is not an Admin, like this:
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None)
super(UserCreateForm, self).__init__(*args, **kwargs)
if not user.is_superuser:
del self.fields['profile'][1, 'Administrador']
but that failed miserably, I got a TypeError: 'ModelChoiceField' object does not support item deletion.
I tried assigning it to None but that didn't work as well since it doesn't support item assignment neither.
Lastly, I tried assisgning it to a forms.ModelChoiceField() using the queryset attribute but I couldn't make it work.
Could someone shed a light?
Edit:
What I am trying to do is to remove the option to create an admin account in case the current logged user is not an admin, the option is defined in the profile choices.

required authentication in forms

I have an issue with the authentication in some templates.
In template where I pass form based in models I can only access if I am logged,
but in template with forms non-based in models I can access without being logged
Form non-model based:
class ProvSearchForm(forms.Form):
proveedor = forms.ModelChoiceField(queryset=Proveedor.objects.all(),required=True)
mes = forms.ChoiceField(
choices = (
('1',"Enero"),
('2',"Febrero"),
('3',"Marzo"),
('4',"Abril"),
('5',"Mayo"),
('6',"Junio"),
('7',"Julio"),
('8',"Agosto"),
('9',"Septiembre"),
('10',"Octubre"),
('11',"Noviembre"),
('12',"Diciembre"),
),
widget = forms.Select()
)
def __init__(self, *args, **kwargs):
super(ProvSearchForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
my view:
#login_required(login_url='/login/')
def BuscarView(request):
if request.method == 'POST':
form = ProvSearchForm(request.POST)
nombre = request.POST.get('proveedor')
mes = request.POST.get('mes')
usuario = request.user
if form.is_valid():
cargaftp = Lectura_FTP()
spftp = cargaftp.leer_ftp()
carga = Actualizar_Descarga()
sp = carga.actualiza(nombre,mes,usuario)
return HttpResponseRedirect('/archivo/')
else:
form = ProvSearchForm()
return render_to_response('buscarform.html',
{'form':form})
my url:
url(r'^buscar/$', 'pc.views.BuscarView', name='buscar'),
This form is take some parameters and pass it to a stored procedure, I need to pass the username from the logged user, but I get an empty (or null) value.
In the navbar of my template I have the tag {{ user.username }} to render the username, but in the template where I pass the non-model based form I can't see any username and I can access without beign logged.
How can enable the authentication in the forms non-model based or how can I pass the username from the logged user to this form.
Thanks in advance
You are not passing RequstContext with render_to_response
i.e
return render_to_response('buscarform.html',
dict, context_instance=RequestContext(request))