On the 'panel' page, I have a choice field with a list of uploaded documents or 'bots' as I usually refer to them. This list only displays 'bots' that have been uploaded by the current user.
panel\forms.py
from django import forms
import os
from upload.models import Document
#### RETRIEVE LIST OF BOTS UPLOADED BY CURRENT USER ####
def get_files(user):
bots = Document.objects.filter(user=user.id)
file_list = []
for b in bots:
file_list.append((b.id,b.docfile))
return file_list
class botForm(forms.Form):
def __init__(self, user, *args, **kwargs):
super(botForm, self).__init__(*args, **kwargs)
self.fields['bot'] = forms.ChoiceField(choices=get_files(user))
This works fine and displays a list of all the users bots. The problem arises when I try to pass these values over to the 'game' page and access them here.
game\views.py
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from game.models import game
from game.forms import GameForm
from upload.models import Document
from panel.forms import botForm
import league
def RPS(request):
if request.method == 'POST': # If the request is a POST method...
if 'PanelPlay' in request.POST:
panel = botForm(request.POST)
if panel.is_valid():
print panel.cleaned_data['bot']
elif 'GamePlay' in request.POST:
form = GameForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
leagueOuput = []
leagueOutput = league.run(form.cleaned_data['bot1'],form.cleaned_data['bot2'])
newGame = game()
newGame.bot1 = leagueOutput[0]
newGame.bot2 = leagueOutput[1]
newGame.bot1wins = leagueOutput[2]
newGame.bot2wins = leagueOutput[3]
newGame.save()
return HttpResponseRedirect(reverse('game.views.RPS')) # Redirect after POST
form = GameForm() # An unbound form
results = game.objects.all() # Load messages for the list page
return render_to_response('game.html', {'results': results, 'form': form}, context_instance=RequestContext(request))
When attempting to access and validate the panel data, I get the following error.
'QueryDict' object has no attribute 'id'
Referring to this specific line.
bots = Document.objects.filter(user=user.id)
I have found and read about a number of similar issues but I can't seem to carry over their solutions to my own project.
Thanks in advance for any and all help.
When you are constructing the botForm, you're passing request.POST (a QueryDict) as the user parameter. Did you mean
panel = botForm(request.user, data=request.POST)
?
(assuming you're using django authentification).
Related
I'm building a quiz app in which I'm storing questions in the database by creating a model class. I am retrieving a random question set for each user from the database and then rendering them on an HTML page. The problem is after logging a user in, a random set of questions appears but that random set is lost after refreshing the page.
How do I solve this
One thing that I thought was retrieving the object set in another view....say after logging a user in and passing it as a dictionary to another view.
But I can't find the syntax or any function (if it exists). Please help.
I'm using django 3.1 and MySQL as my database.
My views.py looks like this:
from django.shortcuts import render, redirect
from .models import *
from .forms import UserForm
from django.contrib.auth.forms import AuthenticationForm
import random
from django.contrib.auth import login, logout, authenticate
# Create your views here.
def home(request):
return render(request, 'testapp/home.html')
def loginuser(request):
#form = UserForm()
if request.method == 'GET':
form = AuthenticationForm()
return render(request, 'testapp/login.html', {'form':form})
else:
user = authenticate(request, username=request.POST['username'], password=request.POST['password'])
if user is None:
return render(request, 'testapp/login.html', {'form':AuthenticationForm(), 'error':'Username or password incorrect'})
else:
login(request, user)
return redirect('paper')
def paper(request):
#objects = Questions.objects.all()
"""count = Questions.objects.all().count()
slice = random.random() * (count-5)
objects = Questions.objects.all()[slice:slice+5]"""
#objects = {{ objects }}
objects = Questions.objects.all().order_by('?')[:5]
return render(request, 'testapp/paper.html', {'objects':objects})
There isn't really a direct way to pass values between views such as args or kwargs. I would recommend using the request session to store values and access them again.
def paper(request):
question_set = Questions.object.all()
question_set = question_set.order_by('?')[:5]
# Retrieve the primary keys from the 5 questions selected.
question_pks = question_set.values_list('pk', flat=True)
# Store the pks in a list on the request session.
request.session['question_ids'] = list(question_pks)
context_data = {'objects': question_set}
return render(request, 'testapp/paper.html', context_data)
def home(request):
# Get all the pks from the request session again.
question_pks = request.session['question_ids']
# Use the pks to retrieve the same question objects from the database.
question_set = Questions.objects.filter(pk__in=question_pks)
context_data = {'objects': question_set}
return render(request, 'testapp/home.html', context_data)
You can make use of request.session to store your questions ids the first time :
def paper(request):
if 'question_ids' not in request.session:
request.session['question_ids'] = list(Questions.objects.all().order_by('?').values_list('id', flat=True)[:5])
objects = Questions.objects.filter(id__in=request.session['question_ids'])
return render(request, 'testapp/paper.html', {'objects':objects})
I'm trying to write a simple IF statement on checking if a lastname in a database exists before a user hits the submit button to create a new record. Here is my code so far, I'm new to Django and Python so the help is appreciated.
I made a variable called lastname, the thought process here is when the user hits submit, it checks the database first before the commit to warn them with a popup if the lastname exists to prevent duplicate records. It would actually be really cool to have it when a person exits the field for it to run the script before they finish filling out the form to save time.
#views.py
from .models import StudentCheck
from django.shortcuts import render
from django.http import HttpResponse, Http404, HttpResponseRedirect
from forms.forms import NewStudentForm
def NewStudentFormCheckList (request):
if request.method == 'POST':
form = NewStudentForm(request.POST)
lastname = StudentCheck.lastname
if form.is_valid():
newstudent= form.save()
else:
form = NewStudentForm()
return render(request, 'forms/newstudentcheck_form.html', {'form': form})
Here is my test code to see if query is working correctly and i keep getting a error that the query set doesnt exists.
from .models import StudentCheck
from django.core.exceptions import ValidationError
from django.shortcuts import render
from django.http import HttpResponse, Http404, HttpResponseRedirect
from forms.forms import NewStudentForm
def NewStudentFormCheckList (request):
if request.method == 'POST':
form = NewStudentForm(request.POST)
lastname = StudentCheck.lastname
number_lastnames = StudentCheck.objects.get(lastname__exact=lastname)
if form.is_valid():
newstudent= form.save()
print (number_lastnames)
else:
form = NewStudentForm()
return render(request, 'forms/newstudentcheck_form.html', {'form': form})
You can get all the entries in the database which have a given value already set using the field lookup exact (see here for more informations).
In your case it'll be StudentCheck.objects.get(lastname__exact=yourvalue). This would give you a QuerySet, and if you want to know how many entries have the given last name, you have to use count() on this QuerySet to know how many entries it has.
You can use this solutions in two different places:
Directly in the view, when receiving the POST values.
In a custom validator, which would be used in the definition of the model (see here to know how to do)
I would recommend to use the second one, as it would be easier to provide custom information for the user on why it's data where not accepted.
Both of these methods requires the data to be passed to the server to be validated though. Otherwise you can define a view that would receive the lastname and return if it's present already in the database in some way (JSON for example), which would be called using Ajax when the user click on the submit button.
Edit:
As per request of OP, here's an example of the custom validator:
from django.core.exceptions import ValidationError
from .models import StudentCheck
def validate_lastname(value):
number_lastnames = StudentCheck.objects.get(lastname__exact=value)
if number_lastnames > 0:
raise ValidationError(
'%s already exists' % value,
)
Now you can use this custom validator with attribute validators, either in the definition of your model or inside the definition of your form like this: lastname = models.CharField(validators=[validate_lastname]).
Hope it helps!
I am trying to add wikipedia API in django and process the wikipedia throung HTML input in view.py.
from django.contrib.auth.forms import UserCreationForm
from django.shortcuts import render
from django.http import HttpResponse
import wikipediaapi
from .forms import ContactForm, ColorfulContactForm
def _form_view(request, template_name='basic.html', form_class=ContactForm):
if request.method == 'POST':
form = form_class(request.POST)
mes = request.POST.get("message")
search = mes.split(' ')
query = search[2]
#return HttpResponse(mes)
mywiki(query)
if form.is_valid():
pass # does nothing, just trigger the validation
else:
form = form_class()
search_id = request.POST.get('message', None)
#
return render(request, template_name, {'form': form})
def mywiki(query):
wiki_wiki = wikipediaapi.wikipedia('en')
page_py = wiki.page(query)
title = page_py.title
return HttpResponse(title)
#return HttpResponse(mes )
I get an error which reports:
TypeError: 'module' object is not callable
Anyone help me
Reason behind error:
Correct format is wikipediaapi.Wikipedia('en'), not wikipediaapi.wikipedia('en')
Note that W in Wikipedia is in caps.
Also You should use
page_py = wiki_wiki.page(query)
instead of
page_py = wiki.page(query)
Since your object variable is wiki_wiki not wiki.
The problem seems to be the line
wiki_wiki = wikipediaapi.wikipedia('en')
according to Wikipedia API docs
wiki_wiki = wikipediaapi.Wikipedia('en')
Wikipedia starting with capital W, which is a class name is called to create the instance. What currently is being used is wikipedia.wikipedia which is a Python module, and as the exception hints, is not callable.
When I load my view at : localhost:8000/Scan, it throws an issue of:
TypeError on views.py in Scan, line 27:
form = Scan() # Otherwise, set the form to unbound
Any idea what I'm doing wrong here? I tried researching, but couldn't find the answer. (Django newbie here) . Thank you all!
Views.py
from django.http import HttpResponse
from Scanner.forms import SubmitDomain
def Scan(request):
if request.method == 'POST': # If the form has been submitted...
form = SubmitDomain(request.POST) # A form bound to the POST data
if form.is_valid(): # If form input passes initial validation...
form.cleaned_data['domainNm'] ## clean data in dictionary
try:
## check if Tld Table has submitted domain already
from Scanner.models import Tld
Tld.objects.get(domainNm=form.cleaned_data['domainNm'])
except Tld.DoesNotExist:
print "Would you like to create an account?"
## redirect to account creation
else:
print "Do you have an account? Please login."
## redirect to account login
else:
form = Scan() # Otherwise, set the form to unbound
Forms.py
from django.forms import ModelForm
from Scanner.models import Tld
class SubmitDomain(ModelForm):
class Meta:
model = Tld #Create form based off Model for Tld
fields = ['domainNm',]
def clean_domainName(self):
val = self.clean_domainName('domainNm')
return val
## This creates the form.
form = SubmitDomain()
In your model form:
from django.forms import ModelForm
from Scanner.models import Tld
class SubmitDomainForm(ModelForm):
class Meta:
model = Tld
fields = ['domainNm']
def clean_domainName(self):
val = self.cleaned_data.get('domainNm')
if Tld.objects.filter(domainNm=val).count() > 0:
raise forms.ValidationError(u'Sorry that domain already
exists, etc, etc')
return val
In your view, do:
from django.shortcuts import render
from Scanner.forms import SubmitDomainForm
def scan(request): # functions should start with a lowercase letter
# Bind the post data to the form, if it exists.
# No need for a separate if statement here
form = SubmitDomainForm(request.POST or None)
if request.method == 'POST':
if form.is_valid():
# save your model form, or do something else
return render(request, 'your-template.html', {'form': form})
Hope that helps you out. Your view is currently instantiating the wrong type of object for the form, hence the TypeError. Your current clean method on your model form will never validate anything. It just sets the value equal to the clean function. Instead of cluttering your view with form validation logic, put that into the clean method of the form for that field and you can raise exceptions for different conditions.
it fails when reuqest.method != "POST", in which case form is not defined
The problem is not specific to django, it's basic python. Your indentation is wrong. The code should probably look like this:
if request.method == 'POST':
form = SubmitDomain(request.POST)
if form.is_valid(): # indent fixed here
form.cleaned_data['domainNm']
I am trying to pass the id through reverse. But it's not working. I'm getting this error
Reverse for 'reg.views.thanks' with arguments '(20,)' and keyword arguments '{}' not found.
Here is my views.py:
from django.http import HttpResponse, Http404, HttpResponseRedirect
from django.core.urlresolvers import reverse
from reg.models import registration, registrationform
from django.shortcuts import render_to_response, get_object_or_404
from django.template import RequestContext
def registration(request):
if request.method == 'POST':
form = registrationform(request.POST)
if form.is_valid():
data = form.save()
id = data.id
return thanks(request,id)
else:
form = registrationform()
return render_to_response('registration.html', {'form' : form}, context_instance=RequestContext(request))
def thanks(request, id):
p = get_object_or_404(registration, pk=id)
return render_to_response('thanks.html', {'reg' : p})
Here is my urls.py:
from django.conf.urls import patterns, include, url
url(r'^registration/$', 'reg.views.registration'),
url(r'^thanks/$', 'reg.views.thanks'),
url(r'^$','django.views.generic.simple.direct_to_template', {'template' : 'index.html'}),
)
Here is thanks.html:
<html>
<body>
<p>Thank you for registration mr.{{reg.username}}</p>
</body>
</html>
and I'm also showing my models.py:
from django.db import models
from django.forms import ModelForm
class registration(models.Model):
username = models.CharField(max_length=100)
password = models.CharField(max_length=100)
def __unicode__(self):
return self.name
class registrationform(ModelForm):
class Meta:
model = registration
Thanks.
from this links (django tutorial):
https://docs.djangoproject.com/en/dev/topics/http/urls/#django.core.urlresolvers.reverse
example:
def myview(request):
return HttpResponseRedirect(reverse('arch-summary', args=[1945]))
so your code goes to:
in urls.py:
url(r'^thanks/(?P<id>\d+)$', 'reg.views.thanks', name='my_thanks_url')
in your function:
return HttpResponseRedirect(reverse('my_thanks_url', args=[id]))
This line
return HttpResponseRedirect(reverse('reg.views.thanks', args=(id,)))
Is trying to construct a url to your view reg.views.thanks, with the id variable used as a parameter.
This line in urls.py
url(r'^thanks/$', 'reg.views.thanks'),
Does not have anywhere for that parameter to go.
The first thing that you need to figure out is whether you actually want to send an HTTP redirect to the browser to tell it to go to the 'thanks' page. If you really do, then you need a way to send that id in the URL. You can do it as part of the URL path itself, as #moguzalp suggests, or you can put it in the query string, like
/thanks/?id=12345
Or you can do other things, like stashing the id in the user's session, and pulling it out when they request the thanks page. That's a bit more complicated, though.
If you don't actually need to issue an HTTP redirect, then there's nothing stopping you from just calling the thanks() function from inside your view function, like this:
def registration(request):
if request.method == 'POST':
form = registrationform(request.POST)
if form.is_valid():
data = form.save()
id = data.id
return thanks(request, id)
else:
form = registrationform()
return render_to_response('registration.html', {'form' : form}, context_instance=RequestContext(request))
The URL won't change in the browser, but the correct ID will be used, and doesn't need to appear anywhere else, in the URL, the query parameters, or the session