I am new in Django, I am trying to validate a form to get the particular value, if value is not exact validate error. For example, i have a field in a model (cot_code), the field has a integer value (12345). I have created a form for this field, i want if the user enter 12345 in form, the form will be valid as success "code is correct", but when user enter a wrong code (55777) the form will raise a validator error "Wrong code". I do not know how to go on with the views.
Model:
class CotCode(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
cot_code = models.IntegerField(default='0', blank=True) # I have set this field as 12345 in model.
date = models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name = 'CotCode'
verbose_name_plural = 'CotCode'
ordering = ['-date']
def __str__(self):
return self.user.username
Forms:
class CotCodeForm(forms.ModelForm):
class Meta:
model = CotCode
fields = ('cot_code',)
Views:
#login_required
def TransferCOTView(request):
#Don't know how to go on here
return render(request, 'transfer_cotcode.html')
Template:
<form method="POST" action="" class="text-center needs-validation" novalidate>
{% csrf_token %}
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="inputGroup-sizing-default">C.O.T</span>
</div>
<input type="text" class="form-control" aria-label="Sizing example input" aria-describedby="inputGroup-sizing-default" placeholder="Enter your COT Code" required>
<div class="invalid-feedback">
Please enter your C.O.T code.
</div>
</div>
<input type="submit" class="btn btn-primary btn-block btn-sm wave-effect my-2" value="{% trans 'Enter' %}" style="box-shadow:none;font-weight:500;"/>
</form>
Related
I want to create a dropdown Course of Trainee where only options of values in CourseName of Course model would be shown. Currently I have tried some soulutions after browsing. But its not working. My course dropdown disappeared after editing in forms.py. If i remove this line
Course = forms.ChoiceField(widget=forms.Select(attrs={'class':'col-sm-4'}), choices=course_obj.get_course_name(), label='Course :')
Then the dropdown would show but with no options
model.py
class Course(models.Model):
CourseID = models.AutoField(primary_key=True)
CourseName = models.CharField(max_length=20)
class Meta():
db_table = "Courses"
def get_course_name(self):
return self.CourseName
class Trainee(models.Model):
Name = models.CharField(max_length=50)
Course = models.CharField(max_length=40)
class Meta():
db_table = "Trainee"
forms.py
class TraineeForm(forms.ModelForm):
course_obj = Course()
Name = forms.CharField(widget=forms.TextInput(attrs={'class':'col-sm-4'}), label='Name :')
Course = forms.ChoiceField(widget=forms.Select(attrs={'class':'col-sm-4'}), choices=course_obj.get_course_name(), label='Course :')
........................
edit.html
<form method="post" class="form-group" type="multipart/form-data">
{%csrf_token%}
{% for Name in form.Name %}
<div class="form-group row">
<label class="col-sm-3 col-form-label">{{ form.Name.label }}</label>
{{ Name }}
</div>
{% endfor %}
{% for Course in form.Course %}
<div class="form-group row">
<label class="col-sm-3 col-form-label">{{ form.Course.label }}</label>
{{ form.Course }}
</div>
{% endfor %}
The Page appears like this
While looping a BoundField object - for Name in form.Name and for Course in form.Course in your case, Django loop through its sub widgets. A CharField has one sub widget, which is its self. A ChoiceField has as many sub widgets as its options, which is zero in your case. This is why your page rendered like that.
According to Django's Doc on choices attribute of ChoiceField:
Either an iterable of 2-tuples to use as choices for this field, enumeration choices, or a callable that returns such an iterable. This argument accepts the same formats as the choices argument to a model field. See the model field reference documentation on choices for more details. If the argument is a callable, it is evaluated each time the field’s form is initialized, in addition to during rendering. Defaults to an empty list.
Try
# forms.py
def course_choices():
return [(course.CourseName, course.CourseName) for course in Course.objects.all()]
class TraineeForm(forms.ModelForm):
Name = forms.CharField(widget=forms.TextInput(attrs={'class':'col-sm-4'}), label='Name :')
Course = forms.ChoiceField(widget=forms.Select(attrs={'class':'col-sm-4'}), choices=course_choices, label='Course :')
class Meta:
model = Trainee
fields = ['Name', 'Course']
And then in your template:
<!-- edit.html -->
<form method="post" class="form-group" type="multipart/form-data">
{% csrf_token %}
<div class="form-group row">
<label class="col-sm-3 col-form-label">{{ form.Name.label }}</label>
{{ Name }}
</div>
<div class="form-group row">
<label class="col-sm-3 col-form-label">{{ form.Course.label }}</label>
{{ form.Course }}
</div>
</form>
===== form.py =====
class TraineeForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(TraineeForm, self).__init__(*args, **kwargs)
self.fields['Course'].widget = forms.Select(choices=Course.objects.values_list('CourseName','CourseName'))
class Meta:
model = Trainee
fields = "__all__"
========= output ===========
I was updating the data in the database by takin the data from an html form when this appeared. I have faced this problem earlier also but I dont remember how to solve it .
my views.py part
def update(request,pk):
task = Task.objects.get(id=pk)
context = {
'task':task,
}
if request.method=="POST":
task.title= request.POST.get('taskname' )
task.save()
return redirect('/main')
return render(request,"update.html",context)
models.py file :
class Task(models.Model):
title = models.CharField(max_length =200)
complete = models.BooleanField(default = False , blank=True)
created = models.DateTimeField(auto_now=True)
my html file :
<div class="container">
<div class="jumbotron mt-3">
<form method= "post">
{% csrf_token %}
<h1 class="text-center">{{task}}</h1>
<input type="text" class="form-control rounded " id="task_name" name="task_name"
aria-describedby="emailHelp" placeholder="Add the task !">
<p class="lead text-center" > Do you really want to update ?</p>
<button class="btn btn-lg btn-primary" type ="submit" >Update »</button>
</form>
</div>
</div>
Your html input element's name attribute does not match the key you are attempting to access in request.POST. You would need to update your name attribute on your input to name="taskname" as opposed to name="task_name"
I would also suggest taking a look at Django's form docs and possibly adding validation since your error was caused by attempting to update the Task.title field with a None value
I inherited a project where we wanted to use django's native User model but also give users some additional fields. So I made a model called UserProfiles, which has a foreignkey to each User instance. I made a template to update these UserProfiles called settings-userprofile.html. Previously, we only had the field api_key for people to modify, so things were basic.
We want every User to have their own list of "assistant" Users, a label relevant for an API we'll be implementing. So I added the field assistants and updated settings-userprofile.html to include a <select multiple> element that lists out all the existing users on our site. We're using a theme/template that is able to implement the select2 pillbox/tokenization element (like the rightmost screencap in this picture)
user_profile/models.py
class UserProfile(models.Model):
phone_number = models.CharField(max_length=15, verbose_name='Phone Number')
user = models.OneToOneField(User, on_delete = models.CASCADE)
api_key = models.CharField(max_length=200, default='12345678',)
assistants = models.ManyToManyField(User, related_name="assistants")
settings-userprofile.html
<form class='form-horizontal' method="post" action="{% url 'profileUpdate' %}">
{% csrf_token %}
<div class="form-group row mb-4">
<label for="api_key" class="col-sm-3 col-form-label"><b>Profile Api Key:</b></label>
<div class="col-sm-9">
<input type="text" name="api_key" class="form-control" id="horizontal-apikey-input" value="{{ request.user.userprofile.api_key }}">
</div>
</div>
<div class="form-group">
<label class="control-label">User list</label>
<select name="assistants" class="select2 form-control select2-multiple" multiple="multiple" data-placeholder="Choose ...">
<optgroup label="Existing users">
{% for u in allUsers %}
{% if u in request.user.userprofile.assistants %}
<option selected value="{{ u.username }}">{{ u.username }}</option>
{% else %}
<option value="{{ u.username }}">{{ u.username }}</option>
{% endif %}
{% endfor %}
</optgroup>
</select>
</div>
<div class="form-group row justify-content-end">
<div class="col-sm-9">
<div>
<button type="submit" name='apikey_submit' class="btn btn-primary w-md">Submit</button>
</div>
</div>
</div>
</form>
user_profile/views.py
from .forms import UserProfileForm
#login_required
def display_settings_page(request):
form = UserProfileForm(instance=request.user)
allUsers = User.objects.all()
return render(request, 'settings-userprofile.html', { 'form':form, 'allUsers':allUsers })
#login_required
def settings_update_profile(request):
allUsers = User.objects.all()
if request.method == 'POST':
old_api = request.user.userprofile.api_key
form = UserProfileForm(data=request.POST, instance=request.user.userprofile)
if form.is_valid():
form.save()
messages.success(request, "Your API key was changed from " + old_api + " to " + form.cleaned_data["api_key"])
return render(request, 'settings-userprofile.html', {'form': form, 'allUsers':allUsers})
else:
print(form.errors)
return render(request, 'settings-userprofile.html', {'form': form, 'allUsers':allUsers})
# omitting the rest of this code since it only applies to GET requests
In forms.py, we represented assistants using forms.ModelMultipleChoiceField and specified the queryset as the set of all Users.
user_profile/forms.py
class UserProfileForm(forms.ModelForm):
api_key = forms.CharField(required=False)
assistants = forms.ModelMultipleChoiceField(required=False,
queryset=User.objects.all(),
)
class Meta:
model = UserProfile
fields = ['api_key', 'assistants']
This got me as far as to a point where I see a dropdown menu that lists out all the users on my site, and I can select 1 or more users. usernames and emails are the same on this application, so I see a list of emails as intended.
In the view function, I can use print(request.POST.getlist('assistants')) and it prints a list of the tokenized usernames selected in the dropdown menu on submission.
However, is_valid() is always failing and I'm not sure how to go about fixing it. For instance, we have a user registered at the email/username devtest4#gmail.com . Selecting them and Printing form.errors reveals...
<ul class="errorlist">
<li>assistants
<ul class="errorlist"><li>“devtest4#gmail.co
m” is not a valid value.</li></ul>
</li>
</ul>
The username still isn't being treated as a valid value, despite the fact that the queryset is specified to be a list of all users.
I have html form which I want to send and save to django model. When I try to send message I get an error:
ValueError at /account/userinfo/akylson/
"<Mail: hhh>" needs to have a value for field "id" before this many-to-many relationship can be used.
Request Method: POST
Request URL: http://localhost:8000/account/userinfo/akylson/
Django Version: 1.11.3
Exception Type: ValueError
Exception Value:
"<Mail: hhh>" needs to have a value for field "id" before this many-to-many relationship can be used.
You can see my code below.
Here is my html form below:-
<form role="form" class="form-horizontal" method="post">
{% csrf_token %}
<div class="form-group">
<input type="checkbox" id="id_receiver" name="receiver" value="{{ user.username }}" checked hidden>
<label class="col-lg-2 control-label">Тема</label>
<div class="col-lg-10">
<input type="text" placeholder="" id="id_subject" name="subject" value="{{ subject }}" class="form-control">
</div>
</div>
<div class="form-group">
<label class="col-lg-2 control-label">Сообщение</label>
<div class="col-lg-10">
<textarea rows="10" cols="30" class="form-control" id="id_message" name="message"></textarea>
</div>
</div>
<div class="form-group">
<div class="col-lg-offset-2 col-lg-10">
<span class="btn green fileinput-button"><i class="fa fa-plus fa fa-white"></i>
<span>Приложение</span><input type="file" name="files[]" multiple=""></span>
<button class="btn btn-send" value="submit" type="submit">Send</button>
</div>
</div>
</form>
Here is my view.py:
#login_required()
def userinfo(request, username):
username = User.objects.get(username=username)
args = {}
args['user'] = username
if request.method == 'POST':
sender = request.user
receiver = request.POST['receiver']
subject = request.POST['subject']
message = request.POST['message']
b = Mail.objects.create(sender=sender, receiver=receiver, subject=subject, message=message)
b.save()
return render(request, 'account/userinfo.html', args)
Here is my models.py:
class Mail(models.Model):
sender = models.ForeignKey(User, related_name='mail_sender')
receiver = models.ManyToManyField(User, related_name='mail_receiver')
subject = models.CharField(max_length=200)
message = RichTextUploadingField()
date = models.DateTimeField(auto_now=True, null=False, blank=False)
class Meta():
ordering = ['-date']
def __str__(self):
return self.subject
Here is my forms.py:
class NewMailForm(forms.ModelForm):
class Meta:
model = Mail
fields = (
'sender',
'receiver',
'subject',
'message',
)
widgets = {'receiver': forms.CheckboxSelectMultiple()}
You have to pass user instances to your views.py.
Change your views.py as showed below,
views.py:
#login_required()
def userinfo(request):
user = request.user
form = NewMailForm(request.POST or None)
if request.method == 'POST':
if not form.is_valid():
print form.errors
return render(request,'')
else:
sender = user
receiver = form.cleaned_data.get("receiver")
subject = form.cleaned_data.get("subject")
message = form.cleaned_data.get("message")
b = Mail.objects.create_user(
sender=sender,
receiver=receiver,
subject=subject,
message=message)
b.save()
return render(request, 'account/userinfo.html')
and forms.py:
<form action="." method="POST">{% csrf_token %}
{{ form.as_p }}
</form>
This will create a new mail objects with requested user.
In your views.py create an instance of your model
for example m = Mail()
then post each of the field using the instance for example
m.receiver = request.POST.get('receiver')
then save with
m.save()
Before a Many2many field can be linked Django needs the id of the record on the other side of the relationship (in this case your Mail) model.
So you have to actually create it before setting the receiver like this:
b = Mail.objects.create(sender=sender, subject=subject, message=message)
b.receiver = receiver
b.save()
You have made several mistakes:
forms.py is not required if you have made an HTML form and linked to project.
You have not defined b. Just written b.save
Just debug these errors and you are Done!
I've got a feedback app in django and it all seems to work fine, no errors i can submit the form and it all seems to work, however i have my model registered into my admin however when i submit the form i doesn't appear in my admin. Sorry if this is very basic i just cant get my head around it please help.
in my models.py
class Feedback(models.Model):
email = models.CharField(max_length=100)
message = models.CharField(max_length=1000)
def __unicode__(self):
return self.title
which i then pass through to forms.py
class FeedbackModelForm(forms.ModelForm):
class Meta:
model = Feedback
fields = ["email", "message"]
and my view is
def feedbackform(request):
form = FeedbackModelForm(request.Post or None)
if form.is_valid():
form.save()
return render(request, "feedback.html", {"form": form})
now in my html looks like this
{% block content %}
<div id="feedback">
<div id="feedback-form" style='display:none;' class="col-xs-4 col-md-4 panel panel-default">
<form method="POST" action="{{ form }}" class="form panel-body" role="form">{% csrf_token %}
<div class="form-group">
<input class="form-control" name="email" autofocus placeholder="Your e-mail" type="email" />
</div>
<div class="form-group">
<textarea class="form-control" name="message" required placeholder="Please write your feedback here..." rows="5"></textarea>
</div>
<button class="btn btn-primary pull-right" type="submit">Send</button>
</form>
</div>
<div id="feedback-tab">Feedback</div>
</div>
{% endblock %}
and in my admin
from .models import Feedback
from .forms import FeedbackModelForm
class FeedbackAdmin(admin.ModelAdmin):
form = FeedbackModelForm
admin.site.register(Feedback, FeedbackAdmin)
You have passed the
{{ form }}
as the action attribute, which is completely wrong. Put it inside a div as
{{ form.as_p }}
that will work for you.
And in the action attribute pass a url in the form of
{% url 'home_page_example' %}
if you wanted to remain in the same page and redirect via view
you can write
action = "."
Show us how did you register your model in the admin.
Make sure that you explicit config the form, like this
class FeedbackAdmin(admin.ModelAdmin)
form = FeedbackModelForm
admin.site.register(Feedback, FeedbackAdmin)
You should return email or message in def __unicode__(self):, not title.
class Feedback(models.Model):
email = models.CharField(max_length=100)
message = models.CharField(max_length=1000)
def __unicode__(self):
return self.email
I think that you should check if the view is currently saving your Feedback.
Try inspecting the DB or in a manage.py shell check if len(Feedback.objects.all()) change when you submit a Feedback in your view.
Also, I recommend you to change the email field to an EmailField and use the FormView class based view.