first of all, I am new in programming with Django. Here is what I have:
The <form> inside my register.html template:
<form method='POST' action='/accounts/register/'>
{% csrf_token %}
{% for field in form %}
{{ field.label_tag }}{{ field }} {{field.help_text}} {{field.errors}{}
<br/>
{% endfor %}
<input type='submit' value='Register' />
</form>
This is inside my forms.py
class MyRegistrationForm(UserCreationForm):
email = forms.EmailField(required=True)
first_name = forms.CharField(required = True)
last_name = forms.CharField(required = True)
password1 = forms.RegexField(widget=forms.PasswordInput,
regex = r'[\w+]{8,}',
label = 'New password',
help_text = "Must be strong!",
error_messages = {'required' : "ASDASDA",
'invalid' : "ZZZZZ"}
)
password2 = forms.RegexField(widget=forms.PasswordInput,
regex = r'[\w+]{8,}',
label = 'Re-enter password',
)
class Meta:
model = User
fields = ('last_name', 'first_name', 'username', 'email', 'password1', 'password2')
def save(self, commit = True):
user = super(MyRegistrationForm, self).save(commit = False)
user.email = self.cleaned_data['email']
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
if commit:
user.save()
return user
This is inside my views.py
def User_Register_View(request):
if request.method == 'POST':
form = MyRegistrationForm(request.POST)
if form.is_valid():
form.save()
register_success = "Account successfuly created!"
return render(request,'index.html', locals())
args = {}
args.update(csrf(request))
args['form'] = MyRegistrationForm()
return render(request,'accounts/register.html',args)
My questions are the following:
{{field.errors}} is not working. No errors are printed. If I let all the fields of the form empty, and I click 'Register', no error is rendered.
If I add another field to this forum, "gender" as a CharField, will it create a column inside my DB for gender? ( I am working with the default sqlite3)
Is there a simple way to modify my code and make the 'User' field optional and, instead, make the 'Email' field be unique and required?
In the state in which my code is, where can I check for the unique property of my email in the DB? Is it inside my views.py, just before form.save() ?
Thank you. Let me know if you have any questions
def User_Register_View(request):
if request.method == 'POST':
form = MyRegistrationForm(request.POST)
if form.is_valid():
form.save()
register_success = "Account successfuly created!"
return render(request,'index.html', locals())
else:
form = MyRegistrationForm() # An unbound form
args = {}
args['form'] = form
return render(request,'accounts/register.html',args)
{{field.errors}} now showing because you are not returning the validated form instance if validation failed. You always return a new instance of MyRegistrationForm. See above example.
adding fields to forms will not affect your db since only models maps to db tables
& 4. You need custom user model to do so, see here for example on how to do it
Related
I have a signup view which takes an email, password, confirm password, and extra string, which must be unique. All of my validation errors return properly (e.g. if an email is duplicated, it displays this must be unique, and if the passwords don't match is displays passwords don't match). However, the extra string displays the django debug page with the validation error, rather than displaying it to the form. Why is this happening?
Django debug page error:
ValidationError at /signup/
['Extra string must be unique.']
Excerpt of template:
{% for field in form %}
<div class="form-group">
{% for error in field.errors %}
<p style="color: red">{{ error }}</p>
{% endfor %}
<label for="{{ field.id_for_label }}">{{ field.label }}:</label>
{{ field }}
</div>
{% endfor %}
Form:
class UserCreationForm(forms.ModelForm):
password1 = forms.CharField(label='Password', widget=forms.PasswordInput(attrs={'class': 'form-control'}))
password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput(attrs={'class': 'form-control'}))
email = forms.CharField(label='Email', widget=forms.EmailInput(attrs={'class': 'form-control'}))
extra_string = forms.CharField(label='Extra String (Must be unique)', widget=forms.TextInput(attrs={'class': 'form-control'}))
class Meta:
model = User
fields = ('email',)
def clean_password2(self):
"""A function to check that the two passwords provided by the user match."""
# Check that the two password entries match
#: User's password.
password1 = self.cleaned_data.get("password1")
#: Password confirm.
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("The passwords must match.") #: This displays properly
return password2
def ensure_unique_string(self):
"""Checks that the entered extra string is unique"""
extra= self.cleaned_data.get("extra_string")
if len(ExtraString.objects.filter(name=extra)) > 0:
raise forms.ValidationError("Ana Group Name must be unique.") #: This displays django debug page
return extra
def save(self, commit=True):
user = super(UserCreationForm, self).save(commit=False)
user.set_password(self.clean_password2())
user.extra_string = self.ensure_unique_string()
user.has_migrated_pwd = True
if commit:
user.save()
return user
Signup View:
class SignUpView(View):
template_name = "account/signup.html"
def get(self, request):
form = UserCreationForm()
return render(request=request, template_name=self.template_name, context={
"form": form
})
def post(self, request):
form = UserCreationForm(request.POST)
if form.is_valid():
user = form.save()
messages.success(request, 'Successfully Registered')
next_url = request.POST.get('next') if 'next' in request.POST else 'profile'
return redirect(next_url)
return render(request, template_name=self.template_name, context={"form": form})
that because you raise in save methods, when you are in the save, is telling your all field are validate, so you need to validate your field before call save methods.
you have 2 solution:
in clean_FIELD_NAME:
def clean_extra_string(self, data):
if len(ExtraString.objects.filter(name=data)) > 0:
raise forms.ValidationError("Ana Group Name must be unique.")
return data
in validate methods:
def validate(self, validate_data):
if len(ExtraString.objects.filter(name=validate_data['extra'])) > 0:
raise forms.ValidationError("Ana Group Name must be unique.")
return validate_data
I am very new to Python and Django and am stuck with this problem , which I think should be very simple to solve.
model.py
class UserDetails(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
billingAddress = AddressField(related_name='+',blank =True ) # Used django-address https://pypi.org/project/django-address/
shippingAddress = AddressField(related_name='+',blank =True)
forms.py
class AddressForm(forms.ModelForm):
class Meta:
model = UserDetails
exclude = ['user']
views.py
def address(request):
form = AddressForm(request.POST or None)
if request.method == 'POST' and form.is_valid():
zipCode = request.POST.get("ZipCode","")
form = AddressForm(data=request.POST)
detailForm = form.save(commit = False)
detailForm.user = request.user
baddressDict = {'raw':request.POST.get("billingAddress","")+", " + zipCode, 'postal_code': zipCode,}
saddressDict = {'raw':request.POST.get("shippingAddress","")+", " + zipCode, 'postal_code': zipCode,}
detailForm.billingAddress = baddressDict
detailForm.shippingAddress = saddressDict
detailForm.save()
else:
form = AddressForm()
return render(request,'showcase/address.html',{'form': form})
address.html
<form action="." method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="text" name="ZipCode" value="Vip Code" >
<input type="submit" value="Submit" >
</form>
What I am trying to do it update the shipping & Billing address for current user.
The first time I am doing this it works but the second time it gives
UNIQUE constraint failed: showcase_userdetails.user_id
which obviously is cause it trying to add another row in the DB.
How do i make sure it updates and not insert?
Thanks,
Gourav
Quite simply, you have to pass an existing instance of your model:
def edit_address(request):
user = request.user
try:
address_instance = UserDetail.objects.get(user=user)
except UserDetail.DoesNotExist:
address_instance = None
if request.method == 'POST':
form = AddressForm(request.POST, instance=address_instance)
if form.is_valid():
details = form.save(commit=False)
# You should really let the form takes care of all this,
# and you should DEFINITLY NOT use unsanitized data from
# request.POST - the whole point of forms is to make sure
# your user inputs are properly sanitized...
details.user = request.user
# etc
else:
# passing it for the GET part too so the user
# can see the already existing data (if any)
form = AddressForm(instance=address_instance)
return render(request,'showcase/address.html',{'form': form})
I am trying to create a formset that captures a parameter from the url to prefill one of the fields. The form is displaying correctly and at the correct address, but after clicking "submit" the page redirects to "/correction/" instead of the intended /correction/A07686+dwdID19, and the form does not save. What might be the issue?
In models.py:
class correction(models.Model):
corrected_word = models.ForeignKey(item)
correction_author = models.ForeignKey(User)
correction_made = models.IntegerField(u'correction_made', choices=CORRECTION_CHOICES)
correction_word = models.CharField(u'correction_word', max_length=200, blank=True, null=True)
time = models.DateTimeField(auto_now_add=True)
approved = models.IntegerField(u'approved', choices=APPROVAL_CHOICES, blank=True, null=True)
def __unicode__(self):
return str(self.time)
In views.py:
def submit_corr(request, bdword):
if hasattr(request, 'user') and request.user.is_authenticated():
word = item.objects.filter(file_position=bdword)[0]
CorrFormSet = inlineformset_factory(item, correction, fields=['correction_made', 'correction_word','correction_author'], can_delete=False, extra=1)
form = CorrFormSet(request.POST, request.FILES, instance=word, initial=[{'correction_author': request.user,}])
if request.method == 'POST':
if form.is_valid():
for entry in form:
entry.save()
else:
form = CorrFormSet(instance=word, initial=[{'correction_author': request.user,}])
return render(request, "correctionform.html", {"form": form,"word": word})
In urls:
url(r'^correction/(?P<bdword>.*)$', 'english.views.submit_corr'),
In the template:
Submit correction</th>
Thanks in advance!
Submit correction doesn't submit a form because it's a link and when you press a link, this sends a request with a GET method to the server so never enter to if request.method == 'POST': .
Please try something like
<form action="/correction/{{word.file_position}}" method="POST">
{# your inputs fields#}
<button type="submit">Submit correction</button>
</form>
I hope to be useful. Regards
I have a form with radio buttons and text fields. When I submit the form, the boolean field does not get created in the record. The boolean field is supposed to be updated via the radio buttons. What could be the issue here?
Here is the relevant part of my forms.py file:
CHOICES = (
(1,'yes'),
(0,'no')
)
class ServiceForm(forms.ModelForm):
one_time_service = forms.ChoiceField(required = True, choices = CHOICES, widget=forms.RadioSelect())
class Meta:
model = Service
fields = ('one_time_service')
This is my models.py one_time_service field
one_time_service = models.BooleanField(default=False)
This is my views.py:
def create(request):
if request.POST:
form= ServiceForm(request.POST)
if form.is_valid():
service_obj = form.save(commit=False)
service_obj.user_id = request.user.id
service_obj.save()
return render_to_response('services/service_created.html',
{'service': Service.objects.get(id=service_obj.id)})
else:
form = ServiceForm()
args= {}
args.update(csrf(request))
args['form'] = form
return render_to_response('services/create_service.html', args )
Edit: Here is my create_service.html
<form action="/services/create" method="post" enctype="multipart/form-data">{% csrf_token %}
<ul>
{{form.as_p}}
</ul>
<input type="submit" name="submit" value="Create Service">
</form>
I have no idea if this is the problem, but the line:
fields = ('one_time_service')
is wrong. That's not a single element tuple, that's a string with parens around it. Add a comma to make it a tuple:
fields = ('one_time_service',)
Edit: also, form.save() does not update any database records -- it creates a new one! That may be your problem.
So I'm building a basic Q&A site-- Each topic has a series of questions associated with it, and each question has multiple answers associated with it.
I'm creating the user input for questions and they have to associated with a topic. This is the questions model
#models.py
class Question(models.Model):
movie = models.ForeignKey(Movie, blank=True, null=True)
question_text = models.CharField(max_length = 1000)
question_detail = models.CharField(max_length = 5000, blank = True, null = True)
q_pub_date = models.DateTimeField(auto_now_add = True)
q_author = models.ForeignKey(User)
class QuestionForm(ModelForm):
def save(self, user = None, force_insert = False, force_update = False, commit = True):
q = super(QuestionForm, self).save(commit = False)
q.q_author = user
if commit:
q.save()
return q
class Meta:
model = Question
exclude = ('movie', 'q_author', 'q_pub_date')
This is the URL conf
#urls.py
url(r'^(?P<movie_id>\d+)/add_question/$', 'add_question'),
Now here is the view
#views.py
def add_question(request, movie_id):
if request.method == "POST":
form = QuestionForm(request.POST, request.FILES)
#QuestionForm.movie = Movie.objects.get(pk = movie_id)
if form.is_valid():
form.save(user = request.user)
return HttpResponseRedirect("/home/")
else:
form = QuestionForm()
return render_to_response("qanda/add_question.html", {'form': form}, context_instance = RequestContext(request))
This is the HTML code
#add_question.html
<h1> Add Question: {{ user.username }}</h1>
<form action = "" method = "post">{% csrf_token %}
{{ form.as_p }}
<input type = "submit" value = "Ask" />
<input type = "hidden" name = "next" value = "{{ next|escape }}" />
</form>
In the view, the commented out line is what I added to the view to try and auto save the model. When adding a question, the URL has the ID of the movie it is associated with, and my thought is to take that ID and then plug it into the ForeignKey to identify which movie is associated with the question. However, when I use my code, it changes all of the Questions' movie associations to the current movie instead of just changing that specific question's movie association. Without the code, it doesn't associate a Movie with the Question at all. How do I fix this?
Use this:
#views.py
def add_question(request, movie_id):
if request.method == "POST":
form = QuestionForm(request.POST, request.FILES)
if form.is_valid():
question = form.save(user = request.user)
question.movie = Movie.objects.get(pk = movie_id)
question.save()
return HttpResponseRedirect("/home/")
else:
form = QuestionForm()
return render_to_response("qanda/add_question.html", {'form': form}, context_instance = RequestContext(request)
For question asked in comment
You should avoid using absolute URLs in views or templates. Consider a scenario, where you decide to change home URL from /home/ to /myhome/. You will have to edit it where ever you have used them. It is always better to name the urls (docs):
# URL Conf
url(r'^home/$', 'home_view', name="home_url"),
url(r'^(?P<movie_id>\d+)/add_question/$', 'add_question', name="add_question_url"),
url(r'^home/(?P<movie_id>\d+)/$', 'movie_view', name="movie_url"),
The name argument act as an unique identifier to your actual URLs
Now in you views:
from django.core.urlresolvers import reverse
def some_view(request):
...
return HttpResponseRedirect(reverse('home_url'))
Now what ever change you make to the URL (say /home/ to /myhome/ makes no effect to the view as long as the name argument has the same value in the URL conf.
If you wish to pass parameters (like movie_id in your case)
def some_view(request, movie_id):
...
return HttpResponseRedirect(reverse('movie_url', kwargs={'movie_id':movie_id}))
The same concept should be used in templates to avoid hard-coding URLS in templates. Please read this for more details