I am trying to modify an app that I have found on the net in order to create surveys but I am getting an error that I do not manage to solve
form.py:
def save(self, commit=True):
import pdb; pdb.set_trace()
""" Save the response object """
# Recover an existing response from the database if any
# There is only one response by logged user.
response = self._get_preexisting_response()
if response is None:
response = super(ResponseForm, self).save(commit=False)
response.survey = self.survey
response.interview_uuid = self.uuid
if self.user.is_authenticated():
response.user = self.user
response.save()
# response "raw" data as dict (for signal)
data = {
'survey_id': response.survey.id,
'interview_uuid': response.interview_uuid,
'responses': []
}
# create an answer object for each question and associate it with this
# response.
for field_name, field_value in self.cleaned_data.items():
if field_name.startswith("question_"):
# warning: this way of extracting the id is very fragile and
# entirely dependent on the way the question_id is encoded in
# the field name in the __init__ method of this form class.
q_id = int(field_name.split("_")[1])
question = Question.objects.get(pk=q_id)
answer = self._get_preexisting_answer(question)
if answer is None:
answer = Answer(question=question)
if question.type == Question.SELECT_IMAGE:
value, img_src = field_value.split(":", 1)
# TODO
answer.body = field_value
data['responses'].append((answer.question.id, answer.body))
LOGGER.debug(
"Creating answer for question %d of type %s : %s", q_id,
answer.question.type, field_value
)
answer.response = response
answer.save()
survey_completed.send(sender=Response, instance=response, data=data)
return response
views.py
class SurveyDetail(View):
#import pdb; pdb.set_trace()
def get(self, request, *args, **kwargs):
survey = get_object_or_404(Survey, is_published=True, id=kwargs['id'])
if survey.template is not None and len(survey.template) > 4:
template_name = survey.template
else:
if survey.display_by_question:
template_name = 'survey/survey.html'
else:
template_name = 'survey/one_page_survey.html'
if survey.need_logged_user and not request.user.is_authenticated():
return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))
categories = Category.objects.filter(survey=survey).order_by('order')
form = ResponseForm(survey=survey, user=request.user,
step=kwargs.get('step', 0))
context = {
'response_form': form,
'survey': survey,
'categories': categories,
}
return render(request, template_name, context)
def post(self, request, *args, **kwargs):
import pdb; pdb.set_trace()
survey = get_object_or_404(Survey, is_published=True, id=kwargs['id'])
if survey.need_logged_user and not request.user.is_authenticated():
return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))
categories = Category.objects.filter(survey=survey).order_by('order')
form = ResponseForm(request.POST, survey=survey, user=request.user,
step=kwargs.get('step', 0))
context = {'response_form': form, 'survey': survey,
'categories': categories}
if form.is_valid():
session_key = 'survey_%s' % (kwargs['id'],)
if session_key not in request.session:
request.session[session_key] = {}
for key, value in form.cleaned_data.items():
request.session[session_key][key] = value
request.session.modified = True
next_url = form.next_step_url()
response = None
if survey.display_by_question:
if form.has_next_step():
save_form = ResponseForm(request.session[session_key],
survey=survey, user=request.user)
response = save_form.save(request)
else:
response = form.save()
if next_url is not None:
return redirect(next_url)
else:
del request.session[session_key]
if response is None:
return redirect('/')
else:
next_ = request.session.get('next', None)
if next_ is not None:
if 'next' in request.session:
del request.session['next']
return redirect(next_)
else:
return redirect('survey-confirmation',
uuid=response.interview_uuid)
if survey.template is not None and len(survey.template) > 4:
template_name = survey.template
else:
if survey.display_by_question:
template_name = 'survey/survey.html'
else:
template_name = 'survey/one_page_survey.html'
return render(request, template_name, context)
the weired thing is that I get the error AttributeError: 'ResponseForm' object has no attribute 'cleaned_data' even if the form got the is_valid attribute
.cleaned_data is only available once you call .is_valid() on the form.
Most likely you haven't called is_valid() on the form in your view yet.
Related
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']
I have multiple links on my page which redirects user to take quiz.
Some quiz requires user to login or create an account and some does not.
def dispatch(self, request, *args, **kwargs):
self.quiz = get_object_or_404(Quiz, url=self.kwargs['quiz_name'])
if self.quiz.draft and not request.user.has_perm('quiz.change_quiz'):
raise PermissionDenied
try:
self.logged_in_user = self.request.user.is_authenticated()
except TypeError:
self.logged_in_user = self.request.user.is_authenticated
if self.logged_in_user:
self.sitting = Sitting.objects.user_sitting(request.user,
self.quiz)
else:
self.sitting = self.anon_load_sitting()
if self.sitting is False:
if self.logged_in_user:
return render(request, self.single_complete_template_name)
else:
return redirect(settings.LOGIN_URL)
return super(QuizTake, self).dispatch(request, *args, **kwargs)
I would like user to redirect like how method decorator does
login/?next=/quiz/f506cb92-ccca-49ff-b2e5-730bbfea6a5a/take/
but instead I get /login/
I would like my user to come back to the page instead of going to "/dashboard"
In my settings I have
LOGIN_REDIRECT_URL ="/dashboard"
My LoginView:
class LoginView(FormView):
template_name = 'login.html'
form_class = LoginForm
success_url = '/dashboard'
def get(self, request, *args, **kwargs):
if request.user.is_authenticated:
return redirect ("/dashboard")
else:
return super(LoginView, self).get(request, *args, **kwargs)
def dispatch(self, request, *args, **kwargs):
if (self.request.user.is_authenticated) and (self.request.user.user_type==4):
return redirect('/dashboard')
else:
return super().dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs):
"""Use this to add extra context."""
context = super(LoginView, self).get_context_data(**kwargs)
if 'show_captcha' in self.request.session:
show_captcha = self.request.session['show_captcha']
context['show_captcha'] = True
return context
def form_valid(self, form):
user = form.login(self.request)
recaptcha_response = self.request.POST.get('g-recaptcha-response')
url = 'https://www.google.com/recaptcha/api/siteverify'
payload = {
'secret': settings.GOOGLE_RECAPTCHA_SECRET_KEY,
'response': recaptcha_response
}
data = urllib.parse.urlencode(payload).encode()
req = urllib.request.Request(url, data=data)
# verify the token submitted with the form is valid
response = urllib.request.urlopen(req)
result = json.loads(response.read().decode())
if result['success']:
if user.two_factor_auth is False and (user.phone_number_verified is True):
login(self.request, user)
try:
UserLog.objects.filter(username=user.id).update(failed_attempt=0)
except Exception:
print("No failed attempts ")
return redirect('/dashboard')
else:
try:
response = send_verfication_code(user)
pass
except Exception as e:
messages.add_message(self.request, messages.ERROR,
'verification code not sent. \n'
'Please retry logging in.')
return redirect('/login')
data = json.loads(response.text)
if data['success'] == False:
messages.add_message(self.request, messages.ERROR,
data['message'])
return redirect('/login')
if data['success'] == True:
self.request.method = "GET"
print(self.request.method)
kwargs = {'user':user}
return PhoneVerificationView(self.request, **kwargs)
else:
messages.add_message(self.request, messages.ERROR,
data['message'])
return redirect('/login')
else:
messages.add_message(self.request, messages.ERROR, 'Invalid reCAPTCHA. Please try again.')
return redirect('/login')
You should be fine by using #login_required() decorator docs are here.
This appends a ?next=... field which within login field you can take from the request.REQUEST.get('next', '/dashboard') and use this for redirect on successful login also look up this question to see if any other answer there satisifies the requirements
Also since you don't want decorators you can try saving to session as request.session["next"]=(source url) and within login view get session param and use it
I have a class that gets the data from the form, makes some changes and save it to the database.
I want to have several method inside.
Get
Post
And some other method that will make some changes to the data from the form
I want the post method to save the data from the form to the database and pass the instanse variable to the next method. The next method should make some changes, save it to the databese and return redirect.
But I have an error. 'Site' object has no attribute 'get'
Here is my code:
class AddSiteView(View):
form_class = AddSiteForm
template_name = 'home.html'
def get(self, request, *args, **kwargs):
form = self.form_class()
return render(request, self.template_name, { 'form': form })
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
# Get website url from form
site_url = request.POST.get('url')
# Check if the site is in DB or it's a new site
try:
site_id = Site.objects.get(url=site_url)
except ObjectDoesNotExist:
site_instanse = form.save()
else:
site_instanse = site_id
return site_instanse
return render(request, self.template_name, { 'form': form })
def get_robots_link(self, *args, **kwargs):
# Set veriable to the Robot Model
robots = Robot.objects.get(site=site_instanse)
# Robobts Link
robots_url = Robots(site_url).get_url()
robots.url = robots_url
robots.save()
return redirect('checks:robots', robots.id, )
I need to pass site_instanse from def post to def get_robots_link
Here is the traceback:
Internal Server Error: /add/
Traceback (most recent call last):
File "/home/atom/.local/lib/python3.8/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/home/atom/.local/lib/python3.8/site-packages/django/utils/deprecation.py", line 96, in __call__
response = self.process_response(request, response)
File "/home/atom/.local/lib/python3.8/site-packages/django/middleware/clickjacking.py", line 26, in process_response
if response.get('X-Frame-Options') is not None:
AttributeError: 'Site' object has no attribute 'get'
[14/Jul/2020 10:36:27] "POST /add/ HTTP/1.1" 500 61371
Here is the place where the problem is:
If I use redirect inside the post method. Everything works good. Like so:
class AddSiteView(View):
form_class = AddSiteForm
template_name = 'home.html'
def get(self, request, *args, **kwargs):
form = self.form_class()
return render(request, self.template_name, { 'form': form })
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
# Get website url from form
site_url = request.POST.get('url')
# Check if the site is in DB or it's a new site
try:
site_id = Site.objects.get(url=site_url)
except ObjectDoesNotExist:
site_instanse = form.save()
else:
site_instanse = site_id
# Set veriable to the Robot Model
robots = Robot.objects.get(site=site_instanse)
# Robobts Link
robots_url = Robots(site_url).get_url()
robots.url = robots_url
robots.save()
return redirect('checks:robots', robots.id, ) ## HERE
return render(request, self.template_name, { 'form': form })
But if remove the line return redirect('checks:robots', robots.id, ) from the post method and put return self.site_instance there. and add the def get_robots_link. It give the error: 'Site' object has no attribute 'get'
class AddSiteView(View):
form_class = AddSiteForm
template_name = 'home.html'
def get(self, request, *args, **kwargs):
form = self.form_class()
return render(request, self.template_name, { 'form': form })
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
# Get website url from form
site_url = request.POST.get('url')
# Check if the site is in DB or it's a new site
try:
site_id = Site.objects.get(url=site_url)
except ObjectDoesNotExist:
site_instanse = form.save()
else:
site_instanse = site_id
self.site_instance = site_instanse #See this
return site_instanse
return render(request, self.template_name, { 'form': form })
def get_robots_link(self, *args, **kwargs):
# Set veriable to the Robot Model
robots = Robot.objects.get(site=self.site_instance)
# Robobts Link
robots_url = Robots(site_url).get_url()
robots.url = robots_url
robots.save()
return redirect('checks:robots', robots.id, )
Use self to encode the data within the object
One must return a response from the post method. This code returns a Site instance on these lines. Not sure what is the intended behavior, either a redirect or render should be used.
try:
site_id = Site.objects.get(url=site_url)
except ObjectDoesNotExist:
site_instanse = form.save()
else:
site_instanse = site_id
return site_instanse
I'm having trouble getting ahold of postdata. For some reason the postdata in the following function returns an empty dict. I have a shopping cart, which I'd like users to pass their shipping preference and calculate the total based on the field passed.
My Form:
class ProductAddToCartForm(forms.Form):
""" form class to add items to the shopping cart """
quantity = forms.IntegerField(widget=forms.TextInput(attrs={'size':'2', 'value':'1', 'style':'width: 40px;'}),
error_messages={'invalid':'Please enter a valid quantity.'},
min_value=1)
product_slug = forms.CharField(widget=forms.HiddenInput())
shipping = forms.BooleanField(initial=True, required=False)
def __init__(self, request=None, *args, **kwargs):
""" override the default so we can set the request """
self.request = request
super(ProductAddToCartForm, self).__init__(*args, **kwargs)
def clean(self):
""" custom validation to check for presence of cookies in customer's browser """
if self.request:
if not self.request.session.test_cookie_worked():
raise forms.ValidationError("Cookies must be enabled.")
return self.cleaned_data
My View:
def show_cart(request, template_name="cart/cart.html"):
if request.method == 'POST':
postdata = request.POST.copy()
if postdata['submit'] == 'Remove':
cart.remove_from_cart(request)
if postdata['submit'] == 'Update':
cart.update_cart(request)
if postdata['submit'] == 'Checkout':
checkout_url = checkout.get_checkout_url(request)
return HttpResponseRedirect(checkout_url)
cart_items = cart.get_cart_items(request)
page_title = 'Shopping Cart'
cart_subtotal = cart.cart_subtotal(request)
return render_to_response(template_name, locals(), context_instance=RequestContext(request))
Function requiring postdata:
def cart_subtotal(request):
cart_total = decimal.Decimal('0.00')
cart_products = get_cart_items(request)
for cart_item in cart_products:
cart_total += cart_item.product.price * cart_item.quantity
return cart_total
I love how I can pass an instance to a form and it will populate it on a page. The trouble I am having is with formset_factory. I am trying to use query_set...
def classroom_update(request, pk):
classroom = get_object_or_404(Classroom, pk=pk)
students = classroom.student_set.all()
# Empty formset forms should be required
class RequiredFormSet(BaseFormSet):
def __init__(self, *args, **kwargs):
super(RequiredFormSet, self).__init__(*args, **kwargs)
for form in self.forms:
form.empty_permitted = False
#StudentFormSet = inlineformset_factory(Classroom, Student)
StudentFormSet = formset_factory(StudentForm, max_num=100, formset=RequiredFormSet)
if request.method == 'POST': # If the form has been submitted...
classroom_form = ClassroomForm(request.POST)
student_formset = StudentFormSet(request.POST, request.FILES)
if classroom_form.is_valid() and student_formset.is_valid():
classroom = classroom_form.save(commit=False)
classroom.user = request.user
classroom.save()
for form in student_formset.forms:
student = form.save(commit=False)
student.classroom = classroom
student.save()
return HttpResponseRedirect('/') # Redirect to a 'success' page
else:
classroom_form = ClassroomForm(instance=classroom)
student_formset = StudentFormSet(query_set=students)
# For CSRF protection
# See http://docs.djangoproject.com/en/dev/ref/contrib/csrf/
c = {'classroom_form': classroom_form,
'student_formset': student_formset,
}
c.update(csrf(request))
return render_to_response('reports/modify_classroom.html', c)
EDIT: Here is the error message...
formset_factory() got an unexpected keyword argument 'query_set'
Apparently I don't know how to use query_set...