I have a form where I must enter e-mail, but in the template do not have space for input, only after passing the validation window appears with the introduction e-mail.
At this moment I see only send button.
This is my code:
<div class="col-lg-6">
<form action="./" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="send">
</form>
</div>
model.py
class InputEmail(models.Model):
email = models.EmailField()
def __unicode__(self):
return self.email
forms.py
from models import InputEmail
from django import forms
class EmailForm(forms.ModelForm):
class Meta:
model = InputEmail
fields = ('email',)
views.py
class Home(View):
template_name = 'index.html'
def get(self, request):
return render(request, self.template_name)
def post(self, request):
if request.method == 'POST':
form = EmailForm(request.POST)
if form.is_valid():
form.save()
messages.success(request, "You send e-mail to us!")
return HttpResponseRedirect('./')
else:
form = EmailForm()
return render(request, 'index.html', {
'form': form
})
The rest - writing and reading from the database works fine.
How enter the input and give it a style?
well the problem is that the first time you arrive to the view the get method is being called (and it is okay, since this is a GET request).
But, inside that get method you are not sending your form to the template. So it can't be rendered.
instead, your get method should look like that:
def get(self, request):
form = EmailForm()
return render(request, self.template_name, {"form": form})
note that the condition in the post method is redundant. You have an "else" but you never get there since the post method is only called when it is a POST request.
Meaning your post method should look like this:
def post(self, request):
form = EmailForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('./')
return render(request, self.template_name, {
'form': form
})
Related
I’m trying to create a dashboard for the staff users to fill in and edit some information regarding their users. The form works and saves successfully, but when I submit it for a second time, it creates a new object. It won’t replace the previous:
This is my views.py file:
class ScientificInfoView(FormMixin, DetailView):
model = ScientificInfo
template_name = 'reg/scientific-info.html'
form_class = ScientificInfoForm
def get_success_url(self):
return reverse('scientific-info', kwargs={'pk': self.object.pk})
def get_context_date(self, **kwargs):
context = super(ScientificInfoView, self).get_context_data(**kwargs)
context['form'] = ScientificInfoForm()
return context
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
def form_valid(self, form):
form.save()
return super(ScientificInfoView, self).form_valid(form)
And my template:
<form method="POST" enctype="multipart/form-data" action="{% url 'scientific-info' pk=object.id %}">
{% csrf_token %}
{{form}}
<button type="submit">submit</button>
</form>
File urls.py:
path('surveys/scientific/<pk>', login_required(views.ScientificInfoView.as_view()), name='scientific-info')
I’m pretty sure that the action part in my form is causing the issue, but how can I solve it?
Use this:
def get_success_url(self):
pk = self.kwargs["pk"]
return reverse("scientific-info", kwargs={"pk": pk})
Or
class ScientificInfoView(FormMixin, DetailView):
model = ScientificInfo
template_name = 'reg/scientific-info.html'
form_class = ScientificInfoForm
def get_success_url(self):
return reverse("scientific-info", args=[pk]) # You can replace pk
I have a problem with saving a form in my CreateView, I found
this solution and it worked for me:
class ScheduleDocumentView(CreateView):
def post(self, request, pk, *args, **kwargs):
form = ScheduleDocumentForm(request.POST, request.FILES)
if form.is_valid():
form.instance.relates_to = Schedule.objects.get(pk=pk)
form.save()
return redirect('planning:schedule-detail', pk=pk)
However my goal is to save a form using form_valid() and get_success_url() without a template in CreateView. I tried something like this(doesn't work):
class ScheduleDocumentView(CreateView):
model = ScheduleDocument
form_class = ScheduleDocumentForm
def form_valid(self, form):
form.instance.relates_to = Schedule.objects.get(pk=pk)
form.save()
return redirect('planning:schedule-detail', pk=pk)
def get_success_url(self):
return reverse('planning:schedule-detail', kwargs={'pk': pk})
It requires a template, is there any other way to handle my post request in DetailView, process it in separate CreateView and redirect it to my DetailView page?
Here's my template for DetailView:
<form enctype="multipart/form-data" action="{% url 'planning:upload-document' schedule.pk %}" method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="button button--secondary">Attach</button>
Urls:
path('schedules/<int:pk>/', ScheduleDetailView.as_view(), name='schedule-detail'),
path('schedules/<int:pk>/upload-document/', ScheduleDocumentView.as_view(), name='upload-document'),
I came across this solution:
class ScheduleDocumentView(CreateView):
model = ScheduleDocument
form_class = ScheduleDocumentForm
def form_valid(self, form):
form.instance.schedule = Schedule.objects.get(pk=self.kwargs['pk'])
return super().form_valid(form)
def get_success_url(self):
return reverse('planning:schedule-detail', kwargs={'pk': self.kwargs['pk']})
template_name is required Django Docs:
The full name of a template to use as defined by a string. Not
defining a template_name will raise a
django.core.exceptions.ImproperlyConfigured exception.
Or in your case Django would cause the default template_name to be 'yourapp/scheduledocument_create_form.html'.
Therefore you get the error TemplateDoesNotExist.
You can get the pk value from self.kwargs(Django Docs).
You can simple create the blank.html template.
class ScheduleDocumentView(CreateView):
http_method_names = ['post']
template_name = 'blank.html' # or use this 'schedule_detail.html'
model = ScheduleDocument
form_class = ScheduleDocumentForm
def form_valid(self, form):
form.instance.relates_to = Schedule.objects.get(pk=self.kwargs.get("pk"))
return super().form_valid(form)
def get_success_url(self):
return reverse('planning:schedule-detail', kwargs={'pk': self.kwargs.get("pk")})
Or use A simple view:
def create_schedule_document(request, pk):
if request.method == 'POST':
form = ScheduleDocumentForm(request.POST, request.FILES)
if form.is_valid():
obj = form.save(commit=False)
obj.relates_to = Schedule.objects.get(pk=pk)
obj.save()
else:
form = ApplyAnonymousForm()
return redirect('planning:schedule-detail', pk=pk)
I'm new to Django and I'm trying to make a very simple app for my coworkers to submit their tasks on a client and how long took them to fulfill their task.
I can submit to my model through the admin page fine but I can't submit it as a form through the HTML page.
I'm using django-autocomplete-light which is working fine as well.
# This is my forms.py file
class PushTask(ModelForm):
name = CharField()
class Meta(object):
"""docstring for Meta."""
model = ClientModel
fields = ['name', 'reason', 'time_spent']
widgets = {
'name': autocomplete.ModelSelect2(url='name-autocomplete'),
}
# This is a part of my models.py file
class ClientModel(models.Model):
Aa = models.AutoField(primary_key=True, unique=True)
name = models.ForeignKey(Clientele, on_delete=models.CASCADE)
time_spent = models.TimeField(default=None)
dec_name = models.CharField(max_length=100, default=None)
reason = models.ForeignKey(Task, on_delete=models.CASCADE)
date_added = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name.name
# ths is my views.py which I believe is causing the issue
class RecordView(LoginRequiredMixin, View):
template_name = 'manage_records.html'
def get(self, request):
print('I got the form ')
formset = PushTask()
return render(request, self.template_name, {'formset': formset})
def post(self, request):
print('I posted ')
formset = PushTask(request.POST)
if formset.is_valid():
ClientModel(name=name, reason=reason, time_spent=time_spent,
dec_name=request.user)
formset.save()
formset = PushTask()
return HttpResponseRedirect('manage_records.html')
args = {'formset': formset}
return render(request, self.template_name, {'formset': formset})
<!-- this is my html form -->
<form method="POST" id="former">
{% csrf_token %}
{{ formset.as_table }}
</form>
The desired outcome is when the user submits the form, to save everything to my database and clean the form for the user to reuse it.
You construct a ClientModel with:
ClientModel(name=name, reason=reason, time_spent=time_spent,
dec_name=request.user)
But that does not make any sense, since your ModelForm is supposed to do that, and becuase reason, time_spent, etc. are all not defined.
You furthermore seem to redirect to a template name, not the name of a view (or the path of a view).
The above looks a lot like a CreateView [Django-doc], therefore I strongly advice to use such view, and alter behavior you want to change:
from django.urls import reverse_lazy
from django.views.generic.edit import CreateView
class RecordView(LoginRequiredMixin, View):
template_name = 'manage_records.html'
form_class = PushTask
success_url = reverse_lazy('some-view-name')
Here the form will have as name form in your template, not formset, but your form is not a formset [Django-doc] in the first place anyway.
Note: usually forms in django have a Form suffix, to avoid confusion with models. You thus might want to use PushTaskForm over PushTask.
The problem was in my views.py as I suspected. I believe this piece of code
return render(request, self.template_name, {'formset': formset})
run before the form got the chance to check for validation.
The correct code:
# views.py
class RecordView(LoginRequiredMixin, View):
template_name = 'manage_records.html'
username = ''
def get(self, request):
print('I got the form ')
form = PushTask()
return render(request, self.template_name, {'form': form})
def post(self, request):
if request.user.is_authenticated:
print('prepost')
form = PushTask(request.POST)
print('I\'m in post function')
if form.is_valid():
profile = form.save(commit=False)
# profile.ip_address = request.META['REMOTE_ADDR']
profile.dec_name = request.user
profile.save()
return redirect('recorder')
print('Prob Not')
args = {'form': form}
return render(request, self.template_name, {'form': form})
I would gladly accept any other explanation.
I'm creating a home page for my Django webapp, outside of Django admin. I'd like the home page to have a very simple ModelForm that when submitted, writes to the database.
I'm getting the following error at /home/ currently and not sure how to resolve it.
AttributeError at /home/ 'ActionCodeForm' object has no attribute
'is_bound'
I know about bound and unbound forms and have read the docs, but I am not sure how to actually implement them.
Here is my model:
class ActionCode(models.Model):
action_code = models.CharField(blank=False, max_length=10,
verbose_name="Action Code")
Here is my ModelForm:
class ActionCodeForm(ModelForm):
class Meta:
model = ActionCode
fields = ('action_code',)
def __init__(self, *args, **kwargs):
super(ActionCodeForm).__init__(*args, **kwargs)
Here is my view:
def action_code_form(request):
if request.method == 'GET':
form = ActionCodeForm()
else:
form = ActionCodeForm(request.POST)
if form.is_valid():
action_code = form.cleaned_data['action_code']
form.save()
else:
form = ActionCodeForm()
return render('action_code_form.html', {'form': form},
context_instance=RequestContext(request))
And here is my template, action_code_form.html:
<form method="post" action="">
{% csrf_token %}
<table>
{{ form }}
</table>
<input type="submit" value="Submit"/>
</form>
And urls.py:
from home.views import action_code_form
urlpatterns = [
url(r'^home/', action_code_form, name="home"),
]
You need to check if the form is valid only if the method is POST. Also, the first param of render() must be request
Your view should be as follows:
def action_code_form(request):
form = ActionCodeForm()
if request.method == 'POST':
form = ActionCodeForm(request.POST)
if form.is_valid():
action_code = form.cleaned_data['action_code']
form.save()
return render(request, 'action_code_form.html', {'form': form})
If you need to override __init__() in your model form, then you should add self as a second parameter to super() (there is no need to keep the following two lines if you do not have any specific behavior that you want to add to your form):
def __init__(self, *args, **kwargs):
super(ActionCodeForm, self).__init__(*args, **kwargs)
I want to limit a queryset for a form based on the user sending the request. I am having some trouble getting a ModelForm to properly limit the queryset of a field when the form is submitted but invalid. The form gets redisplayed with the error text, but no longer has the queryset limited. What could be the cause here?
models.py
from django.db import models
from django.contrib.auth.models import User
class Patient(models.Model):
name = models.CharField(max_length=100)
doctor = models.ForeignKey(User)
def __unicode__(self):
return self.name
class Prescription(models.Model):
name = models.CharField(max_length=100)
patient = models.ForeignKey(Patient)
views.py
import medical.models as models
import medical.forms as forms
from django.shortcuts import render
def add_form(request):
if request.method == 'POST':
form = forms.PrescriptionForm(request.POST)
if form.is_valid():
form.save()
else:
form = forms.make_prescription_form(request.user)
return render(request, 'add_form.html', {'form': form})
forms.py
import medical.models as models
from django.forms import ModelForm, ModelChoiceField
class PrescriptionForm(ModelForm):
class Meta:
model = models.Prescription
def make_prescription_form(dr):
class PrescriptionForm(ModelForm):
patient = ModelChoiceField(queryset=models.Patient.objects.filter(doctor=dr))
class Meta:
model = models.Prescription
return PrescriptionForm
add_form.html
{{ request.user.first_name }}
{% if form.errors %}
<p style="color: red;">Please correct the error{{ form.errors|pluralize }} below.</p>
{% endif %}
<form action="" method="post">{% csrf_token %}
{{ form }}
<br>
<input type="submit" value="Submit">
</form>
I would greatly appreciate any help with this, or suggestion on a better way to achieve the same thing! Let me know if any more files would be helpful. I'm using Django 1.3.
First off, it looks like you left off a bit - make_prescription_form returns a class, not a form instance, and you're passing the class directly to the rendering in the GET path. I am assuming that's a typo.
You're not using your make_prescription_form wrapper in the POST path. The smallest change from this implementation would be:
def add_form(request):
form_class = forms.make_prescription_form(request.user)
if request.method == 'POST':
form = form_class(request.POST)
if form.is_valid():
form.save()
else:
form = form_class()
return render(request, 'add_form.html', {'form': form})
As for other ways to do this - you can just set the form field's queryset directly in your view.
forms.py
class PrescriptionForm(ModelForm):
class Meta:
model = models.Prescription
views.py
def add_form(request):
if request.method == 'POST':
form = PrescriptionForm(request.POST)
form.fields['patient'].queryset = models.Patient.objects.filter(doctor=request.user)
if form.is_valid():
form.save()
else:
form = PrescriptionForm()
form.fields['patient'].queryset = models.Patient.objects.filter(doctor=request.user)
return render(request, 'add_form.html', {'form': form})
Or set doctor as an argument to PrescriptionForm's __init__ and update the queryset there:
forms.py
class PrescriptionForm(ModelForm):
class Meta:
model = models.Prescription
def __init__(self, *args, doctor=None, **kwargs):
super(PrescriptionForm, self).__init__(*args, **kwargs)
if self.doctor is not None:
self.fields['patient'] = models.Patient.objects.filter(doctor=doctor)
views.py
def add_form(request):
if request.method == 'POST':
form = PrescriptionForm(request.POST, doctor=request.user)
if form.is_valid():
form.save()
else:
form = PrescriptionForm(doctor=request.user)
return render(request, 'add_form.html', {'form': form})