I have an inlineformset_factory containing a field. When this field is a CharField (blank=False) and I run is_valid() on the formset, True is always returned even though the CharField is left blank. When I replace the CharField with a DateField (default=timezone.now(), blank=False), is_valid() will return True only when the field is filled as expected. Why is the CharField always returning True when running is_valid() on the formset but the DateField does not? Note that I want the CharField to behave like the DateField.
Interestingly enough, the formset behaves as expected when both the CharField and DateField are present.
Code below is shown with title and date but I have tried with only title and only date as described above. Any help is appreciated. This is driving me up the wall!
models.py
class Author(models.Model):
author = models.CharField(max_length=128)
description = models.CharField(max_length=1000)
class Book(models.Model):
author = models.ForeignKey(Author, on_delete=models.CASCADE)
title = models.CharField(max_length=100)
date = models.DateField(default=timezone.now(), blank=False)
forms.py
class AuthorForm(forms.ModelForm):
class Meta:
model = Author
fields = ('author', 'description')
class BookForm(forms.ModelForm):
class Meta:
model = Book
fields = ('title', 'date')
BookFormSet = forms.inlineformset_factory(
Author,
Book,
form=BookForm,
fields=('title', 'date'),
extra=1,
can_delete=False,
can_order=False
)
views.py
class CreateAuthorView(CreateView):
template_name = "author_create.html"
model = Author
form_class = AuthorForm
def get_context_data(self, **kwargs):
context = super(CreateAuthorView, self).get_context_data(**kwargs)
if self.request.POST:
form = self.get_form(self.form_class)
context["book"] = BookFormSet(self.request.POST, instance=form.instance)
else:
context["book"] = BookFormSet()
return context
def form_valid(self, form):
context = self.get_context_data()
book = context["book"]
print(form.data.get("author"))
print("book.is_valid()", book.is_valid()) # ***This always prints True when only CharField is part of Book model***
return redirect(self.get_success_url())
def get_success_url(self):
return reverse("author_list")
author_create.html
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<div>
{{ form }}
</div>
<div>
{{ book.management_form }}
{% for book_form in book %}
<div>
{{ book_form }}
</div>
{% endfor %}
</div>
<button type="submit">Submit Author</button>
</form>
When dealing with formsets, completely empty forms are not validated unless the minimum/maximum number is set in the formset definition itself.
Related
models.py
here is my model
class Load_post(models.Model):
user = models.ForeignKey(get_user_model(),on_delete=models.CASCADE)
pick_up_station = models.CharField(max_length=150)
destination_station = models.CharField(max_length=150)
sender_name = models.CharField(max_length=150)
phone_number = PhoneNumberField(null=False , blank=False , unique=True)
receiver_name = models.CharField(max_length=150)
sending_item = models.CharField(max_length=150)
weight = models.CharField(max_length=150)
metric_unit = models.CharField(max_length=30, default='SOME STRING')
quantity = models.PositiveIntegerField(default=1)
requested_shiiping_price = models.PositiveIntegerField()
pick_up_time = models.DateField()
drop_time = models.DateField()
paid_by = models.CharField(max_length=150)
created_at = models.DateTimeField(auto_now=True)
published_date = models.DateField(blank=True, null=True)
def __str__(self):
return self.user.username
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
def publish(self):
self.published_date = timezone.now()
self.save()
def get_absolute_url(self):
return reverse('local')
class Meta:
ordering = ["-created_at"]
unique_together = ["sender_name", "receiver_name"]
please check the phone number
forms.py
this is form.py
class Loader_post_form(forms.ModelForm):
phone_number = PhoneNumberField()
metric_unit = forms.ChoiceField(choices=UNIT, required=True)
class Meta:
model = Load_post
fields = ("pick_up_station", "destination_station",
"sender_name", "phone_number", "receiver_name",
"sending_item","image_of_load","weight","metric_unit",
"quantity","requested_shiiping_price","pick_up_time",
"drop_time","paid_by")
views.py
This is my views.py
absolute URL used in models already
class Loader_post_view(CreateView, LoginRequiredMixin):
login_url = 'Driver/login/'
form_class = forms.Loader_post_form
model = Loader_Signup
template_name = "Driver/post.html"
def form_valid(self,form):
form.instance.user = self.request.user
form.save()
return super(Loader_post_view,self).form_valid(form)
post.html
this is html page (template)
{% extends "Driver/base.html" %}
{% block content %}
<h1>create a post</h1>
{% csrf_token %}
{{form}}
<button type="submit">submit</button>
{% endblock content %}
this is html code
how to add it to the database
and I cannot see any error in my forms
thank you
am working on driver and client-side project
From what I see you html template cannot submit the form because you ae missing the <form> tags - if you do not have them hidden in your base.html.
Your html template should be something like this:
{% extends "Driver/base.html" %}
{% block content %}
<h1>create a post</h1>
<form method="POST">
{% csrf_token %}
{{form}}
<button type="submit">submit</button>
</form>
{% endblock content %}
The {{ form }} renders the form with all the inputs but does not create the tags needed for html forms.
In addition there are some other errors in the code you posted.
In your view the model you defined is called Loader_Signup, however the model you posted is Load_post. Either you posted the wrong model or you declared the wrong model in your view.
In your form one field is called image_of_load, however, this field is not part of you model.
In your model you have got a field called phone_number, you are defining a field with the same name in your form. The field in your form has got no connection to your model so take it out.
Unfortunately you are not providing any details about your PhoneNumberField so this cannot be checked.
I'm working with Django and what I want to do is to have a DetailView of Posts, and inside that detail view I want a comments section with a form for posts comments. When I load the detail view it doesn't show me the form of Comments I'm using Class Based Views for the Detail of the form.
My models.py looks like this:
class Post(models.Model):
author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
title = models.CharField(max_length = 200)
text = models.TextField()
created_date = models.DateTimeField(default = timezone.now)
likes = models.IntegerField(default=0)
tags = models.CharField(max_length = 50, default = '' )
def get_absolute_url(self):
return reverse('blog:post_list')
def __str__(self):
return self.title
class Comments(models.Model):
post = models.ForeignKey('blog.Post', related_name='comments', on_delete=models.CASCADE)
text = models.TextField()
created_date = models.DateTimeField(default = timezone.now)
The views.py looks like this:
class PostDetailView(DetailView):
form_class = CommentsForm
model = Post
The form looks like this:
class CommentsForm(forms.ModelForm):
class Meta:
model = Comments
fields = ('text',)
widgets = {
'text' : forms.Textarea(attrs={'class':'comment-textarea'})
}
And the comments_form.html looks like this:
<div class="container">
<div class="row">
<div class="col">
<h1>Estoy siendo insertado</h1>
<form action="" method="POST">
{%csrf_token%}
{{ form.as_p }}
<input type="submit" class="btn mt-2 btn-comments" value="Comment">
</form>
</div>
</div>
</div>
That's because DetailView does not handle the form_class. You have a few options here:
provide the form via get_context_data
apply the FormMixin on the DetailView. (Can be found under django.view.generic.edit)
Context data example:
def get_context_data(self, **kwargs):
context = super(PostDetailView, self).get_context_data(**kwargs)
context['comments_form'] = CommentsForm()
return context
I am trying to display the data in details template that I would obtain using AgentForm and I am also trying to add a Matrix1Form that will be unique to each agent, and that matrix1form would be displayed in details.html.
Here is my views.py and if I try to display the Matrix1Form, the data from Agent model doesn't get displayed and vice versa, if I want to display an agent, I have to comment out the Matrix1Form. There are no errors popping up so far. The data just don't get displayed.
views.py
class AgentDetailsView(generic.DetailView):
template_name = 'User/AgentDetails.html'
class Meta:
model = Agent
def get(self, request, *args, **kwargs):
matrix1form = Matrix1Form()
return render(request, self.template_name, {'matrix1form':
matrix1form})
forms.py
class AgentForm(forms.ModelForm):
prefix = 'agentform'
class Meta:
model = Agent
fields = '__all__'
class Matrix1Form(forms.ModelForm):
prefix = 'matrix1form'
class Meta:
model = Matrix1
fields = '__all__'
models.py
class Agent(models.Model):
AgencyName = models.CharField(blank=True, max_length = 50,
verbose_name="Agency Name")
OtherAgencyName = models.CharField(max_length=50, blank=True)
FirstName = models.CharField(max_length=50, null=True)
LastName = models.CharField(max_length=50, null=True)
details.html
<ul>
<li>AgencyName: {{agent.AgencyName}} </li>
<li>OtherAgencyName: {{agent.OtherAgencyName}} </li>
<li>First Name: {{agent.FirstName}} </li>
<li>Last Name: {{agent.LastName}} </li>
</ul>
<form class="form-horizontal" action="" method="post"
enctype="multipart/form-data">
{% csrf_token %}
<table>
{{ matrix1form.as_table }}
</table>
</form>
if i understand you correct, you need to override get_context_data for example:
class AgentDetailsView(generic.DetailView):
template_name = 'User/AgentDetails.html'
class Meta:
model = Agent
def get_context_data(self, **kwargs):
# ^^^^^^^^^^^^^^
context = super(AgentDetailsView, self).get_context_data(**kwargs)
matrix1form = Matrix1Form()
context['matrix1form'] = matrix1form
return context
I try to update a ForeignKey field of a model in django form. I want a user not to write his name into a input field as an author of the article that he wrote but his idmust be saved in the field in Article model. In my html-form I display only a button with hidden input. But in my views.py I write that the form should take user.id and put it in the 'article_author' field.
Unfortunately, I've got no updates into table. What am I doing wrong?
my model:
class Article(models.Model):
article_pub_date = models.DateField(default=None,null=True,verbose_name="Дата публикации")
article_title = models.CharField(max_length=70, verbose_name="Заголовок", null=True)
article_text = models.TextField(verbose_name="Текст", null=True)
article_author = models.ForeignKey(User, verbose_name='Автор', blank=True, null=True)
my views.py
def article_detail(request, article_id):
user = request.user
article = get_object_or_404(Article, pk=article_id)
author_form = ArticleForm(request.POST or None, instance=article, initial={'article_author': user.id})
if author_form.is_valid():
author_form.save()
else:
return redirect('/')
my forms.py
class ArticleForm(forms.ModelForm):
class Meta:
model = Article
fields = ('article_author',)
widgets = {'article_author': forms.HiddenInput()}
and my template:
<form method="POST" action="">
{% csrf_token %}
{{ author_form.as_p }}
<input type="submit" value="BIND" class="btn">
</form>
Try one of the following:
if author_form.is_valid():
article = author_form.save(commit=False)
article.article_author = user
# article.article_author_id = user.id #w ill work as well
article.save()
else:
return redirect('/')
or in the form instantiation:
initial={'article_author_id': user.id}
I created a form based on several ModelForm elements. All fields work fine excluding the
ImageField. Due to the missing ImageField form.is_valid() always returns False - even though I pass request.FILES to form.
Why the form with the ImageField is always invalid / empty?
Forms
class UserProfileForm2(forms.ModelForm):
class Meta:
model = models.UserProfile
fields = ['description', 'picture']
class LocationForm(forms.ModelForm):
class Meta:
model = models.Location
fields = ['city', 'state', 'country']
class UserForm(forms.ModelForm):
class Meta:
model = registration_models.User
fields = ['first_name', 'last_name']
Models
class Location(models.Model):
city = models.CharField(max_length=100)
state = models.CharField(max_length=100)
country = models.CharField(max_length=100)
def __unicode__(self):
return ' - '.join([self.city, self.state, self.country])
class UserProfile(models.Model):
authenticationuser = fields.AutoOneToOneField(AuthUser)
description = models.TextField()
picture = models.ImageField(upload_to='uploaded_files/', null=True)
location = models.ForeignKey(Location, null=True)
appear_in_public_ranking = models.BooleanField(default=True)
def __unicode__(self):
return self.authenticationuser.username
View
#login_required
def changeprofile(request):
form = None
# user posted his new profile settings
if request.method == 'POST':
user_form = myforms.UserForm(request.POST)
user_profile_form = myforms.UserProfileForm2(request.POST, request.FILES)
location_form = myforms.LocationForm(request.POST)
forms_are_invalid = not (user_form.is_valid() and user_profile_form.is_valid() and not location_form.is_valid())
if forms_are_invalid:
forms = {'user_form':user_form,
'user_profile_form':user_profile_form,
'location_form':location_form}
return shortcuts.render(request, 'changeprofile.html', forms)
location_form.save()
user_form.save()
user_profile_form.save()
return HttpResponseRedirect('/profile')
else:
forms = {'user_form':user_form,
'user_profile_form':user_profile_form,
'location_form':location_form}
return shortcuts.render(request, 'changeprofile.html', forms)
Template
<form action="{% url 'changeprofile' %}" method="post">
{% csrf_token %}
{{ user_form }}
{{ location_form }}
{{ user_profile_form }}
<input type="submit" value="Submit" />
</form>
If your form contains file input then you must set enctype in your form as:
<form action="{% url 'changeprofile' %}" method="post" enctype="multipart/form-data">
Otherwise request.FILES will always be empty.