I was debugging my program and I noticed that on the line Formset.is_valid i am getting error:
missing 1 required positional argument: 'self'
Could you please advise how it could be solved to make formset and all the forms to validate successfully and save to database. Also, is double validation (formset and form) necessary? Thank you for insights.
views.py
from django.shortcuts import render
from .forms import modelformset_factory, AssumptionsForm
from .models import Assumptions
import pdb
model_names = ['Form1', 'Form2']
def get_assumptions(request):
if request.method == 'POST':
print('Reached post')
formset = modelformset_factory(
Assumptions, form=AssumptionsForm, extra=5)
pdb.set_trace()
for thing in model_names:
if thing in request.POST:
print('template name in model_names')
if formset.is_valid():
for form in formset:
if form.is_valid():
print('in for loop after valid form1')
assumptions = form.save(commit='False')
assumptions.Name = thing
assumptions.save()
else:
formset = modelformset_factory(
Assumptions, form=AssumptionsForm, extra=5)
print('reached else')
return render(request, 'assumptions.html', {'formset': formset, 'model_names': model_names})
models.py
from django.db import models
from django.forms import ModelForm
class Assumptions(models.Model):
Worst_Case = models.FloatField(null=True, blank=True, default=None)
Grey_Case = models.FloatField(null=True, blank=True, default=None)
Red_Case = models.FloatField(null=True, blank=True, default=None)
Blue_Case = models.FloatField(null=True, blank=True, default=None)
Green_Case = models.FloatField(null=True, blank=True, default=None)
Best_Case = models.FloatField(null=True, blank=True, default=None)
Name = models.TextField(null=True, blank=True, default=None)
assumptions.html
<div class="form">
<form action="" method="post">
{% csrf_token %}
{{ formset.management_form }}
{{ formset.non_form_errors.as_ul }}
{% for vardas in model_names %}
<h1>{{vardas}}</h1>
<table id="formset" class="form">
{% for form in formset.forms %}
{% if forloop.first %}
<thead><tr>
{% for field in form.visible_fields %}
<th>{{ field.label|capfirst }}</th>
{% endfor %}
</tr></thead>
{% endif %}
<tr class="{% cycle 'row1' 'row2' %}">
{% for field in form.visible_fields %}
<td>
{# Include the hidden fields in the form #}
{% if forloop.first %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% endif %}
{{ field.errors.as_ul }}
{{ field }}
</td>
{% endfor %}
</tr>
{% endfor %}
</table>
<input type="hidden" name="{{vardas}}" />
{% endfor %}
<input type="submit" value="Next">
</form>
</div>
forms.py
from django import forms
from django.forms import modelformset_factory, ModelForm
from .models import Assumptions
class AssumptionsForm(ModelForm):
class Meta:
model = Assumptions
fields = ['Worst_Case', 'Grey_Case', 'Red_Case', 'Blue_Case', 'Green_Case', 'Best_Case']
exclude = ['Name']
You haven't instantiated your formset. A factory is something that returns a class, so here modelformset_factory returns a formset class that you then need to instantiate in both your get and post blocks.
def get_assumptions(request):
AssumptionsFormset = modelformset_factory(
Assumptions, form=AssumptionsForm, extra=5)
if request.method == 'POST':
formset = AssumptionsFormset(request.POST)
if formset.is_valid():
...
else:
formset = AssumptionsFormset()
return render(request, 'assumptions.html', {'formset': formset, 'model_names': model_names})
Also note, you don't need to check is_valid() on each form; if the formset is valid, all the forms will be valid.
Related
Whenever I click on the profiles(links) on the profile_list page, I get the profile doesn't exist error
it always goes to profiles that do not longer exist in the database.
Models.py:
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
# Create your models here.
class Profile(models.Model):
user=models.OneToOneField(User,on_delete=models.CASCADE)
follows=models.ManyToManyField(
"self",
related_name="followed_by",
symmetrical=False,
blank=True)
def __str__(self):
return self.user.username
#receiver(post_save,sender=User)
def create_profile(sender, instance, created, **kwargs):
if created:
user_profile=Profile(user=instance)
user_profile.save()
user_profile.follows.add(instance.profile)
user_profile.save()
admin.py:
from django.contrib import admin
from django.contrib.auth.models import Group,User
from .models import Profile
class ProfileInline(admin.StackedInline):
model=Profile
class UserAdmin(admin.ModelAdmin):
model=User
fields=["username"]
inlines=[ProfileInline]
# Register your models here.
admin.site.unregister(Group)
admin.site.unregister(User)
admin.site.register(User,UserAdmin)
views.py:
from django.urls import reverse
from django.shortcuts import render
from requests import request
from users.models import Profile
from django.http import HttpResponseRedirect
# Create your views here.
def dashboard(request):
return render(request,"inbox/layout.html")
def feed(request):
return render(request,"inbox/feed.html")
def outbox(request):
return render(request,"inbox/outbox.html")
def profile_list(request):
profiles=Profile.objects.exclude(user=request.user)
return render(request,"inbox/profile_list.html",{"profiles":profiles})
def profile(request, pk):
if not hasattr(request.user, 'profile'):
missing_profile = Profile(user=request.user)
missing_profile.save()
profile = Profile.objects.get(pk=pk)
if request.method == "POST":
current_user_profile = request.user.profile
data = request.POST
action = data.get("follow")
if action == "follow":
current_user_profile.follows.add(profile)
elif action == "unfollow":
current_user_profile.follows.remove(profile)
current_user_profile.save()
return render(request, "inbox/profile.html", {"profile": profile})
profile.html:
<!-- inbox/templates/inbox/profile_list.html -->
{% extends 'inbox/layout.html' %}
{% block content %}
<form method="post">
{% csrf_token %}
<div >
<p>#{{ profile.user.username|upper }}</p>
<div class="buttons has-addons">
{% if profile in user.profile.follows.all %}
<button class="button is-success is-static">Follow</button>
<button class="button is-danger" name="follow" value="unfollow">
Unfollow
</button>
{% else %}
<button class="button is-success" name="follow" value="follow">
Follow
</button>
<button class="button is-danger is-static">Unfollow</button>
{% endif %}
</div>
<p1>following:</p1>
<ul>
{% for following in profile.follows.all %}
<li>{{ following }}</li>
{% endfor %}
</ul>
<p2>followers:</p2>
<ul>
{% for follower in profile.followed_by.all %}
<li>{{ follower }}</li>
{% endfor %}
</ul>
</div>
</form>
{% endblock content %}
profile_list.html template:
<!-- inbox/templates/inbox/profile_list.html -->
{% extends 'inbox/layout.html' %}
{% block content %}
<form method="post">
{% csrf_token %}
{% for profile in profiles %}
<div class="column">
<p>{{ profile.user.username }}</p>
<p>#{{ profile.user.username|lower }}</p>
</div>
{% endfor %}
</form>
{% endblock content %}
You need to match Profile's pk with profile = Profile.objects.get(pk=pk), currently you mentioned the pk of User model, which matched the given queryset in profile view, so try sending pk of profile in profile_list.html template:
{% for profile in profiles %}
<div class="column">
<p>{{ profile.user.username }}</p>
<p>#{{ profile.user.username|lower }}</p>
</div>
{% endfor %}
Also, it is better to use get_object_or_404 instead of get, as it calls get() on a given model manager, but it raises Http404 instead of the model’s DoesNotExist exception.
So, views.py:
def profile(request, pk):
if not hasattr(request.user, 'profile'):
missing_profile = Profile(user=request.user)
missing_profile.save()
profile = get_object_or_404(Profile, pk=pk)
if request.method == "POST":
current_user_profile = request.user.profile
data = request.POST
action = data.get("follow")
if action == "follow":
current_user_profile.follows.add(profile)
elif action == "unfollow":
current_user_profile.follows.remove(profile)
current_user_profile.save()
return render(request, "home/profile.html", {"profile": profile})
Now, if the profile does not exist, it will show no Profile matches the given query.
The issue is that Django modelformset_factory does not save to database when inputs are inserted into the forms. It appears that only else statement is reached after forms are submitted for processing. Clearly the issue is with part in views.py where if 'name' in request.POST: then do sth. Advise how to solve it would be highly appreciated. Thank you.
views.py
from django.shortcuts import render
from .forms import modelformset_factory, AssumptionsForm
from .models import Assumptions
model_names = ['Form1', 'Form2']
def get_assumptions(request):
if request.method == 'POST' and 'name' in request.POST:
formset = modelformset_factory(
Assumptions, form=AssumptionsForm, extra=5)
if formset.is_valid():
print('valid form')
for form in formset:
if form.is_valid():
print('in for loop after valid form1')
assumptions = form.save(commit='False')
assumptions.Name = 'name'
assumptions.save()
else:
formset = modelformset_factory(
Assumptions, form=AssumptionsForm, extra=5)
print('reached else')
return render(request, 'assumptions.html', {'formset': formset, 'model_names': model_names})
models.py
from django.db import models
from django.forms import ModelForm
class Assumptions(models.Model):
Worst_Case = models.FloatField(null=True, blank=True, default=None)
Grey_Case = models.FloatField(null=True, blank=True, default=None)
Red_Case = models.FloatField(null=True, blank=True, default=None)
Blue_Case = models.FloatField(null=True, blank=True, default=None)
Green_Case = models.FloatField(null=True, blank=True, default=None)
Best_Case = models.FloatField(null=True, blank=True, default=None)
Name = models.TextField(null=True, blank=True, default=None)
forms.py
from django import forms
from django.forms import modelformset_factory, ModelForm
from .models import Assumptions
class AssumptionsForm(ModelForm):
class Meta:
model = Assumptions
fields = ['Worst_Case', 'Grey_Case', 'Red_Case', 'Blue_Case', 'Green_Case', 'Best_Case']
exclude = ['Name']
assumptions.html
<div class="form">
<form action="" method="post">
{% csrf_token %}
{{ formset.management_form }}
{{ formset.non_form_errors.as_ul }}
{% for name in model_names %}
<h1>{{name}}</h1>
<table id="formset" class="form">
{% for form in formset.forms %}
{% if forloop.first %}
<thead><tr>
{% for field in form.visible_fields %}
<th>{{ field.label|capfirst }}</th>
{% endfor %}
</tr></thead>
{% endif %}
<tr class="{% cycle 'row1' 'row2' %}">
{% for field in form.visible_fields %}
<td>
{# Include the hidden fields in the form #}
{% if forloop.first %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% endif %}
{{ field.errors.as_ul }}
{{ field }}
</td>
{% endfor %}
</tr>
{% endfor %}
</table>
<input type="submit" name="{{name}}" value="save" />
{% endfor %}
</form>
</div>
name needs to be in your request.POST,
doublecheck your template and add an input tag with a name='name'
<input name='name' />
I am quite new to Django. I am currently using ModelForm to save user input data to model. However, I would like to save data to other child models which inherits from parent model. However, my code saves data to the parent model. I guess that save() function should be overwritten to save data to child model, but I have no idea how to do it. Also, how should I scale my template or forms.py to include more forms with different submit button names(or any other method so that submitted forms could be distinguished and database populated accordingly)? Any insights highly appreciated. Please find my code below.
forms.py
from django import forms
from django.forms import modelformset_factory, ModelForm
from .models import Assumptions, Scenario1_Assumptions,
Scenario2_Assumptions, Scenario3_Assumptions, Scenario4_Assumptions ...
Scenario_N_Assumptions
class AssumptionsForm(ModelForm):
class Meta:
model = Assumptions
fields = ['Worst_Case', 'Grey_Case', 'Red_Case', 'Blue_Case',
'Green_Case', 'Best_Case']
exclude = ()
AssumptionsFormSet = modelformset_factory(Assumptions, form=AssumptionsForm,
extra = 5)
views.py
from django.shortcuts import render
from .forms import AssumptionsFormSet, modelformset_factory
from .models import Scenario1_Assumptions, Assumptions
def get_assumptions(request):
if request.method == 'POST':
formset = AssumptionsFormSet(request.POST)
if formset.is_valid():
if 'scenario1' in request.POST:
for form in formset:
Scenario1_Assumptions = form.save() #THIS DOESN'T WORK
if 'scenario2' in request.POST:
for form in formset:
Scenario2_Assumptions = form.save() #and so on...
else:
formset = AssumptionsFormSet()
return render(request, 'assumptions.html', {'formset': formset})
models.py
from django.db import models
from django.forms import ModelForm
class Assumptions(models.Model):
Worst_Case = models.FloatField(null=True, blank=True, default=None)
Grey_Case = models.FloatField(null=True, blank=True, default=None)
Red_Case = models.FloatField(null=True, blank=True, default=None)
Blue_Case = models.FloatField(null=True, blank=True, default=None)
Green_Case = models.FloatField(null=True, blank=True, default=None)
Best_Case = models.FloatField(null=True, blank=True, default=None)
class Scenario1_Assumptions(Assumptions):
pass
class Scenario2_Assumptions(Assumptions):
pass
class Scenario3_Assumptions(Assumptions):
pass
class Scenario4_Assumptions(Assumptions):
pass
.
.
.
class Scenario_N_Assumptions(Assumptions):
pass
Assumptions.html
<form action="" method="post">
{% csrf_token %}
{{ formset.management_form }}
{{ formset.non_form_errors.as_ul }}
<table id="formset" class="form">
{% for form in formset.forms %}
{% if forloop.first %}
<thead><tr>
{% for field in form.visible_fields %}
<th>{{ field.label|capfirst }}</th>
{% endfor %}
</tr></thead>
{% endif %}
<tr class="{% cycle 'row1' 'row2' %}">
{% for field in form.visible_fields %}
<td>
{# Include the hidden fields in the form #}
{% if forloop.first %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% endif %}
{{ field.errors.as_ul }}
{{ field }}
</td>
{% endfor %}
</tr>
{% endfor %}
</table>
<input type="submit", name = "scenario1", value="Submit" />
</form>
I have a Django model class that extends the django.contrib.auth.models.User:
class MyModel(models.Model):
user = models.OneToOneField(User, models.CASCADE, unique=True)
bio = models.TextField()
date_of_birth = models.DateField()
and out of this model I'm making a ModelForm:
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
fields = ['bio', 'date_of_birth']
How can I tell the MyModelForm to take in the User's fields such as username, first_name, last_name?
Example in the class Meta fields I can add ['bio', 'date_of_birth', 'user'] but that will just provide me with the dropdown to select to whom shall the MyModel in the MyModelForm be related to.
Doing ['bio', 'date_of_birth', 'user.first_name'] throws an exception django.core.exceptions.FieldError: Unknown field(s) (user.first_name) specified for MyModel
Edit: here's the traceback
https://pastebin.com/0T42VKEP
I kinda found my own solution, by overriding ModelForm's __init__ method:
class MyModelForm(forms.ModelForm):
first_name = forms.CharField()
class Meta:
model = MyModel
fields = ['bio', 'date_of_birth']
def __init__(self, *args, **kwargs):
super(MyModelForm, self).__init__(*args, **kwargs)
my_user = kwargs.get('instance')
first_name = my_user.user.first_name
self.fields['first_name'].initial = first_name #this will show the first name in the html page when i request the instance
And when I'm instantiating my form I just pass an instance of MyModel as a
kwarg: form = MyModelForm(instance=my_model_instance)
You can use InlinFormset. Here I am posting a code sample used by me that might help you. I have modified a bit according to your need, so if anything doesn't work let me know.
#forms.py
class UserForm(forms.ModelForm):
class Meta:
model = User
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
then in your views you should do like
def profileEdit(request,username):
# querying the User object with pk from url
user = User.objects.get(username=username)
# prepopulate MyModelForm with retrieved user values from above.
user_form = UserForm(instance=user)
MyModelInlineFormset = inlineformset_factory(User, MyModel,can_delete=False, fields="__all__")
formset = MyModelInlineFormset(instance=user)
if request.user.is_authenticated() and request.user.id == user.id:
if request.method == "POST":
user_form = UserForm(request.POST, request.FILES, instance=user)
formset = MyModelInlineFormset(request.POST, request.FILES, instance=user)
if user_form.is_valid():
created_user = user_form.save(commit=False)
formset = MyModelInlineFormset(request.POST, request.FILES, instance=created_user)
if formset.is_valid():
created_user.save()
formset.save()
return HttpResponseRedirect('/')
return render(request, "profile_edit.html", {
'title':'Edit -'+ user.get_full_name(),
"user_form": user_form,
"formset": formset,
})
else:
raise PermissionDenied
and in your profile_edit.html
{% extends "layout.html" %}
{% block content %}
{% if messages %}
<div>
{% for message in messages %}
<div class="alert alert-{{ message.tags }}"> <!-- singular -->
<a class="close" data-dismiss="alert">×</a>
{{ message|safe }}
</div>
{% endfor %}
</div>
{% endif %}
<div class="col-xs-8 col-xs-offset-2">
<div class="card">
<div class="card-content">
<h2 class="flow-text">Update your information</h2>
<form action="." method="POST" class="padding" enctype="multipart/form-data">
{% csrf_token %}
{% for field in user_form %}
<div class="form-group">
{{ field.errors }}
<label for="{{ field.label }}" >{{ field.label }}</label>
{{ field }}
{% if field.help_text %}
<small class="form-text text-muted">{{ field.help_text|safe }}</small>
{% endif %}
</div>
{% endfor %}
{{ formset.management_form }}
{% for form in formset %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in form.visible_fields %}
<div class="form-group">
{{ field.errors }}
<label for="{{ field.label }}" >{{ field.label }}</label>
{{ field }}
{% if field.help_text %}
<small class="form-text text-muted">{{ field.help_text|safe }}</small>
{% endif %}
</div>
{% endfor %}
{% endfor %}
<input type="submit" class="btn btn-primary" value="Save"></input>
</form>
</div>
</div>
</div>
{% endblock content %}
trying to create a registration form, and I am facing an issue. so, below are my python pages:
form.py
from .models import User
from django import forms
from django.forms import ModelForm
class SignUpForm(ModelForm):
class Meta:
model = User
fields = ('username','password','email')
models.py
from django.db import models
#from django.core.urlresolvers import reverse
from django.contrib.auth.models import User
class Registration(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
urls.py
urlpatterns = [
url(r'^register/$', views.SignUpFormView, name= 'register'),
]
test.html
{% extends 'user_info/base.html' %}
{% block body %}
{% block content %}
<form method="POST">
{% csrf_token %}
{{ form }}
username:<br>
<input type="text" name="username"><br>
password:<br>
<input type="text" name="password"><br>
email:<br>
<input type="text" name="email"><br>
<input type="submit" value="Submit" />
</form>
{% endblock %}
{% endblock %}
views.py
def SignUpFormView(request):
template_name = 'test.html'
try:
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password')
email = form.cleaned_data.get('email')
return render(request, template_name, {'form':form})
except ValueError:
print("Oops! That was not a valid entry, try again...")
else:
SignUpForm()
return render(request, 'user_info/about.html')
The issue is, my "SignUpFormView" function in views.py is not entering the "if" statement, its directly going to "else". I seem to be lost here.
I have 'about.html'. I do not see any error as well. Which I find very weird. Please help.
Note: I am using Django's default in-built "User" model, and I do not wish to create any custom model.
Modified views.py
def SignUpFormView(request):
user_form = 'SignUpForm'
template_name = 'test.html'
if request.method == 'POST':
form = user_form(request.POST)
if form.is_valid():
form.save()
#username = form.cleaned_data.get('username')
#password = form.cleaned_data.get('password')
#email = form.cleaned_data.get('email')
#user.save()
return render(request, template_name, {'form':form})
else:
SignUpForm()
return render(request, 'user_info/about.html')
Modified forms.py
from .models import User
from django import forms
from django.forms import ModelForm
class SignUpForm(forms.ModelForm):
#password = forms.Charfield(widget=forms.PasswordInput)
class Meta:
model = User
fields = ('username','password','email')
modified test.html
{% extends 'user_info/base.html' %}
{% block body %}
{% block content %}
{% for error in form.errors %}
{{ form.errors | default_errors }}
{% endfor %}
<form method="post">
{% csrf_token %}
{{ form.as_p }}
{% for field in form %}
<p>
username:<br>
<input type="text" name="username"><br>
password:<br>
<input type="text" name="password"><br>
email:<br>
<input type="text" name="email"><br>
{% for error in field.errors %}
<p style="color: red">{{ error }}</p>
{% endfor %}
</p>
{% endfor %}
<button type="submit" value="Submit">sign up </button>
</form>
{% endblock %}
{% endblock %}