form.is_valid() is false when it shouldn't be - django-forms

So i'm new in Django and i'm trying some tutorials. This code is exact same as the one in tutorial but it does not work form me.
views.py
from .forms import BlogPostForm
def blog_post_create_view(request):
form = BlogPostForm(request.POST or None)
if form.is_valid():
print(form.cleaned_data)
else:
print(form.slug, form.title, form.content)
template_name = "form.html"
context = {"form": None}
return render(request, template_name, context)
forms.py
from django import forms
class BlogPostForm(forms.Form):
title = forms.CharField()
slug = forms.SlugField()
content = forms.CharField(widget=forms.Textarea)
form.html
{% extends "base.html" %}
{% block content %}
{% if title %}
<h1> {{ title }}</h1>
{% endif %}
<form method="POST" action="."> {% csrf_token %}
{{ form.as_p }}
<button type="submit">SEND</button>
</form>
{%endblock%}
So when I run this, code the is_valid() functions returns False and I get :
AttributeError: 'BlogPostForm' object has no attribute 'slug'

Related

How do you filter Formsets in Django inlineformset factory

I have two models, effectively a parent/child relationship. I have used inlineformset factory successfully for most of my objectives but one is proving rather troublesome. I only want to show the notes authored by the logged on user and enable that user to add, edit and delete note records authored by them. I am getting notes from all users logged on or not.
Django version 4.1, Python version 3.8.1
My Classes
class Fungi(models.Model):
CommonName = models.CharField(max_length=255, blank=False, null=False, default='Common Name')
LatinName = models.CharField(max_length=255, blank=False, null=False, default='Latin Name')
...
slug = models.SlugField(null=True)
...
class FungiNotes(models.Model):
Fungi = models.ForeignKey(Fungi, max_length=255, blank=False, null=False,
NoteAuthor = models.IntegerField(default=1, blank=True, null=True)on_delete=models.CASCADE, related_name='fungi_notes')
Note = models.CharField(max_length=255, blank=True, null=True, default='NoData')
...
slug = models.SlugField(null=True)
......
self.slug = slugify(self.Fungi_id)
Forms.py
FungiNotesFormset = inlineformset_factory(
Fungi,
FungiNotes,
extra=1,
labels='',
can_delete=True,
exclude=('Fungi','slug','NoteCount','NoteUser'),
)
views.py
class FunginotesEditView(SingleObjectMixin, FormView): #https://www.youtube.com/watch?v=OduVfuv44K8
model = FungiNotes
template_name = 'fungi_notes.html'
def get(self, request, *args, **kwargs):
self.object = self.get_object(queryset=Fungi.objects.all())
return super().get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
self.object = self.get_object(queryset=Fungi.objects.all())
return super().post(request, *args, **kwargs)
def get_form(self, form_class=None):
print('get_form__self.object +== ', self.object)
return FungiNotesFormset(**self.get_form_kwargs(), instance=self.object)
def form_valid(self, form):
form.save()
messages.add_message(
self.request,
messages.SUCCESS,
'Changes were saved.'
)
return HttpResponseRedirect(self.get_success_url())
def get_success_url(self):
return reverse('FungiDetail-Page', kwargs={'slug': self.object.slug})
urls.py
path('Fungis/<int:pk>/notes/edit/', views.FunginotesEditView.as_view(), name='Fungi_note_add_edit_delete'),
Fungi_notes.html
{% block DetailBlock %}
<form action="" method="post" enctype="multipart/form-data">
{% for hidden_field in form.hidden_fields %}
{{ hidden_field.errors }}
{{ hidden_field }}
{% endfor %}
{% csrf_token %}
{{ form.management_form }}
{{ form.non_form_errors }}
<div class="detail">
<h3><label class="sub-content">Update Fungi Notes</label></h3>
{% for fungi_note_form in form.forms %}
<h4>
{% if fungi_note_form.instance.id %}
Fungi Note:
{% else %}
{% if fungi_note_form.forms|length > 1 %}
Add another Note
{% else %}
Add a Note
{% endif %}
{% endif %}
</h4>
{% for hidden_field in fungi_note_form.hidden_fields %}
{{ hidden_field.errors }}
{% endfor %}
{{ refs.non_field_errors }}
<div class="sub-content">
<h4>
{{ fungi_note_form|crispy }}
</h4>
</div>
{% endfor %}
<p>
<button type="submit" class="btn btn-success">Update Note(s)</button>
Cancel
</p>
</div>
</form>
{% endblock DetailBlock %}
My approach has been to try and edit the formset and limit it to records as can be retrieved from the database by:
SELECT
Fungi.id,
FungiNotes.*
FROM
FungiNotes
INNER JOIN Fungi ON Fungi.id = FungiNotes.slug
WHERE
FungiNotes.NoteUser = 29 AND Fungi.id = 3
I have searched high and low for away to do this with no luck. I have a suspicion that 'get_form_kwargs()' might be in the solution somewhere!!!
Thank you

Django-MPTT Template: Subcategories not rendered when in recursetree

I am building a category and subcategory tree for my eCommerce website. Category model has a TreeForeignKey to itself so that categories can have many other subcategories as children. In my product.html route, I successfully rendered the categories tree with {& recursetree [models] &} tag (see first image below). When the user clicks on say the "Pumps" link, the user will be brought to another page that shows "Pumps" and its subcategories only. However, when i tried to replicate the same thing with {& recursetree [models] &}, it did not work out. I only see "Pumps" parent and none of its children subcategories. I've made sure that i passed in a treequeryset into the recursetree tag so that i dont run into "object not subscriptable error". However, i have hit a roadblock and do not know what is wrong with my code.
models.py
from django.db import models
from mptt.models import MPTTModel, TreeForeignKey, TreeManyToManyField
from ckeditor_uploader.fields import RichTextUploadingField
from django.urls import reverse
# Create your models here.
class Category(MPTTModel):
Status = (
('True', 'True'),
('False', 'False'),
)
bool_choices = (
(True, 'Yes'),
(False, 'No'),
)
parent = TreeForeignKey('self', blank = True, null = True, related_name = 'children', on_delete=models.CASCADE)
name = models.CharField(max_length=50)
slug = models.SlugField(unique=True, null=False)
description = models.TextField()
status = models.CharField(max_length=10, choices = Status)
is_active = models.BooleanField(choices=bool_choices)
meta_keywords = models.CharField(max_length=255)
meta_description = models.CharField(max_length=255)
created_at = models.DateTimeField(auto_now_add = True)
updated_at = models.DateTimeField(auto_now = True)
image = models.ImageField(blank = True, upload_to = 'images/')
class Meta:
db_table = 'categories'
verbose_name_plural = 'Categories'
def __str__(self):
return f"{self.name}"
class MPTTMeta:
order_insertion_by = ['name']
def get_absolute_url(self):
return reverse('category_detail', kwargs={'slug':self.slug})
views.py
def product(request):
category = Category.objects.all()
context = {'category': category}
return render(request, 'product.html', context)
def category(request, slug):
category = Category.objects.all().filter(slug=slug)
context = {'category': category}
return render(request, 'category.html', context)
urls.py
from django.urls import path
from . import views
from django.conf.urls.static import static
from django.conf import settings
urlpatterns = [
path("product/", views.product, name='product'),
path("<str:slug>/", views.category, name='category'),
]+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
product.html
{% extends 'layout.html' %}
{% block title %}
{% endblock %}
{% block body %}
<div>
{% load mptt_tags %}
<div class = "container">
<ul class="root">
{% recursetree category %}
<li>
{{ node.name }}
{% if not node.is_leaf_node %}
<ul class="children">
{{ children }}
</ul>
{% endif %}
</li>
{% endrecursetree %}
</ul>
</div>
</div>
{% endblock %}
[Categories and its subcategories successfully rendered in product.html]
[1]: https://i.stack.imgur.com/WO2ZH.png
category.html
{% extends 'layout.html' %}
{% block title %}
{{ category.id }}
{% endblock %}
{% block body %}
{% load mptt_tags %}
<div class = "container">
<ul class="root">
{% recursetree category %}
<li>
{{ node.name }}
{% if not node.is_leaf_node %}
<ul class="children">
{{ children }}
</ul>
{% endif %}
</li>
{% endrecursetree %}
</ul>
</div>
{% endblock %}
[Pumps' subcategories failed to render in the category.html]
[2]: https://i.stack.imgur.com/6DRkQ.png
The output from category = Category.objects.all().filter(slug=slug) is a <TreeQuerySet [<Category: Pumps>]> only.
If i need to render the children as well, i need to call the following line to grab the descendants and the model instance itself.
category = category.get_descendants(include_self=True)

Adding an object to a dropdown list without reloading the page

Hi I have a 'member' model that references a 'role' model. What I would like is when a user creates a 'member' they can either choose from a list of default 'roles' (that have been loaded to the database when the server starts using fixtures) or they can click on add role and then type in and click submit and the newly created role is created and assigned to the newly created 'member' object.
I would like it so that I am able to just create a role without submitting, and the role then appears in the dropdown menu for the role field in the member model. Is this where I would need to learn about AJAX to implement this feature?
Models
class MemberRole(models.Model,get_fields):
name = models.CharField(max_length = 20)
def __unicode__(self):
return self.name
class Member(models.Model,get_fields):
first_name = models.CharField(max_length = 20)
role = models.ForeignKey(MemberRole, null = True, blank = True)
View
def add_member(request):
model_url = 'member-add'
if request.method == "POST":
rform = MemberRoleForm(request.POST, instance=MemberRole())
mform = MemberForm(request.POST, instance=Member())
if rform.is_valid() and mform.is_valid():
new_role = rform.save()
new_member = mform.save(commit=False)
new_member.role = new_role
new_member.save()
return HttpResponseRedirect('members')
else:
rform = MemberRoleForm(instance=MemberRole())
mform = MemberForm(instance=Member())
return render_to_response('create_model.html', {'role_form': rform, 'member_form': mform, 'model_url': model_url,},context_instance=RequestContext(request))
snippet create_model.html
<div id = "subtemplate">
<form action="{% url model_url %}" method="POST">
{% csrf_token %}
{% if model_url == 'member-add' %}
{% for field in member_form %}
{% if field.label == 'Role' %}
<div id="roleExistsMemberForm">
<button type="button" onclick="showDiv()">Add Role</button>
{{ field.errors }}
{{ field.label_tag }} {{ field }} {{ field.help_text }}
</div>
{% else %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
</div>
{% endif %}
{% endfor %}
<div Id="addRoleOnMemberForm">
{% for field in role_form %}
{{ field.errors }}
{{ field.label_tag }} {{ field }}
{% endfor %}
</div>
{% else %}
<ul>
<li>{{ form.as_ul }}</li>
</ul>
{% endif %}
<div id="centerbuttons">
<input id="save_contact" type="submit" value="Add"/>
</div>
</form>
Yes, Ajax would be the first point of call for something like this. You can submit the form in the background to a Django view, the view could then respond with a fresh list of options to re-populate the drop down list with.

Error while passing a POST data to form wizard

I have an initial form as below
forms.py
class LoginForm(forms.Form):
activity_no = forms.CharField()
username = forms.CharField()
views.py
def test(request):
if request.method == 'POST' :
form = LoginForm(request.POST)
if form.is_valid() :
act_no = form.cleaned_data['activity_no']
username = form.cleaned_data['username']
form_data = {}
form_data['activity_no'] = act_no
form_data['username'] = username
return render_to_response("test1.html", { 'form_data' : form_data}, context_instance=RequestContext(request))
else:
form = LoginForm()
return render_to_response("test.html", {'form': form }, context_instance=RequestContext(request))
test.html
{% extends "admin/base.html" %}
{% block content %}
<form action="/todo/test/" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
{% endblock %}
test1.html
{% extends "admin/base.html" %}
{% block content %}
<form action="/todo/login/" method="post">{% csrf_token %}
{% for name, data in form_data.items %}
<input type="hidden" name={{name}} value={{data}}>
{% endfor %}
<input type="submit" value="Yes"/>
</form>
{% endblock %}
I fill this form, display few contents of a file and pass the above form data to a form wizard
But when I pass the data to the form wizard via post method in the template, I get a "ManagementForm Data missing" error but if the data is passed through the GET method, I don't get any error but as defined, the data is seen in the url in the GET method ( in my case it contains username which I don't want to disclose)
My Form Wizard
class LoginWizard(SessionWizardView):
def __name__(self):
"""When using decorators, Django tries to get the name of the
function and since we're a class, we'll fail. So add this method to
compensate."""
return 'LoginWizard'
template_name = "wizard_form.html"
def done(self, form_list, **kwargs) :
form_data = process_form_data(form_list)
My query is that how would I handle the post data in the form wizard.
Please let me know if I am missing anything or any other information is required from my end.
You need to add {{ wizard.management_form }} in your template as explained it in reference django wizard templates.
Like:
{% extends "admin/base.html" %}
{% block content %}
<form action="/todo/test/" method="post">{% csrf_token %}
{{ wizard.management_form }}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
{% endblock %}
Add that in all templates for wizard.

Update a date-time field (from system) but don't make it visible to user

The following is my "view" which renders a form through "editpost.html". I want to update the timestamp (datetime field) to be edited by the system time, but don't want that to be visible to the user. I tried using "hidden" keyword in the modelform definition Meta class, but that does not update the time correctly. I tried doing it in the template but doesn't work. Any ideas?
def editpost(request, postid):
blog = BlogPost.objects.get(pk=postid)
if request.method == 'POST':
form = BlogPostForm(request.POST, instance=blog)
blog = form.save()
return HttpResponseRedirect('/blog/%s' % str(postid))
else:
form = BlogPostForm(initial={'timestamp': datetime.now()}, instance=blog)
form.save(commit=False)
return render_to_response("editpost.html", {'form': form, 'postid': postid}, RequestContext(request))
editpost.html
{% block content %}
<form action="." method="post">{% csrf_token %}
{% for field in form %}
{% if field.label_tag != "Timestamp" %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
</div>
{% endif %}
{% endfor %}
<input type="submit" value="Save" />
</form>
{% endblock %}
May be better would be rewrite def save(...) of the model. You can try it:
def save(self, *args, **kwargs):
self.timestamp = datetime.now()
super(Dog,self).save(*args, **kwargs)

Resources