I want previously set dates and times to be displayed before they are edited. The previously set name and description of my event are being displayed as it should. Here's a part of my code:
Forms:
class EventForm(forms.ModelForm):
name = forms.CharField(label='Event name', widget=forms.TextInput(attrs={'class': 'form-control'}))
description = forms.CharField(label='Description', required=False, widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 4, 'cols': 15}))
date_hour_start = forms.DateTimeField(input_formats=['%d/%m/%Y %H:%M'], widget=forms.DateTimeInput(attrs={'type': 'datetime-local', 'class': 'form-control col-md-4'}))
date_hour_end = forms.DateTimeField(input_formats=['%d/%m/%Y %H:%M'], widget=forms.DateTimeInput(attrs={'type': 'datetime-local', 'class': 'form-control col-md-4'}))
Views:
def event_update_view(request, event_id):
event = get_object_or_404(Event, event_id=event_id)
event.date_hour_start = datetime.datetime.strftime(event.date_hour_start, '%d/%m/%Y %H:%M:%S')
event.date_hour_end = datetime.datetime.strftime(event.date_hour_end, '%d/%m/%Y %H:%M:%S')
if request.method == 'POST':
form = EventForm(request.POST, instance=event)
if form.is_valid():
event = form.save()
event.save()
return redirect(reverse('list_events'))
return redirect(reverse('list_events'))
def event_create_view(request):
form = EventForm(request.POST or None)
if form.is_valid():
form.save()
form = EventForm()
return redirect(reverse('list_events'))
context = {
'form': form
}
return render(request, "eventss/add_event.html", context)
HTML (just a part):
<div class="col-md-12">
<p style="margin-bottom: .5rem">Date and Time (Start) <span style="color:red">*</span></p>
{{ form.date_hour_start }}
</div>
<div class="col-md-12">
<p style="margin-bottom: .5rem">Date and Time (End)<span style="color:red">*</span></p>
{{ form.date_hour_end }}
</div>
Why isn't it working? Here's how it's showing. (It's aaaa because it's in Portuguese but it's the year)
To get the instance date and time to show in the datetime-locale input, please change the form input using widgets to the following:
widgets = {
'start_date': forms.DateTimeInput(attrs={'class': 'form-control', 'type': 'datetime-local'}, format='%Y-%m-%dT%H:%M'),
'end_date': forms.DateTimeInput(attrs={'class': 'form-control', 'type': 'datetime-local'}, format='%Y-%m-%dT%H:%M'),
}
Related
I have a model named SaleEntry:
class SaleEntry(models.Model):
date = models.DateField()
ebay_price = models.FloatField()
amazon_price = models.FloatField()
ebay_tax = models.FloatField()
paypal_tax = models.FloatField()
tm_fee = models.FloatField(default=0.3)
promoted = models.FloatField(default=0.0)
profit = models.FloatField()
discount = models.FloatField(default=0)
country = models.CharField(max_length=100, default="-----")
user = models.ForeignKey(User, on_delete=models.CASCADE, default=0)
def save(self, *args, **kwargs):
if not self.pk: # object is being created, thus no primary key field yet
change_balance = Balance.objects.get(user=self.user)
change_balance.balance = change_balance.balance - self.amazon_price - self.tm_fee + self.discount
change_balance.save()
super(SaleEntry, self).save(*args, **kwargs)
def calc_profit(self):
return self.ebay_price - self.amazon_price - self.ebay_tax - self.paypal_tax - self.tm_fee - self.promoted + self.discount
def __str__(self):
return f'{self.user} - {self.profit}'
And I have a form handling this model SaleEntryForm:
class SaleEntryForm(ModelForm):
class Meta:
model = SaleEntry
fields = "__all__"
widgets = {
'date': DateInput(attrs={'class': 'form-control', 'id':'f_date'}),
'ebay_price': forms.NumberInput(attrs={'class': 'form-control', 'placeholder': 'eBay Price', 'id':'f_ebay_price', 'onkeyup': 'calc_profit()'}),
'amazon_price': forms.NumberInput(attrs={'class': 'form-control', 'placeholder': 'Amazon Price', 'id':'f_amazon_price', 'onkeyup': 'calc_profit()'}),
'ebay_tax': forms.NumberInput(attrs={'class': 'form-control col-1', 'placeholder': 'eBay Tax', 'id':'f_ebay_tax', 'onkeyup': 'calc_profit()'}),
'paypal_tax': forms.NumberInput(attrs={'class': 'form-control col-1', 'placeholder': 'Paypal Tax', 'id':'f_paypal_tax', 'onkeyup': 'calc_profit()'}),
'tm_fee': forms.NumberInput(attrs={'class': 'form-control col-1', 'placeholder': 'TM Fee', 'id':'f_tm_fee', 'onkeyup': 'calc_profit()'}),
'promoted': forms.NumberInput(attrs={'class': 'form-control col-1', 'placeholder': 'Promoted', 'id':'f_promoted', 'onkeyup': 'calc_profit()'}),
'profit': forms.NumberInput(attrs={'class': 'form-control', 'placeholder': 'Profit', 'readonly':'true', 'id':'f_profit'}),
'discount': forms.NumberInput(attrs={'class': 'form-control', 'placeholder': 'Discount', 'id':'f_discount'}),
'country': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Country', 'id':'f_country'}),
}
def __init__(self, *args, **kwargs):
'''
relate the sale registration form to the user who created it.
'''
user_id = kwargs.pop('user_id')
super().__init__(*args, **kwargs)
self.fields['user'] = forms.ModelChoiceField(queryset=User.objects.filter(id=user_id), empty_label=None, initial=User.objects.get(id=user_id))
self.fields['user'].widget.attrs['class'] = 'no-display'
I am using this form in the html page:
<form id="form_add_sale">
{% csrf_token %}
<tr>
{% for field in form %}
{% if field is not form.user %}
<td>
{{ field }}
</td>
{% else %}
{{ field }}
{% endif %}
{% endfor %}
<td><input class="btn btn-primary" type="submit" display="inline" name="btn_register_sale"></td>
</tr>
</form>
and this is the ajax to send the data to server:
$(document).on("submit", '#form_add_sale', function(e){
e.preventDefault();
$.ajax({
url:"{% url 'add_sale' %}",
type:"POST",
data:{
date: $("#f_date").val(),
ebay_price: $("#f_ebay_price").val(),
amazon_price: $("#f_amazon_price").val(),
ebay_tax: $("#f_ebay_tax").val(),
paypal_tax: $("#f_paypal_tax").val(),
tm_fee: $("#f_tm_fee").val(),
promoted: $("#f_promoted").val(),
profit: $("#f_profit").val(),
discount: $("#f_discount").val(),
country: $("#f_country").val(),
},
success: function(){
alert("Created new sale!");
}
})
//.done(function(response){
// $("#table_sales").load(location.href + " #table_sales");
//})
.fail(function(xhr, status, error){
var err = eval("(" + xhr.responseText + ")");
alert(err.Message);
})
})
upon submitting the form, I'm getting the next error (which didn't occur when submitting the form regularly without ajax with the exact same code in the view):
<ul class="errorlist"><li>user<ul class="errorlist"><li>This field is required.</li></ul></li></ul>
this is the request.POST:
<QueryDict: {'date': ['2021-02-11'], 'ebay_price': ['70'], 'amazon_price': ['50'], 'ebay_tax': ['10'], 'paypal_tax': ['5'], 'tm_fee': ['0.3'], 'promoted': ['0.0'], 'profit': ['4.70'], 'discount': ['0'], 'country': ['-----']}>
I think you forgot the csrf_token. try adding:
csrfmiddlewaretoken:$('input[name=csrfmiddlewaretoken]').val()
to the data.
More information can be found here
I have a form, ApplyJobForm and a Formset, ApplyJobFormset. GET method works when I pass the form and the formset to a view, but for the post request the form and the formset is_valid() isn't working, after clicking submit it returns me to a view without saving. I am unable to save the form with the formset, I don't know what I'm doing wrong here.
Here are my codes.
models.py
class Applicants(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
job = models.ForeignKey(Job, on_delete=models.CASCADE, related_name='applicants')
experience = models.IntegerField(blank=True, null=True)
cv = models.FileField(upload_to=user_directory_path)
degree = models.CharField(choices=DEGREE_TYPE, blank=True, max_length=10)
created_at = models.DateTimeField(default=timezone.now)
def __str__(self):
return f'{self.user.get_full_name()} Applied'
class Certification(models.Model):
applicant = models.ForeignKey(Applicants, on_delete=models.CASCADE, related_name='applicant_certifications')
name = models.CharField(max_length=50)
certification = models.FileField(upload_to=user_directory_path, blank=True)
def __str__(self):
return f'{self.user.get_full_name()} certificate'
forms.py
class ApplyJobForm(forms.ModelForm):
class Meta:
model = Applicants
fields = ('job', 'degree', 'experience', 'cv')
exclude = ('job',)
labels = {
'degree': 'Degree',
'experience': 'Experience',
'cv': 'CV',
}
widgets = {
'degree': forms.Select(attrs={
'class': 'form-control',
}
),
'experience': forms.NumberInput(
attrs={
'class': 'form-control',
}
),
'cv': forms.FileInput(
attrs={
'class': 'form-control',
}
),
}
ApplyFormset = modelformset_factory(
Certification,
fields=('name', 'certification'),
extra=1,
widgets={
'name': forms.TextInput(
attrs={
'class': 'form-control',
'placeholder': 'Certification name'
}
),
'certification': forms.FileInput(
attrs={
'class': 'form-control',
'placeholder': 'Upload certification'
}
)
}
)
views.py
def job_apply(request, job_id=None):
template_name = 'apply_form.html'
applyform = ApplyJobForm(request.GET or None)
job = get_object_or_404(Job, id=job_id)
formset = ApplyFormset(queryset=Certification.objects.none())
if request.method == 'GET':
context = {'applyform': applyform, 'formset': formset}
return render(request, template_name, context)
elif request.method == 'POST':
applyform = ApplyJobForm(request.POST)
formset = ApplyFormset(request.POST)
if applyform.is_valid() and formset.is_valid():
apply = applyform.save(commit=False)
applyform.job = job
apply.save()
for form in formset:
# so that `apply` instance can be attached.
certification = form.save(commit=False)
certification.apply = apply
certification.save()
return redirect('successful-apply')
else:
return redirect('job-detail', id=job.id)
return render(request, template_name, {'applyform': applyform, 'formset': formset})
Here an applicant can add as many certification field when applying for a job, although the certification field is not a required field. Certification model is bound to the Applicants model.
.html
<form class="form" method="POST" action="" enctype="multipart/form-data" role="form" autocomplete="off">
.................
</form>
First of all, never redirect if your forms are not valid. You want to render your template with the invalid form so that you can display the errors to the user. This also helps debugging since you'll see the errors.
So in your view, remove these two lines:
else:
return redirect('job-detail', id=job.id)
so that the invalid case renders the forms in your template.
Next, since you have files to upload, you need to initialise forms that require files with request.FILES:
formset = ApplyFormset(request.POST, request.FILES)
(and the same for applyform).
Finally make sure that in your template you are also displaying all the errors, either on each field ({{ form.<field>.errors }}) or globally ({{ form.errors }}).
I'm using Django. I need a form that shows the 3 fields of a class that I have created, the idea is that every time you want to add a new day and time to start and end, show a new new section, so that each teacher can be found in more of a day and time of beginning and end (the three fields go together)
I still do not logo to make it work, if someone has any idea they would be grateful.
Models.py
class Profesor(Person):
legajo = models.IntegerField(blank=True, null=True)
type = models.CharField(max_length=30)
matter = models.CharField(max_length=100, blank=True, null=True)
calendar = models.ForeignKey('calendar', on_delete=models.DO_NOTHING)
user = models.CharField(max_length=20, blank=True, null=True)
class calendar(models.Model):
day = models.DateTimeField(default=date.today().isoweekday())
hs_init = models.DateTimeField(default=datetime.now().hour)
hs_end = models.DateTimeField(default=datetime.now().hour)
Forms.py
class addProfesorForm(ModelForm):
calendar = forms.ModelChoiceField(queryset=calendar.objects.all(), widget=forms.HiddenInput())
class Meta:
model = Profesor
TYPES = (
('Motiv', 'Motiv'),
('Academic', 'Académic'),
('Otro', 'Otro')
)
help_texts = {
'matter': 'message'
}
fields = ['id', 'type', 'matter']
widgets = {
'type': Select2Widget(choices=typeS)
}
class calendarForm(ModelForm):
class Meta:
model = calendar
fields = ['day','hs_init','hs_end']
Views.py
def agregarTutor(request):
if request.method == 'POST':
form = addProfesorForm(request.POST['calendar'])
calendar=calendar.objects.all()[0]
if form.is_valid():
id = form.cleaned_data['id']
try:
person_Sysatem = SysatemPerson.objects.get(pk=id)
alumn_Sysatem = SysatemAlumn.objects.get(pk=id)
except SysatemPerson.DoesNotExist:
return render(request, 'menu/new-Profesor.html',
{'new_manual': True, 'not_found': True, 'nbar': 'profesors', 'id': id})
new_Profesor = Profesor(
nombre=person_Sysatem.nombre.rstrip(),
id=person_Sysatem.numerodocu,
legajo=alumn_Sysatem.legajo,
telefono=person_Sysatem.telefono.rstrip(),
mail=person_Sysatem.mail.rstrip(),
type=form.cleaned_data['type'],
calendar=form.cleaned_data['calendar'],
matter=form.cleaned_data['matter'],
user=id,
)
Profesor.save(new_Profesor)
contrasena = 'id'+str(id)[0:5]
user = User.objects.create_user(id, person_Sysatem.mail.rstrip(), contrasena)
user.first_name = person_Sysatem.nombre.rstrip()
user.save()
form = addProfesorForm(initial={'calendar':calendar})
return render(request, 'menu/new-Profesor.html', {'form': form, 'Profesor': new_Profesor, 'success': True, 'nbar': 'profesors'})
else:
return render(request, 'menu/new-Profesor.html', {'form': form, 'error_form': True, 'nbar': 'profesors'})
else:
form = addProfesorForm()
return render(request, 'menu/new-Profesor.html', {'form': form, 'nbar': 'profesors'})
Template.html
<h2>new Profesor</h2>
<div class="row">
<div class="col">
<form method="post">{% csrf_token %}
{% include 'common/form_template.html' with form=form %}
<button type="submit" style="margin-top: 10px; float: right;" class="btn btn-primary">Add</button>
</form>
</div>
</div>
When I upload a photo to django through form the image field is empty. I confirmed this by using logging.info(form.cleaned_data['picture'] )
I checked through the console that the form has 'multipart/form-data'
The model :
class Person(models.Model):
user = models.ForeignKey(User, default=1)
name = models.CharField(max_length=250,null=True)
last_name = models.CharField(max_length=500)
treatment_plan=models.CharField(max_length=256,null=True,blank=True)
treatment_done=models.CharField(max_length=256,null=True,blank=True)
picture = models.ImageField(upload_to='image', storage=DEFAULT_FILE_STORAGE,blank=True)
def __str__(self):
return self.name
the modelForm :
class PersonForm(forms.ModelForm):
class Meta:
model = Person
fields = ['name', 'last_name', 'age', 'martial_status', 'mobile', 'sex',
'amount_paid','amount_left','note', 'address','date','picture','treatment_done','treatment_plan','chief_complain']
widgets = {
'name': forms.TextInput(attrs={'required': True, 'class': 'form-control',
'placeholder': 'name'}),
'last_name': forms.TextInput(attrs={'required': True, 'class': 'form-control',
'picture': forms.FileInput(attrs={'required': False,'class': 'form-control','enctype': 'multipart/form-data'}),
view.py :
def add_person(request):
if not request.user.is_authenticated():
return render(request, 'core/login.html')
else:
form = PersonForm(request.POST or None,request.FILES or None,instance=Person())
#form = PersonForm(request.POST or None,request.FILES )
if form.is_valid():
persons = form.save()
persons.user = request.user
#to capitalized the first letter so we have consistency when querying , this is a workaround since __iexact is not working
persons.name=persons.name.title()
persons.last_name=persons.last_name.title()
logging.info(form.cleaned_data['last_name'] )
persons.save()
return redirect('home')
context = {
"form": form,
}
return render(request, 'core/add_person.html', context)
The html template :
<div class="col-sm-4 form-group">
<label for="address">{% trans "Address" %}</label>
{{ form.address|add_class:"form-control" }}
</div>
<div class="col-sm-4 form-group">
<label for="pic">{% trans "Picture" %}</label>
{{form.picture}}
</div>
I may be wrong, but still, as far as I know the parameter "multipart/form-data" should be in the form, and not in input, and you install it to the FieldFile
'picture': forms.FileInput(attrs={'required': False,'class': 'form-control','enctype': 'multipart/form-data'}),
I have two forms:
class Form_registration_security (ModelForm):
class Meta:
model = Security
fields = ['fk_id_users_security', 'e_mail', 'password']
widgets = {
'e_mail': forms.TextInput(attrs = {'placeholder': 'Your Email'}),
'password': forms.TextInput(attrs = {'placeholder': 'New Password'}),
}
class Form_registration_user (ModelForm):
class Meta:
model = Users
fields = ['id', 'first_name', 'last_name', 'date_birthdaty']
widgets = {
'id': forms.TextInput(attrs = {'placeholder': 'id'}),
'first_name': forms.TextInput(attrs = {'placeholder': 'First Name'}),
'last_name': forms.TextInput(attrs = {'placeholder': 'Last Name'}),
'date_birthdaty': forms.TextInput(attrs = {'placeholder': 'Date'})
}
But data saves only in one mode - (Form_registration_user).
Code in view:
def save_registration (request ):
if request.method == 'POST':
form_user = Form_registration_user(request.POST)
form_security = Form_registration_security(request.POST)
if form_user.is_valid() and form_security.is_valid():
data_user = form_user.save()
data_security = form_security.save(commit=False)
data_security.data_user = data_user
data_security.save()
return render_to_response('see_you_later.html')
else:
return render_to_response('error.html')
I'm always see - error.html, although I'm fill right form.
Model User have a primary key.
Model Security have a foreign key.
My template:
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<div class="entry_or_register">
{% load staticfiles %}
<img src="{% static "tumblr.gif" %}" width="1250" height="550">
<form name="registration" method="post" action="save/">
{% csrf_token %}
{{ form_registration_user.as_p }}
{{ form_registration_security.as_p }}
<input type="submit" value="SignUp">
</form>
</div>
</body>
</html>
Thanks for help! Right function:
def save_registration (request ):
if request.method == 'POST':
form_user = Form_registration_user(request.POST)
form_security = Form_registration_security(request.POST, request.FILES)
if form_user.is_valid():
data_user = form_user.save()
data_security = form_security.save(commit=False)
data_security.data_user = data_user
data_security.save()
return render_to_response('see_you_later.html')
else:
return render_to_response('error.html')
You should post also the html markup of the corresponding template.
Anyway, here's a view i used once i had to save data from two ModelForms in the same page, with the user clicking a single submit button:
def register(request):
message = None
if request.method == 'POST':
user_form = NewUserForm(request.POST)
details_form = UserDetailsForm(request.POST, request.FILES)
if user_form.is_valid():
new_simple_user = user_form.save()
message = _("User inserted")
if details_form.is_valid():
# Create, but don't save the new user details instance.
new_user_details = details_form.save(commit=False)
# Associate the user to the user details
new_user_details.user = new_simple_user
# save a new user details instance
new_user_details.save()
message = _("User details inserted")
else:
user_form = NewUserForm()
details_form = UserDetailsForm()
return render_to_response('register.html', { 'user_form': user_form, 'details_form': details_form, 'message': message,},\
context_instance=RequestContext(request))
I'm not sure how you rendered your forms in the template, but it could be that when you click submit, only one of the forms sends its data in the HTTP request.
Then the other form's constructor won't find its key in the POST variable and the outcome won't be a valid form. I think that's why you test always fail.
Now, I hope you could give us some more details on what you're trying to do but I think you are going to need a custom Form class (that would be the union of your two current forms) instead of a ModelForm.
EDIT : sorry, you shouldn't actually need to do that...
Good luck.