add/remove fields in django forms - django

So I have a form where user can post "Parents" details also fields for Children from a different model.
What I need is that to allow users to add "Children" fields as many children as they have . Also for the children fields not to be required in case they do not have children.
But, if one of the children fields is filled the others are required.
models.py :
class Parent(models.Model):
title = models.CharField(max_length=250)
address = models.CharField(max_length=250)
class Kid(models.Model):
family = models.ForeignKey(Parent)
title = models.CharField(max_length=250)
age = models.CharField(max_length=250)
views.py
def add_family(request):
if request.method == 'POST':
parent_form = ParentForm(request.POST)
kid_form = KidForm(request.POST)
if parent_form.is_valid() and kid_form.is_valid():
parent = parent_form.save(commit=False)
parent.save()
kid = kid_form.save(commit=False)
kid.family = parent
kid.save()
return redirect('index')
else:
parent_form = ParentForm()
kid_form = KidForm()
template = 'add_family.html'
context = {'parent_form': parent_form, 'kid_form': kid_form}
return render(request, template, context)
template:
<form method="post">
{% csrf_token %}
{{ parent_form.title }}
{{ parent_form.address }}
{{ kid_form.title }}
{{ kid_form.age }}
<button type="submit">Send</button>
</form>
so if the "kid_form.title" is filled. then the age is required.
any help?

Related

'modelBlog' object has no attribute 'CommentModel_set'

Im try make blog detail and comment in one page but if im try posting comment i got error like this 'modelBlog' object has no attribute 'CommentModel_set'
My views
def comment(request, id):
blog = get_object_or_404(modelBlog, id=id)
form = CommentForm(request.POST or None)
heading = blog.title
if request.method == 'POST':
if form.is_valid():
data={
'name':request.POST['name'],
'komentar':request.POST['komentar'],
}
blog.CommentModel_set.create(**data)
return redirect('blog:detail', id)
context = {
'title':'Detail',
'heading': heading,
'blog':blog,
'comment':comment,
'form':form
}
return render(request, 'blog/detail.html', context)
And my model
class modelBlog(models.Model):
title = models.CharField(max_length=200)
description = models.TextField()
body = models.TextField()
pub_date = models.DateTimeField(auto_now_add=True,)
def __str__(self):
return ('{}.{}').format(self.id, self.title)
class CommentModel(models.Model):
user = models.ForeignKey('auth.User',default=1, on_delete=models.CASCADE)
blog = models.ForeignKey(modelBlog, on_delete=models.CASCADE)
name = models.CharField(max_length=200)
komentar = models.TextField()
pub_date = models.DateTimeField(auto_now_add=True,)
My forms
class CommentForm(forms.ModelForm):
class Meta:
model = CommentModel
fields = [
'name',
'komentar',
]
widgets = {
'name': forms.TextInput(attrs={'class':'form-control'}),
'komentar': forms.Textarea(attrs={'class':'form-control'}),
}
}
My templates
<form action="{% url 'blog:comment' blog.id %}" method="post">
{% comment %} {% endcomment %}
{% csrf_token %}
{% for forms in form %}
<div class="mb-3">
<label for="exampleFormControlInput1" class="form-label">{{forms.label}}</label>
<input type="{{forms.type}}" name="{{forms.name}}" class="form-control" id="exampleFormControlInput1">
</div>
{% endfor %}
<button type="submit" class="btn btn-primary">Kirim</button>
</form>
Don't use uppercase! You must omit capital letters when use "_set"
blog.commentmodel_set.create(**data)
From the doc:
"If you don’t specify a related_name attribute for a field in an abstract base class, the default reverse name will be the name of the child class followed by '_set', just as it normally would be if you’d declared the field directly on the child class. For example, in the above code, if the related_name attribute was omitted, the reverse name for the m2m field would be childa_set in the ChildA case and childb_set for the ChildB field."

fields do not recognise django

I have been having a problem working with formsets in my project and I've been trying to get to the bottom of this. While doing so, a couple of different errors have been appearing. Generally, what I want to do is create an object of entity A (workout) and get redirected to a template/url that lets me "fill" it with objects of entity B, which I will be making at that point dynamically using model formsets. The problem seems to be revolving around the form, more specifically: if I write the fields one by one, as in :
CycleFormSet = modelformset_factory(
Cycle, fields=('reps', 'place_in_workout', 'exercise', 'number_of_times', 'break_inbetween'), extra=1
)
Then, I get the error: Unknown field(s) (place_in_workout, break_inbetween, reps, number_of_times) when I attempt to run the server. If I use exclude for some field, or do fields = 'all' , then I don't get an error at this point. However, I get the error : ['ManagementForm data is missing or has been tampered with'] when I try to post the data of the workout object. Me code:
models.py
class Exercise(models.Model):
name = models.CharField(max_length=150)
description = models.TextField(max_length=500)
def __str__(self):
return self.name
class Workout(models.Model):
name = models.CharField(max_length=150, null=True)
created_by_user = models.ForeignKey(User, null=True, on_delete=models.RESTRICT)
description = models.TextField(max_length=1000, null=True)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
class Cycle(models.Model):
place_in_workout = models.IntegerField
exercise = models.ManyToManyField(Exercise)
number_of_times = models.IntegerField
reps = models.IntegerField
break_inbetween = models.IntegerField
workout = models.ManyToManyField(Workout)
class WorkoutCompleted(models.Model):
datetime = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(User, on_delete=models.RESTRICT)
forms.py
class CreateUserForm(UserCreationForm):
class Meta:
model = User
fields = ['username', 'email', 'password1', 'password2']
class WorkoutForm(forms.ModelForm):
class Meta:
model = Workout
fields = ['name', 'description']
class ExerciseForm(forms.ModelForm):
class Meta:
model = Exercise
fields = ['name', 'description']
CycleFormSet = modelformset_factory(
Cycle, fields='__all__', extra=1
)
urls.py
urlpatterns = [
path('register/', views.register_page, name='register'),
path('login/', views.login_page, name='login'),
path('logout', views.logout_page, name='logout'),
path('', views.index, name='index'),
path('browse/', views.browse, name='browse'),
path('workouts/<str:user_id>/', views.workouts, name='workouts'),
path('add_exercise/', views.add_exercise, name='add_exercise'),
path('create_workout/<str:user_id>/', views.fill_workout, name='fill_workout')
]
views.py
#login_required(login_url='login')
def workouts(request, user_id):
context = {}
if request.method == 'POST':
form = WorkoutForm(request.POST)
if form.is_valid():
workout = form.save(commit=False)
workout.created_by_user = request.user
workout.save()
workout_id = workout.id
context = {'workout_id': workout_id}
return render(request, 'Trainmate/fill_workout.html', context)
else:
form = WorkoutForm()
workout_programs = Workout.objects.all()
user_workouts = workout_programs.filter(created_by_user=user_id)
context = {'user_workouts': user_workouts, 'form': form}
return render(request, 'Trainmate/workouts.html', context)
#login_required(login_url='login')
def fill_workout(request, user_id):
if request.method == 'POST':
# workouts = Workout.objects.filter(created_by_user__exact=request.user).order_by('-created_at')
# current_workout = workouts[0]
# pk_workout = current_workout.id
pk_workout = 1
formset = CycleFormSet(request.POST)
if formset.is_valid():
for form in formset:
cycle = form.save(commit=False)
cycle.workout = Workout.objects.get(pk=pk_workout)
cycle.save()
context = {}
return render(request, 'Trainmate/home.html', context)
else:
formset = CycleFormSet(queryset=Cycle.objects.none())
context = {'formset': formset}
return render(request, 'Trainmate/fill_workout_with_sets', context)
(there are more views, I didn't include some views about login/logout, if asked, I will, I didn't want to make the post even bigger than it's already going to be). Also, I have run the views with the commented section, I believe I am doing some mistake with queryset, therefore I gave the pk_workout=1 so that the fault in the query set is not relevant. There is at least a workout object in the database at all times.
workouts.html
{% extends 'Trainmate/main.html' %}
{% block content %}
<h1>My Workouts</h1>
<div>
{% for workout in user_workouts %}
<tr>
<td>{{ workout.name }}</td>
<td><a class="btn btn-sm btn-info" href="">Update</a></td>
<td><a class="btn btn-sm btn-info" href="">Delete</a></td><br>
</tr>
{% endfor %}
</div>
<h1>Create new Workout</h1>
<form method="POST" action="{% url 'fill_workout' request.user.id %}">
{% csrf_token %}
{{ form }}
<input type="submit" value="Create Workout">
</form>
{% endblock %}
fill_workout.html
{% extends 'Trainmate/main.html' %}
{% block content %}
<h1>Fill workout with sets</h1>
<form id="form_container" method="POST" action="">
{% csrf_token %}
{{ formset.management_form }}
{% for form in formset %}
<div class="set_form">
{{ form.as_p }}
</div>
{% endfor %}
<button id="add-form" type="button">Add another set</button>
<button type="submit"> Create Cycle</button>
</form>
let set_form = document.querySelectorAll(".set_form")
let container = document.querySelector("#form_container")
let add_button = document.querySelector("#add_form")
let total_forms = document.querySelector("#id_form-TOTAL-FORMS")
let form_num = set_form.length -1
add_button.addEventListener('click',add_form)
function add_form(e){
e.preventDefault()
let new_form = set_form[0].cloneNode(true)
let form_regex = RegExp(`form-(\\d){1}-`,'g')
form_num ++
new_form.innerHTML = new_form.innerHTML.replace(form_regex, `form-${form_num}-`)
container.insertBefore(new_form, add_button)
total_forms.setAttribute('value', `${form_num + 1}`)
}
{% endblock %}
I tried to run the server and complete the form with the name and description of the workout object without the javascript part of the template above, I still get the same error.
Sorry for the long post and the , I have been trying to narrow down my problem as much as I can before posting, but it seems I get nowhere.
You need to initialise the fields when you define them in your models, you are missing the parenthesis () from your model fields in the Cycle model
class Cycle(models.Model):
place_in_workout = models.IntegerField()
exercise = models.ManyToManyField(Exercise)
number_of_times = models.IntegerField()
reps = models.IntegerField()
break_inbetween = models.IntegerField()
workout = models.ManyToManyField(Workout)

KeyError 'image' formsets

It's my first time with formsets / images and this is my error:
KeyError at /houses/new/
'image'
This is my code:
models.py
class House(models.Model):
user = models.ForeignKey(User, related_name='houses', on_delete=models.CASCADE)
address = models.CharField(max_length=500)
type = models.CharField(default='House', max_length=100)
stories = models.IntegerField()
square_feet = models.IntegerField()
description = models.TextField()
# Class is for the houses images
class Image(models.Model):
house = models.ForeignKey(House, default=None, related_name="images", on_delete=models.CASCADE)
image = models.ImageField(verbose_name='image')
forms.py
# This is the blueprint for House forms
class AlbumForm(forms.ModelForm):
address = forms.CharField(label="Address:")
type = forms.CharField(label="Type of House (House, Condo, Cottage):")
stories = forms.IntegerField(label="House Stories:")
square_feet = forms.IntegerField(label='Square Feet:')
class Meta:
model = House
fields = ['address', 'type', 'stories', 'square_feet', 'description']
# This is the form for images
class ImageForm(forms.ModelForm):
image = forms.ImageField(label='Image')
class Meta:
model = Image
fields = ('image',)
views.py
def post_house(request):
ImageFormSet = modelformset_factory(Image, form=ImageForm, extra=10)
if request.method == 'POST':
house_form = AlbumForm(request.POST)
formset = ImageFormSet(request.POST, request.FILES, queryset=Image.objects.none())
if house_form.is_valid() and formset.is_valid():
post_form = house_form.save(commit=False)
post_form.user = request.user
post_form.save()
for form in formset.cleaned_data:
image = form['image']
photo = Image(house=post_form, image=image)
photo.save()
messages.success(request, "New house listing success")
house = post_form
return redirect('houses:details', house_id=house.pk)
else:
return render(request, 'login.html')
else:
house_form = AlbumForm()
formset = ImageFormSet(queryset=Image.objects.none())
return render(request, 'houses/house_form.html', {'house_form': house_form, 'formset': formset})
house_form.html
{% extends 'base.html' %}
{% block content %}
<br>
<div class="container">
<h4>Post a New Home</h4>
<form id="post_form" method="post" action="" enctype="multipart/form-data">
{% csrf_token %}
{{house_form}}
{{ formset.management_form }}
{% for form in formset %}
{{ form }} <br>
{% endfor %}
<input type="submit" name="submit" class="btn btn-success" value="Submit" />
</form>
</div>
{% endblock %}
It must be some relation between my form key and what each form in formset is taking. That being said they're both 'image' so I don't see the problem. Please let me know if you got an idea. Thanks a ton!
Try the below code,
if formset.is_valid():
for form in formset:
data = form.cleaned_data
image = data.get('image')
photo = Image(house=post_form, image=image)
photo.save()

Django add user to 'team'

I want the logged in user to be able to add users to a team they have created. At the moment I have created a form which lets the user select the user and the team they want to add them to, but they can select from every team in the database rather than just those they have created. Any ideas? These are my models, view and the form i have created. Also help with what to put in my HTML file would be appreciated.
Models:
class UserTeams(models.Model):
userID = models.ForeignKey(User,on_delete=models.CASCADE)
teamID = models.ForeignKey(Team,on_delete=models.CASCADE)
class Team(models.Model):
name = models.CharField(max_length=100)
venue = models.CharField(max_length=100)
countryID = models.ForeignKey(Countries, on_delete=models.CASCADE)
owner = models.ForeignKey(User)
View:
def invite(request):
if request.method == 'POST':
form = InvitePlayerForm(request.POST)
if form.is_valid():
userteam = form.save(commit=False)
userteam.save()
else:
form = InvitePlayerForm()
query = UserTeams.objects.all()
return render(request, 'teammanager/invite.html', {
"invite": query,
"form": form
})
Form:
class InvitePlayerForm(forms.ModelForm):
class Meta:
model = UserTeams
fields = ['userID','teamID']
HTML:
{% extends "teammanager/header.html" %}
{% block content %}
<html>
<body>
<h4>Invite players to your team</h4>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
</form>
{% endblock %}
Modify your form like so it will do the FK filter based on the userteam object.
class InvitePlayerForm(forms.ModelForm):
class Meta:
model = UserTeams
fields = ['userID','teamID']
def __init__(self,user,*args,**kwargs):
super(InvitePlayerForm,self ).__init__(*args,**kwargs)
self.fields['teamID'].queryset = Team.objects.filter(id__in = UserTeam.objects.filter(userID = user))

Show objects properly as choices in django forms choicefield

I am working on some kind of testing application. I have two models for tests and users answers:
class TestModel(AbstractDatetimeModel):
number = models.IntegerField(unique=True)
answer_1 = models.CharField(max_length=255)
answer_2 = models.CharField(max_length=255)
class AnswerModel(AbstractDatetimeModel):
ANSWERS = (
('1', 'A'),
('2', 'B')
)
candidate = models.ForeignKey(User)
question = models.ForeignKey(TestModel)
answer = models.CharField(max_length=1, choices=ANSWERS)
And I have a form, where candidate (user) can answer each question. To implement this I use a view formset_factory:
def communicative_test(request):
questions = TestModel.objects.all()
question_formset = formset_factory(form=TestForm, extra=questions.count())
question_formset = question_formset(initial=[{'candidate': request.user, 'question': x.number,
'answer_1': x.answer_1, 'answer_2': x.answer_2} for x in questions])
return render(request, 'testing/communicative.html', locals())
On a form I need to show ChoiceField, where choices should be data from fields answer_1 and answer_2. Here is this form:
class TestForm(forms.ModelForm):
answer_1 = forms.CharField()
answer_2 = forms.CharField()
VARIANTS = (
('answer_1', answer_1),
('answer_2', answer_2)
)
variants = forms.ChoiceField(choices=VARIANTS, widget=forms.RadioSelect())
class Meta:
model = TestAnswer
fields = '__all__'
Problem is that on a page these answers displays as radio buttons with following labels:
<django.forms.fields.CharField object at 0x7f36248ef5d0>
<django.forms.fields.CharField object at 0x7f36248ef650>
I need to display it properly.
Well, as #Anentropic mentioned, I was not on the right way.
And he is right, because I need to submit only answer A or B. But for user on the form I need to display text for these answers from Test model. So I wrote two templatetags for this.
class TestForm(forms.ModelForm):
class Meta:
model = TestAnswer
fields = '__all__'
def communicative_test(request):
questions = TestModel.objects.all()
QuestionFormSet = formset_factory(form=TestForm, max_num=questions.count())
formset = QuestionFormSet(initial=[{'candidate': request.user, 'question': x.number} for x in questions])
return render(request, 'testing/communicative.html', locals())
Two custom templatetags for each answer (A/B):
#register.filter(name='get_answer1')
def get_answer1(question):
try:
question = TestModel.objects.get(number=question)
answer = question.answer_1
except ObjectDoesNotExist:
answer = ''
return answer
#register.filter(name='get_answer2')
def get_answer2(question):
try:
question = TestModel.objects.get(number=question)
answer = question.answer_2
except ObjectDoesNotExist:
answer = ''
return answer
And template is:
{% load test_tags %}
<form id="communicative-test-form" method="post">
{% csrf_token %}
{{ question_formset.management_form }}
{% for form in question_formset.forms %}
{% crispy form %}
{{ form.id }}
<p>{{ form.question.value }}</p>
<p><label>
<input type=radio name="form-{{ form.question.value|add:"-1" }}-answer" id='id_form-{{ form.question.value|add:"-1" }}-answer' value="1">
{{ form.question.value|get_answer1 }}
</label></p>
<p><label>
<input type=radio name="form-{{ form.question.value|add:"-1" }}-answer" id='id_form-{{ form.question.value|add:"-1" }}-answer' value="2">
{{ form.question.value|get_answer2 }}
</label></p>
{% endfor %}
<div style="text-align: right;" class="col-md-12">
<button type="submit">Save</button>
</div>
</form>