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!
Related
I have this code in which I need to use a method that takes the number the person inputs to check if the person exists in the database. The thing is, how do I pass the numbers the person uses to the method?
The numbers are what's called cuit in here.
The method works like this:
response=get_persona("74013028")
The numbers should be the ones the person types. If the person exists, it returns the name and last name like this:
response["persona"]["lastname"]["name"]
If the person doesn't exist, it has to print that.
Where should I place this piece of code and how do I make it take the input of the user to verify if the person is in the database?
This is the view:
from django.shortcuts import render, HttpResponse
import requests
from django.views import View
from .forms import MonotributoForm
from app.ws_sr_padron import get_persona
class Constancia(View):
def get(self, request):
return render(request, 'app/constancia-inscripcion.html')
def post(self,request):
if request:
form = MonotributoForm(request.POST)
if form.is_valid():
cuit = form.cleaned_data.get('cuit')
email = form.cleaned_data.get('email')
cuit.save()
email.save()
return HttpResponseRedirect('app/constancia-inscripcion.html')
else:
pass
return render(request, 'app/constancia-inscripcion.html')
I was working on a project where the user inputs the answer to the question and then the user input needs to be checked on clicking submit button. If input matches the answer stored in database in the admin portal then it should redirect it to a new page else it should give an error wrong answer.
What's happening is that for every user input i am redirected to the other page. But never shows Wrong Answer even if input other than that in database answer is entered. How do I tackle this?
forms.py
from django import forms
from .models import Answer
from django.core.exceptions import ObjectDoesNotExist
class CheckAnswer(forms.Form):
your_answer=forms.CharField(label='Answer')
def clean(self):
cleaned_data=super(CheckAnswer,self).clean()
response=cleaned_data.get("your_answer")
try:
p = Answer.objects.filter(answer__contains=response)
except Answer.DoesNotExist:
raise forms.ValidationError("Wrong Answer")
models.py
from django.db import models
from django.contrib.auth import get_user_model
User=get_user_model()
users=User.objects.all()
class Answer(models.Model):
name=models.CharField(max_length=10,unique=True)
answer=models.CharField(max_length=100)
def __str__(self):
return self.name
class Meta:
ordering= ["-name"]
views.py
from django.shortcuts import render,redirect
from django.views.generic import *
from . import models
from django import forms
from .forms import CheckAnswer
def Arena1(request):
if request.method=='POST':
form = CheckAnswer(request.POST)
if form.is_valid():
return redirect('thanks')
else:
form=CheckAnswer()
return render(request,'levels/arena1.html',{'form':form})
The Model Managers filter method does not raise DoesNotExist, you should use Answer.objects.get(answer__contains=response) to raise DoesNotExist, keep in mind that this can also return a MultipleObjectsReturned error if there is more than one answer matching your response, filter will just return an empty list.
The other option is to use Answer.objects.filter(answer__contains=response).exists() and check if it returns true or false.
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']
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).
I have a signup form that needs to be loaded for every page of my site if the user is a guest. I figured the easiest way to do this would be to create a "signup" app/module and have the form variable defined in the init.py so it was automatically initiated on every view, assuming I imported the module. However, I'm having a bit of trouble getting my view to find the form variable. "global name 'form' is not defined" Below is my setup:
I have a /signup/init.py and /signup/form.py files.
This is my init.py
from django import forms
from signup.form import SignUpForm
form = SignupForm()
This is my form.py
class SignupForm(forms.Form):
fullname = forms.CharField(min_length=3, max_length=25, initial='name', error_messages={'required': 'A unique username is required.', 'min_length': 'Your username must contain at least 3 characters.'})
username = forms.CharField(min_length=3, max_length=25, initial='choose a username', error_messages={'required': 'A unique username is required.', 'min_length': 'Your username must contain at least 3 characters.'})
password = forms.CharField(min_length=7, initial='choose a password', error_messages={'required': 'Please enter a password.','min_length': 'Your password must contain at least 7 characters.'})
email = forms.EmailField(initial='e-mail address', error_messages={'required': 'Please enter a valid email address.', 'invalid': 'Please enter a valid email address.'})
find_me = forms.BooleanField(initial=True, required=False)
tos = forms.BooleanField(error_messages={'required': 'You must accept our Terms of Service.'})
And I'm trying to load those from my /views/index.py file:
from django.http import HttpResponse
from pymongo import *
from user import *
import mongo
from django.shortcuts import render_to_response
from django.template import RequestContext, loader
import signup
#index view
def index(request):
return render_to_response('index.html',
{'form': signup.form},
context_instance=RequestContext(request),
)
I removed the irrelevant code in index.py... but basically.. (i'll probably have an if else for the return statement to only return the 'form':form when the user is unregistered)
Am I approaching this completely wrong? Anyone mind showing me what I'm doing incorrectly?
::Edit::
Also, I noticed that I didn't have signup.form in the return, but that still throws a
AttributeError at /
'module' object has no attribute 'form'
error. I changed the code above to accommodate that
I would just point out that the way you're doing it is an extremely bad idea. You have one instance of the form across every request: that's always going to be dangerous, allowing the possibility of information leakage across requests. Don't do it.
Instead, use the built-in mechanism that Django has to do this for you: context processors. In your signup/form.py, define a simple function:
def signup_form(request):
return SignupForm()
and add this to TEMPLATE_CONTEXT_PROCESSORS in settings.py:
'signup.form.signup_form',
You should use from signup import form or from signup import * to make form variable available in your views.py. If you do import signup it will import the module with the namespace signup and to address the form you need to do signup.form.
I'm not sure what you are trying to do by assigning it to an identifier?
I would do this:
#init.py:
from django import forms
from signup.form import SignUpForm
#index view
def index(request):
return render_to_response('index.html',
{'form': signup.SignUpForm()},
context_instance=RequestContext(request),
)
OR
#init.py:
from django import forms
from signup.form import SignUpForm as Form
#index view
def index(request):
return render_to_response('index.html',
{'form': signup.Form()},
context_instance=RequestContext(request),
)
UPDATE
Change your form.py to :
class SignUpForm(forms.Form):
instead of :
class SignupForm(forms.Form):