Ive tried to submit a model class using a view function but the form didn't submitted.
This The model class inside models.py file :
class Campaign(models.Model):
username = models.OneToOneField(User, unique=True)
title = models.CharField(max_length=200)
message = models.TextField()
link = models.CharField(max_length=200)
added= models.DateTimeField(auto_now_add=True)
and this its form inside forms.py :
class CampaignForm(forms.ModelForm):
class Meta:
model = Campaign
fields=('title','message')
Ive tried to submit this form using this function at views.py :
def Campaign(request):
form = CampaignForm(request.POST or None)
if request.method == 'POST':
if form.is_valid():
submit= Campaign(username=request.user)
submit.save()
context={
'form':form,
}
return render(request, 'campaigns.html',context)
And this is the html file :
{% extends "base.html" %}
{% block content %}
<form action="" method="POST" class="">
{% csrf_token %}
{{form.as_p}}
<input type="submit">
</form>
{% endblock content %}
You have to do action="#" in your form html because some browsers can not accept empty action values.
Also you have a mistake in this part of code:
submit= Campaign(username=request.user)
submit.save()
You have to get the form values into your object, you can do it this way:
submit = form.save(commit=False)
submit.username = request.user
submit.save()
Some browsers will fail to post if the action attribute is empty, try with
<form action="." method="POST">
Notice the dot ".", since you are using the same view to display the form and process it the dot it's ok.
Related
I am trying to create a user profiles for users in my Django app. I have the form displaying where I want it to and when I try to submit, nothing happens.
I put a print statement after the form.is_valid in my view.py and found that it wasn't 'valid' but I have no idea why.
I have tried several different ways to 'clean' / 'validate' data but I can't get past the form being 'invalid.'
Any help would be greatly appreciated!
urls:
path('userinfo/', views.user_info, name='userinfo')
form template:
{% extends "base.html" %}
{% load bootstrap4 %}
{% block content %}
<div class="container">
<h1>Enter User Info</h1>
<form method="POST" class="form">
{% csrf_token %}
{% bootstrap_form form %}
<input type="submit" class="btn btn-primary" value="Create Profile">
</form>
</div>
{% endblock %}
view:
def user_info(request):
form = ProfileForm()
if request.method == 'POST':
form = ProfileForm(request.POST)
if form.is_valid():
form.save()
else:
form = ProfileForm()
return render(request, 'miraDashboard/form.html', context={'form': form})
model:
from django.db import models
from django.contrib.auth.models import User
class Profile(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE)
name = models.CharField("Full Name", max_length=1024)
job_role = models.CharField("Role", max_length=254, default="Seeking Job Opportunities")
zip_code = models.CharField("Zip Code", max_length=5)
user_image = models.ImageField("Upload Profile Picture", upload_to='images/')
def __str__(self):
return f'{self.user.username} Profile'
form:
from django.forms import ModelForm
from .models import Profile
class ProfileForm(ModelForm):
class Meta:
model = Profile
fields = ['name','job_role','zip_code', 'user_image']
if you want to see errors in form change else statmant:
def user_info(request):
form = ProfileForm()
if request.method == 'POST':
form = ProfileForm(request.POST)
if form.is_valid():
form.save()
else:
print(form.errors.as_data()) # here you print errors to terminal
return render(request, 'miraDashboard/form.html', context={'form': form})
after form.is_valid() you don't need to set it again (form = ProfileForm() in else statment). this way your form will get errors( you cen see them in form.errors).
I want to update user info with UserChangeForm and things go pretty well except for the ManyToManyField. When I render the page I can see that all user informations are displayed in correct order of each field like user's username will be in the username field but it's blank in manytomanyfield.
#model.py
class Department(models.Model):
name = models.CharField(max_length=100)
class CustomUser(AbstractUser):
username = None
email = models.EmailField(_('Email Address'), unique=True)
department = models.ManyToManyField(Department)
# some other fields
# forms.py
class EditUserForm(UserChangeForm):
class Meta:
model = CustomUser
fields = ['email', 'department', ..]
widgets = {'department': forms.CheckboxSelectMultiple()}
# view.py
def home(request):
template_name = "app/home.html"
edit_form = EditUserForm(instance=request.user)
if request.method == "POST":
edit_form = EditUserForm(request.POST, instance=request.user)
if edit_form.is_valid():
edit_form.save()
return JsonResponse({'success': True}, status=200)
else:
return JsonResponse({'error': edit_form.errors}, status=400)
return render(request, template_name, {'edit_form': edit_form})
# template
<form action="{% url 'home' %}" method="POST">
<div class="row">
{{edit_form.email}}
{{edit_form.first_name}}
{% for department in edit_form.department %}
<h6 id="checkbox">{{department.tag}} {{department.choice_label}}</h6>
{% endfor %}
</div>
</form>
here is the picture
As you can see the names and email are displaying inside the form field but why all checkboxes are empty? (Checkbox fields are department)
If you just want to render the field you don't need a for loop. You can just use {{edit_form.department}}. In case you need to modify each input field in CheckboxSelectMultiple you should loop through edit_form.department.field.choices.
For example:
{% for choice, value in edit_form.department.field.choices %}
<input type="checkbox" name="{{choice.instance.value}}" value="{{choice.instance.pk}}" id="id_{{choice.instance.value}}">
{% endfor %}
Note that this will work only in django 3.0 and newer.
you need pass the value and the name in the input in your template
{% for value, name in edit_form.fields.department.choices %}
<input type="checkbox" name="{{name}}" value="{{value}}" id="{{name}}">
{% endfor %}
I am creating a form using ModelForm to let the users upload a file along with a description . The is_valid() function isn't returning true and I am really confused. I have searched and there are many questions with same title as mine but they don't solve my problem.
here is forms.py:
class PostForm(forms.ModelForm):
document = forms.FileField(widget=forms.FileInput)
class Meta:
model = FeedModel
fields = ['description', 'document']
Here is models.py:
class FeedModel(models.Model):
description = models.CharField(max_length=255, blank=True)
document = models.FileField()
like = models.IntegerField(default=0)
dateTime = models.DateTimeField(auto_now=True, auto_created=True)
user = models.ForeignKey(User, on_delete=models.CASCADE, default=0)
def get_absolute_url(self):
u=self.user
return reverse('home:feed',u.primary_key)
Here is views.py:
class PostView(CreateView):
form_class = PostForm
template_name = 'home/feedModel_form.html'
def get(self, request, *args, **kwargs):
form=self.form_class(None)
return render(request, self.template_name, {'form':form })
def post(self, request, *args, **kwargs):
logger = logging.getLogger(__name__)
form=self.form_class(request.POST)
if form.is_valid():
user=request.user
self.object=form.save(commit=False)
self.object.user=user
self.object.save()
logger.error("voila")
redirect({'home:feed'}, user.id)
return render(request, self.template_name, {'form':form })
def feedview(request, user_id):
user = User.objects.get(pk=user_id)
return render(request, 'home/feed.html', {'user': user})
Here is feedModel_form.html:
{% extends 'home/navbar.html' %}
{% block body %}
<div class="form">
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
{% include 'home/form.html' %}
<button type="submit" class="button button-block" `
name="reg_btn">Post</button>`
</form>
</div>
{% endblock %}
Here is form.html:
{% for field in form %}
<div class="field-wrap">
<label>
{{ field.label_tag }}<span class="req">*</span>
</label>
<div>{{ field }}</div>
</div>
{% endfor %}
To see why the form isn't valid, you should check form.errors.
One error will be because you have not passed request.FILES to the form.
form=self.form_class(request.POST, request.FILES)
There may be other errors as well. If you used {{ form }} in your template, Django would include the errors automatically. Since you are rendering the fields manually, it's up to you to include the errors.
The key problem here is that you have overridden post. That means that you're missing out on lots of the code from CreateView.
In your case, it looks like you could remove the post method, and simply override form_valid instead.
def form_valid(self, form):
self.object=form.save(commit=False)
self.object.user=user
self.object.save()
# Note that you had {'home:feed'} here which was incorrect
return redirect('home:feed', user_id)
Your document field expects an uploaded file and is required. In order for the form to actually get the file, you have to also pass it the uploaded file in views.py:
form = self.form_class(data=request.POST, files=request.FILES)
I need form where user can create article with several images. I use django-multiupload app for image field. I can select several images but when I try to submit the form I have message under the image field: "Field is empty and field is required". Where is my mistake? Why I have such message when image field is not empty?
Also maybe someone can advice good examples or apps to save several images. I would be very grateful for any help.
models.py:
class Article(models.Model):
description = models.TextField(_('Description'))
class Image(models.Model):
article= models.ForeignKey(Article, on_delete=models.CASCADE)
image = models.FileField(_('Image'), upload_to='images/%Y/%m/%d/')
forms.py:
class ArticleForm(forms.ModelForm):
class Meta:
model = Article
fields = ('description', )
image = MultiFileField()
def save(self, commit=True):
instance = super(ArticleForm, self).save(commit)
for each in self.cleaned_data['image']:
Image.objects.create(image=each, article=instance)
return instance
views.py:
def article_add(request):
data = dict()
if request.method == 'POST':
article_form = ArticleForm(request.POST, request.FILES)
if article_form.is_valid():
article = article_form.save(commit=False)
******
article.save()
data['form_is_valid'] = True
articles = Article.objects.all
context = {'articles': articles}
context.update(csrf(request))
data['html_article'] = render_to_string('project/article_list.html', context)
else:
data['form_is_valid'] = False
else:
article_form = ArticleForm()
context = {'article_form': article_form}
data['html_article_form'] = render_to_string('project/article_add.html', context, request=request)
return JsonResponse(data)
article_add.html:
{% load widget_tweaks %}
<form method="post" action="{% url 'article_add' %}" class="article-add-form">
{% csrf_token %}
{% for field in article_form %}
<div class="form-group{% if field.errors %} has-danger{% endif %}">
<label class="form-control-label" for="{{ field.id_for_label }}">{{ field.label }}</label>
{% render_field field class="form-control" %}
{% for error in field.errors %}
<div class="form-control-feedback">{{ error }}</div>
{% endfor %}
</div>
{% endfor %}
<button type="submit">Submit</button>
</form>
Try adding "min_num" constraint on the image field,
image = MultiMediaField(min_num=1, media_type='image')
EDIT
def article_add(request):
if request.method == 'POST':
article_form = ArticleForm(request.POST, request.FILES)
if article_form.is_valid():
article = article_form.save(commit=False)
******
article.save()
#assume you have already a view in the name 'article_list'.
return redirect('article_list')
else:
article_form = ArticleForm()
context = dict(article_form=article_form)
return render(request, 'project/article_add.html', context)
The problem maybe because you were trying to render two templates in a single view, also when using django template rendering render is a shortcut function, which is mostly preferred to use, rather than string converting and parsing into json.
Also, 'article_list' must be another view, which shows the list of all the articles, after adding a new article, you should consider redirecting to the list view. Here you were trying to render multiple templates, in a single view. You could make of something like this in your list view,
def article_list(request):
articles = Article.objects.all()
context = dict(articles=articles)
return render(request, 'project/article_list.html', context)
Although, these are my personal opinion regarding the code you just shared. Try this approach...
I have created my first app in Django (1.10.5) / Python 3.4. I have a login page and a register page. Which is working fine.
I can create new user and login with that id. Now after the login I want user to fill a form with some information and click on submit. And the information should get stored in the database.
So I created a model first : Model.py
class UserInformation(models.Model):
firstName = models.CharField(max_length=128)
lastName = models.CharField(max_length=128)
institution = models.CharField(max_length=128)
institutionNumber = models.CharField(max_length=128)
cstaPI = models.CharField(max_length=128)
orchidNumber = models.CharField(max_length=128)
This has created a table in the DB.
forms.py
class UserInformationForm(ModelForm):
class Meta:
model = UserInformation
fields = '__all__'
views.py
def home(request):
form = UserInformationForm()
variables = { 'form': form, 'user': request.user }
return render(request,'home.html',variables)
home.html
{% extends "base.html" %}
{% block title %}Welcome to Django{% endblock %}
{% block head %}Welcome to Django{% endblock %}
{% block content %}
<p> Welcome {{ user.username }} !!! Logout<br /><br /> </p>
<form method="post" action=".">{% csrf_token %}
<table border="0">
{{ form.as_table }}
</table>
<input type="submit" value="Submit" style="position:absolute"/>
</form>
{% endblock %}
But when I click on submit button, It does not insert data into my table.
here is the answer, we need to use the request.POST
def home(request):
if request.method == 'POST':
form = UserInformationForm(request.POST)
form.save()
return HttpResponseRedirect('/home/')
else:
form = UserInformationForm()
variables = { 'form': form, 'user': request.user }
return render(request,'home.html',variables)
the first: you need add urls.py to you app
the second: you need to change your views.py to lool like this
`
info = UserInformation()
lastName = request.POST.get('lastName')
...
info.save()
`