KeyError in Django form kwargs - django

def user_info(request, template_name='social/retrieve_user_data.html', username=None):
user = User.objects.get(username=username)
if request.method == 'POST':
form = UserInfoForm(request.POST, user)
print(form.is_valid())
if form.is_valid():
form.save()
else:
print('not post')
form = UserInfoForm(user)
return render_to_response(template_name, RequestContext(request, {
'form': form,
}))
class UserInfoForm(forms.Form):
def __init__(self,*args,**kwargs):
self.user = kwargs.pop('user')
super(UserInfoForm,self).__init__(*args,**kwargs)
This is producing a KeyError with exception value u'user'. What is wrong here? In both cases, form is initialized with a valid value of user. Why am I getting a keyerror>

You're not passing the user as a keyword argument in either the if or the else block. It should be:
form = UserInfoForm(request.POST, user=user)
and:
form = UserInfoForm(user=user)

Only func(foo=bar)can put {"foo":bar} into kwargs dictionary! According to your code form = UserInfoForm(request.POST, user),you can use self.user = args[1] to capture user.

Related

Cannot assign "<QuerySet [<Books: Utengano-ut/23>]>": "TeacherIssue.book_id" must be a "Books" instance

I wanted to implement Select2MultipleWidget but I have not managed to succeed in the view. This is what I have but it gives a value error
raise ValueError(
ValueError: Cannot assign "<QuerySet [<Books: Utengano-ut/23>]>": "TeacherIssue.book_id" must be a "Books" instance.
My view
def new_issue(request,pk):
if request.method == 'POST':
form = IssueForm(request.POST,school= request.user.school,pk=pk,issuer = request.user)
if form.is_valid():
print("Form valid")
try:
book = request.POST.getlist('book_id')
#book = form.cleaned_data['book_id'].id
for item in book:
form.cleaned_data[item].id
form.save(commit=True)
books = Books.objects.filter(id__in = book).select_related('subject')
for book.id in books:
Books.Claimbook(book)
return redirect('all_borrowed_teacher', borrowed=borrowed)
except Exception as e:
return redirect('teachers')
else:
form = IssueForm(school= request.user.school,pk=pk,issuer = request.user)
return render(request, 'lib.html', {'form': form})
This is the form
class IssueForm(forms.ModelForm):
def __init__(self,*args, pk, **kwargs):
super(IssueForm, self).__init__(*args, **kwargs)
self.fields["book_id"] = forms.ModelMultipleChoiceField(queryset=Books.objects.all(), widget=Select2MultipleWidget)
class Meta:
model = TeacherIssue
fields = ['book_id']

passing object between forms and views

I have a problem with passing object between views and forms and back.
On first form i check token (GET) with email - if it's ok - you can go further. If not - go away :D
views.py:
def login(request):
try:
token = request.GET['token']
except:
return render(request,'error.html')
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
return HttpResponseRedirect('/vote/')
else:
form = LoginForm(initial={'token': request.GET['token']})
return render(request,'login.html', context = {'form':form})
forms.py:
class LoginForm(forms.Form):
email = forms.EmailField(label='Email', max_length=254,widget=forms.TextInput(attrs={'class':'required'}))
token = forms.CharField(widget=forms.HiddenInput())
def clean(self):
cleaned_data = super().clean()
try:
voter = Person.objects.get(email__iexact=cleaned_data['email'],token__exact=cleaned_data['token'])
except Person.DoesNotExist:
raise ValidationError('Invalid email')
It works.
But now i try to go to voting form.
And I want to use voter object (which is set in LoginForm). Of course this is different form, so I have to pass it. I thought about session, but there's no request.session in form. This is in view, but there's no voter... or is it?
As always when I'm stuck for many minutes, I wrote the question and after few minutes I got excellent solution, so I want to share it with you:
I moved checking into view and use form.add_error. And I don't need token hidden field anymore:
forms.py:
class LoginForm(forms.Form):
email = forms.EmailField(label='Email', max_length=254,widget=forms.TextInput(attrs={'class':'required'}))
views.py:
def login(request):
try:
token = request.GET['token']
except:
return render(request,'error.html')
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
try:
voter = Person.objects.get(email__iexact=form.cleaned_data['email'],token__exact=token)
return HttpResponseRedirect('/vote/')
except Person.DoesNotExist:
form.add_error('email','Invalid email')
else:
form = LoginForm()
return render(request,'login.html', context = {'form':form})
And now I can pass voter into next form using request, session, whatever :D

How to use Httprequest object in FormView?

i was converting the below function view in class based view :
but the problem was the below login code uses request object . so how to use this request in a form view .
Functional view i wanted to change to class based view :
def login(request):
if request.method == 'GET':
form = UserLoginForm()
elif request.method == 'POST':
form = UserLoginForm(request.POST)
if form.is_valid():
username = form.cleaned_data.get('name')
password = form.cleaned_data.get('password')
user = User.objects.filter(name=username, password=password).first()
if user is not None:
request.session['user'] = username
return redirect('index')
else:
messages.error(request, 'Username or password no matched')
return render(request, 'products_app/login.html', {'form': form})
FormView/class based view of the above code i changed to that gives error :
class Login(FormView):
template_name = 'products_app/login.html'
form_class = UserLoginForm
success_url = reverse_lazy('index')
def form_valid(self, form):
username = form.cleaned_data.get('name')
password = form.cleaned_data.get('password')
user = User.objects.filter(name=username, password=password).first()
if user is not None:
request.session['user'] = username
else:
messages.error(request, 'Username or password no matched')
super().form_valid(form)
here the problem is ,request is not being received unlike in the functional view of above def login(request). so gives error:
module 'django.http.request' has no attribute 'session'
The problem is you are using the request module as stated in the error. What you actually want is the request instance that invoked the class. Your code should be self.request.
I've eliminated all the superfluous code to only show the parts with request.
class Login(FormView):
...
def form_valid(self, form):
...
if user is not None:
self.request.session['user'] = username
else:
messages.error(self.request, 'Username or password no matched')
...

create help text for a field dynamically

I have my response form and view like this
class ResponseForm(ModelForm):
class Meta:
model = ResponseModel
exclude = ('author', 'title','submit_count')
# help_texts = {
# 'ans1': user.q1.value,
# }
#login_required
def ResponseFormView(request):
if request.method == "POST":
form = ResponseForm(request.POST)
if form.is_valid():
submission = form.save(commit=False)
submission.author = request.user
submission.save()
return render(request, 'thanks.html', {})
else:
form = ResponseForm()
return render(request, 'response_tem.html', {'form': form})
I want the help text for 'ans1' field to be the value of q1 field of request.user. How do I do it?
You can do it like this:
class ResponseForm(ModelForm):
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None) # popping user from known arguments
super(ResponseForm, self).__init__(*args, **kwargs)
if user:
self.fields['ans1'].help_text = "Help Text for {}".format(user.username)
class Meta:
model = ResponseModel
exclude = ('author', 'title','submit_count')
#login_required
def ResponseFormView(request):
if request.method == "POST":
form = ResponseForm(request.POST)
if form.is_valid():
submission = form.save(commit=False)
submission.author = request.user
submission.save()
return render(request, 'thanks.html', {})
else:
form = ResponseForm(user=request.user) # passing user as known argument
return render(request, 'response_tem.html', {'form': form})
Here, in the view I am passing the request.user as known argument when I am initiating Form Class's Object (marked with comment). Then in the Form, I am catching the user sent from view and updating the field's help text.

Django - Form bind data after initialization

I have a user model for which I'm trying to make a view that manages both create/update form rendering/post.
Here is the view that I did for now
def user_edit(request, user_id=None):
obj = {}
status = 200
if user_id:
user = get_object_or_404(User, pk=user_id)
else:
user = User()
user_form = UserForm(instance=user, prefix='user')
if request.method == 'POST':
user_form = UserForm(request.POST, instance=user, prefix='user')
if user_form.is_valid():
user_form.save()
else:
status = 406
obj['user_form'] = user_form
return render(request, 'user/edit.html', obj, status=status)
This works fine, but as you can see, my user_form is initialized 2 times. In order to make this more DRY, at POST time I'd like to update the form definition instead of redefining it. Something like:
if request.method == 'POST':
user_form.data = request.POST
user_form.prefix = 'user'
But I can't make this work. So 2 questions:
Does my view seem valid ?
How can I avoid the form re-definition ?
I would just restructure a couple of lines this way:
def user_edit(request, user_id=None):
status = 200
if user_id:
user = get_object_or_404(User, pk=user_id)
else:
user = User()
user_form = UserForm(request.POST or None, instance=user, prefix='user')
if request.method == 'POST':
if user_form.is_valid():
user_form.save()
else:
status = 406
return render(request, 'user/edit.html', {'form': user_form}, status=status)
Sometimes, it makes sense to duplicate may be 1 line of code to keep it readable.
You should use if condition like this to initialize form only once:
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(request, 'contact.html', {
'form': form,
})
Taken from documentation of django. If you are new to Python, it may seem strange to define a variable in if..else statement, but it is pretty common and valid way in Python.