required authentication in forms - django

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))

Related

How to transfer some variable to django form?

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)

KeyError at /addData/ 'user'

Getting this KeyError on form POST action. What I'm trying to do here is my users have lists and in those lists they can add number values. Here I'm trying to call for all of some specific users lists to my form where user can choose which for of his/hers list they want to add the value to.
form:
class data_form(forms.Form):
selection = forms.ModelChoiceField(queryset=None)
data = forms.IntegerField()
def __init__(self, *args, **kwargs):
user = kwargs.pop("user")
super(data_form, self).__init__(*args, **kwargs)
self.fields['selection'].queryset = List.objects.filter(user=user)
Views, first handles main page and second is for adding the data
#login_required
def app(request):
form = list_form
form2 = data_form(user=request.user)
user = request.user.pk
user_lists = List.objects.filter(user=user)
list_data = {}
for list in user_lists:
list_data[list.name] = DataItem.objects.filter(list=list)
context = {'user_lists': user_lists, 'form': form, 'form2': form2, 'list_data': list_data}
return render(request, 'FitApp/app.html', context)
#require_POST
def addData(request):
form = data_form(request.POST)
if form.is_valid():
new_data = DataItem(data=request.POST['data'], list=List.objects.get(id=request.POST['selection']))
new_data.save()
return redirect('/app/')
You forgot to pass the user instance to your form. Also you shouldn't be accessing the POST data directly, use the form cleaned_data. And since selection is a ModelChoiceField you get the instance selected already not the id, so no need make a query.
#require_POST
def addData(request):
form = data_form(request.POST, user=request.user)
if form.is_valid():
cd = form.cleaned_data
new_data = DataItem(data=cd['data'], list=cd['selection'])
new_data.save()
return redirect('/app/')

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.

Pass logged user to model field django

I don't know how to get the username from the current user.
I have a edit form rendered with djano-crispy-forms:
class RecepcionForm(forms.ModelForm):
fecha_recepcion = forms.DateField(widget=DateInput())
def __init__(self,*args,**kwargs):
super(RecepcionForm,self).__init__(*args,**kwargs)
self.helper = FormHelper(self)
self.helper.layout = Layout(
Field('id_proveedor',
'anio',
'mes',
'usuario',
readonly = True
),
Fieldset('',
'fecha_recepcion',
'num_archivos',
Submit('save','Grabar')
)
)
class Meta:
model = DetalleRecepcion
my views.py:
#login_required(login_url='/login/')
def RecepcionView(request):
idp = request.GET.get('i')
anio = request.GET.get('a')
mes = request.GET.get('m')
if request.method == 'POST':
r = DetalleRecepcion.objects.get(id_proveedor=idp,anio=anio,mes=mes)
form = RecepcionForm(request.POST, instance=r)
if form.is_valid():
form.save()
return HttpResponseRedirect('/monitor/')
else:
r = DetalleRecepcion.objects.get(id_proveedor=idp,anio=anio,mes=mes)
form = RecepcionForm(instance=r)
return render_to_response('recepcion.html',
{'form':form},
context_instance=RequestContext(request))
I need to fill the field usuario with the logged username.
I tried with form = request.user.username before the save of the form.
I am confused of this have to be done passed the value in the form definition or in the view.
If is possible to overwrite the retrieved value from the database and fill the field with the username in the form class.
Another question
How can I change the widget type in the form. The field id_proveedor is a foreign key and is rendered as a drop down box (select widget), but I need to show the value displayed in a label where the can't edit the value.
I tried with the readonly propertie, but the user is not capable to write in the select box, but is capable to select from the drop down.
How can change the widget or how can I disabled the drop dwon function from the select box
Thanks in advance
You can always pass whatever arguments or keyword arguments you need to a form class, you just have to remove them from the *args or **kwargs that are passed on when calling super(), otherwise Django will throw an exception because it's receiving an arg or kwarg it's not expecting:
class MyForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user') # notice the .pop()
super(MyForm, self).__init__(*args, **kwargs)
# views.py
def my_view(request):
# assuming the user is logged in
form = MyForm(user=request.user)
I came across the same as your problem and found a solution just now. I do not know whether this is the best solution or maybe I will have problem later.
def add_trip_event(request):
#form = Trip_EventForm()
#return render(request, 'trips/add_trip_event.html', {'form': form})
if request.method == "POST":
form = Trip_EventForm(request.POST, request.FILES)
if form.is_valid():
post = form.save(commit=False)
post.trip_owner = Owner.objects.get(owner=request.user)
post.pub_date = timezone.now()
post.view = 0
post.save()
form.save_m2m()
return HttpResponseRedirect(reverse('trips:index'))
else:
form = Trip_EventForm()
return render(request, 'trips/add_trip_event.html', {'form': form})