Django forms creates table rows by itself - python

I'm using django with forms. And on every one of them django add <tr> & <td> before the different inputs.
Example:
forms.py
class LoginForm(forms.Form):
username = forms.CharField(label='username', max_length=50)
password = forms.CharField(label='password', widget=forms.PasswordInput, max_length=100)
views.py:
class Login(View):
def get(self, request):
form = LoginForm()
return render(request, 'login.html', {'form': form})
In the html file i simply import the form via
{{ form | linebreaks }}
But now the given html code looks like this:
<form method="post" action="/">
<input type="hidden" name="csrfmiddlewaretoken" value="*csrftoken*">
<p><tr><th><label for="id_username">username:</label></th><td><input type="text" name="username" maxlength="50" required id="id_username"></td></tr><br><tr><th><label for="id_password">password:</label></th><td><input type="password" name="password" maxlength="100" required id="id_password"></td></tr></p>
<br>
<button class="button" type="submit">Login</button>
</form>
But why does django do this? Can't it simply just use the input tags?

try this :
{{form.as_p|linebreaks}}
instead of :
{{form|linebreaks}}

Related

How to post my html form to django model and save it?

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!

Django Model Form not appearing in admin

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.

django modelformset_factory doesn't include actual forms

I've been trying to follow tutorials and other SO questions and have a modelformset_factory that's displaying a list of what looks like forms in the html, but it turns out they're not actual forms.
html that gets displayed:
<div ='container'>
<div class='row'><tr><th><label for="id_form-0-config_key">Config key:</label></th><td><input id="id_form-0-config_key" maxlength="63" name="form-0-config_key" type="text" value="ClientMustVerify" /></td></tr>
<tr><th><label for="id_form-0-config_value">Config value:</label></th><td><input id="id_form-0-config_value" maxlength="63" name="form-0-config_value" type="text" value="TRUE" /><input id="id_form-0-id" name="form-0-id" type="hidden" value="3" /></td></tr> <input type="submit" value="Update" /></div>
<div class='row'><tr><th><label for="id_form-1-config_key">Config key:</label></th><td><input id="id_form-1-config_key" maxlength="63" name="form-1-config_key" type="text" value="Auditing" /></td></tr>
<tr><th><label for="id_form-1-config_value">Config value:</label></th><td><input id="id_form-1-config_value" maxlength="63" name="form-1-config_value" type="text" value="FALSE" /><input id="id_form-1-id" name="form-1-id" type="hidden" value="4" /></td></tr> <input type="submit" value="Update" /></div>
<div>
notice there is no form tag anywhere. working backwards, here's the excerpt from the template:
<div ='container'>
{% for form in formset %}
<div class='row'>{{form}} <input type="submit" value="Update" /></div>
{% endfor %}
<div>
yes, I added the submit button manually hoping to get these to work, but of course if there isn't a form tag, then the submit button won't do anything.
views.py:
from limbo.models import serverConfig
from django.forms import modelformset_factory
from django.forms import formset_factory
def editServer(request):
result = serverConfig.objects.values()
myConfigs = [entry for entry in result]
finalFormSet = modelformset_factory(serverConfig, exclude=('id',), extra=0)
#other lines
return render(request, 'limboHtml/ServerConfiguration.html', {'formset': finalFormSet, 'SubmitMessage': '', 'CurrentConfigs': myConfigs})
forms.py:
class serverForm(ModelForm):
class Meta:
model = serverConfig
fields = ['config_key', 'config_value']
def __init__(self, *args, **kwargs):
super(serverForm, self).__init__(*args, **kwargs)
instance = getattr(self, 'instance', None)
if instance and instance.pk:
self.fields['config_key'].widget.attrs['readonly'] = True
self.fields['config_key'].widget.attrs['disabled'] = True
and models.py:
class serverConfig(models.Model):
config_key = models.CharField(max_length=63)
config_value = models.CharField(max_length=63)
I tried using finalFormSet = formset_factory(serverForm, extra=0) at one point, but then I just got no content in the html...
As described in the formset documention you must add the form tag manually. This is not very different from what you do when displaying a single form.
It appears that you are iterating through the formset and displayig them one by one. That means you must also add the management form
<form method="post" action="">
{{ formset.management_form }}
<div ='container'>
{% for form in formset %}
<div class='row'>{{form}} <input type="submit" value="Update" /></div>
{% endfor %}
<div>
</form>
Or you will get errors about a missing or misconfigured management form.
Note that it does not include the tags, or a submit button. We’ll have to provide those ourselves in the template.
Read more: Working with Forms: Building a form in Django
The reason you are not getting the <form> tag is because from a logical point of view a form validation can be handled anywhere in your application. That's why you need to specify the form tag explicitly with the target url (good to use reverse(view_name)), method and other parameters.

Django form will not validate

I am working with Django forms and for some reason, this form will not validate! It submits alright, or at least the runserver shows an http post response with code 200 (ok). For some reason though, my form will not pass the is_valid test!
views.py:
def new_show(request):
if request.method == 'POST':
img_form = ImageForm(request.POST, request.FILES)
show_form = NewShowForm(request.POST)
if show_form.is_valid():
new_Show = Show()
new_Show.title=show_form.cleaned_data['title']
new_Show.body=show_form.cleaned_data['body']
new_Show.pub_date=timezone.now()
new_Show.location=show_form.cleaned_data['location']
new_Show.time=show_form.cleaned_data['time']
new_Show.save()
if img_form.is_valid():
image=Image(image=request.FILES['imageFile'])
new_Show.image_set.add(image)
return HttpResponseRedirect(reverse('shows'))
else:
return HttpResponseRedirect(reverse('shows'))
else:
show_form = NewShowForm()
img_form = ImageForm()
return render_to_response(
'shows/new_show.html',
{'show_form': show_form, 'img_form': img_form},
context_instance=RequestContext(request)
)
Here is my template snippet:
<form action="{% url "new_show" %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<p>{{ show_form.non_field_errors }}</p>
<p>
<label for="title">Title:</label>
<input type="text" name="title"/>
</p>
<p>
<label for="body">Body:</label>
<textarea type="text" name="body"> </textarea>
</p>
<p>
<label for="location">Location:</label>
<input type="text" name="location"/>
</p>
<p>
<label for="time">Date:</label>
<input type="text" id="time" maxlength="25" size="25" name="time"><img src="{{ STATIC_URL }}../../static/cal.gif" width="16" height="16" border="0" alt="Pick a date">
</p>
<!-- Upload Form. Note enctype attribute! -->
{% csrf_token %}
<p>{{ img_form.non_field_errors }}</p>
<p>{{ img_form.imageFile.label_tag }}</p>
<p>
{{ img_form.imageFile.errors }}
{{ img_form.imageFile }}
</p>
<p><input type="submit" value="Add Upcoming Show"></input></p>
</form>
Here is my form Class:
class NewShowForm(forms.Form):
title=forms.CharField()
body=forms.CharField(widget=forms.TextArea)
location=forms.CharField()
time=forms.DateTimeField(required=True)
class ImageForm(forms.Form):
imageFile = forms.FileField(required=False, label='Select an Image')
Please help me!
If new_Show is a model, why not create a ModelForm instead of forms.Form?
So, instead of
class NewShowForm(forms.Form):
title=forms.CharField()
body=forms.CharField(widget=forms.TextArea)
location=forms.CharField()
time=forms.DateTimeField(required=True)
class ImageForm(forms.Form):
imageFile = forms.FileField(required=False, label='Select an Image')
why not using,
from django.forms import ModelForm
class NewShowForm(ModelForm):
class Meta:
model = NewShow
class ImageForm(ModelForm):
class Meta:
model = Image
?
Using ModelForm will ensure that form validation meets that of model. Moreover, it can cut off your code (especially line 6 to 11).
It will help to add these two lines to your view before if is_valid() to see the errors it's giving:
if request.method == 'POST':
img_form = ImageForm(request.POST, request.FILES)
show_form = NewShowForm(request.POST)
print(form.is_valid())
print(form.errors)
if show_form.is_valid():
You can paste the errors here and we can see what's the issue
Since you've put 2 Django forms together under one HTML form tag, when you submit the form on the front-end you're sending an extra field through request.POST that your NewShowForm doesn't have. If you combine both forms into a single Django form, you should be able to get this to work.

Django ValidationError for custom model formset with custom fields (data is missing or has been tampered with)

I'm working on a model formset for a Membership model (models auth.User membership to app.Project). Here's app/forms.py, after I trimming things I have confirmed to be irrelevant after commenting them out:
class EditMembership(forms.ModelForm):
delete = forms.BooleanField(required=False, initial=False)
class Meta:
model = models.Membership
fields = ('is_owner',)
def clean_delete(self):
return self.cleaned_data['delete']
class BaseEditMemberships(forms.models.BaseModelFormSet):
# Some custom methods not dealing with validation.
pass
EditMembershipSet = forms.models.modelformset_factory(models.Membership,
form=EditMembership, extra=0, formset=BaseEditMemberships)
Here is my template:
<form method="{{ method|default:"post" }}" action="{{ action }}">
{% csrf_token %}
<ul>
{% for form in formset %}
<li>{{ form.instance.user}}</li>
{{ form.as_ul }}
{% endfor %}
</ul>
<input type="submit" value="{{ submit_value|default:"Submit" }}" />
</form>
And my view:
#ownership_required(message="You must be an owner to edit memberships.")
def edit_memberships(request, pk):
project = get_object_or_404(models.Project, pk=pk)
if request.method == "GET":
formset = forms.EditMembershipSet(
queryset=project.membership_set.all()
)
return render_formset_fullpage(request, formset, "Edit Memberships",
template=forms.EDITMEMBERSHIPS_PATH)
elif request.method == "POST":
formset = forms.EditMembershipSet(request.POST)
return HttpResponse("Hooray!")
And the model in question:
class Membership(models.Model):
class Meta:
unique_together = ('project', 'user')
project = models.ForeignKey('common.Project', editable=False)
user = models.ForeignKey('auth.User')
is_owner = models.BooleanField(default=False, blank=False,
help_text="Indicates ownership of the project")
project_alias = models.CharField(max_length=CHARFIELD_SHORT,
help_text="User-given name", blank=True)
The problem is I keep getting a ValidationError back after doing the POST:
ValidationError at /project/4/memberships
[u'ManagementForm data is missing or has been tampered with']
From what I can tell, forms.EditMembership is doing OK. I can render that form and recreate it from the POST with no validation error, so I guess it is something wrong with the way I am using BaseEditMemberships/EditMembershipSet.
EDIT:
Just to give you even more information, here are an example form which is generated and the POST vars for one of my test requests. The form:
<form method="post" action="">
<div style='display:none'><input type='hidden' name='csrfmiddlewaretoken' value='d6d535efd35e83076e1ac14a82ef4cdc' /></div>
<ul>
<li>someuser</li>
<li><label for="id_form-0-is_owner">Is owner:</label>
<input checked="checked" type="checkbox" name="form-0-is_owner" id="id_form-0-is_owner" />
</li>
<li><label for="id_form-0-delete">Delete:</label>
<input type="checkbox" name="form-0-delete" id="id_form-0-delete" />
<input type="hidden" name="form-0-id" value="8" id="id_form-0-id" />
</li>
</ul>
<input type="submit" value="Submit" />
</form>
Corresponding POST vars if I check the delete box:
form-0-id: u'8'
csrfmiddlewaretoken: u'd6d535efd35e83076e1ac14a82ef4cdc'
form-0-delete: u'on'
form-0-is_owner: u'on'
You need to include {{ formset.management_form }} in your template. See Django's formset documentation on rendering templates for formsets.

Categories