Unable to set form choices from view Django - django

I learned how to do this from Django Form ChoiceField set choices in View in Form initial
However it doesn't seem to work correctly, choices are not given
view:
form_class = AskMCQuestionForm()
mc_choices = []
if question.One:
mc_choices.append(tuple((1, question.One)))
if question.Two:
mc_choices.append(tuple((2, question.Two)))
if question.Three:
mc_choices.append(tuple((3, question.Three)))
if question.Four:
mc_choices.append(tuple((4, question.Four)))
if question.Five:
mc_choices.append(tuple((5, question.Five)))
mc_choices = tuple(mc_choices)
print(mc_choices)
form_class.fields['user_answer'].choices = mc_choices
form_class.fields['assignment'].initial = assignment
form_class.fields['exam'].initial = question.exam
form_class.fields['correct_answer'].initial = question.correct_answer
form_class.fields['text'].initial = question.text
print("About to render page for MC question")
return render(request, 'Exam/ask_question.html', {'question': question, 'form': form_class})
form:
class AskMCQuestionForm(forms.ModelForm):
class Meta:
model = MC_Question
fields = ('text', 'user_answer', 'assignment', 'correct_answer', 'exam',)
widgets = {
'text': forms.TextInput(attrs={'class': 'form-control', 'readonly': True}),
'user_answer': forms.Select(attrs={'class': 'form-control'}),
'assignment': forms.Select(attrs={'class': 'form-control'}),
'correct_answer': forms.HiddenInput(),
'exam': forms.HiddenInput(),
}
model:
class MC_Question(models.Model):
One = models.CharField(max_length=200)
Two = models.CharField(max_length=200)
Three = models.CharField(max_length=200, blank=True, null=True)
Four = models.CharField(max_length=200, blank=True, null=True)
Five = models.CharField(max_length=200, blank=True, null=True)
class Answers(models.IntegerChoices):
one = 1
two = 2
three = 3
four = 4
five = 5
text = models.CharField(max_length=200)
correct_answer = models.IntegerField(choices=Answers.choices, blank=True, null=True)
user_answer = models.CharField(max_length=200)
exam = models.ForeignKey(Test, on_delete=models.CASCADE)
assignment = models.ForeignKey(Assignment, on_delete=models.CASCADE, blank=True, null=True)
question is an object of MC_Question, the same as what the form is creating.
Apologies if I have left out an important detail, it's been several years since I posted on stackoverflow

By default the model form creates a TextInput to work with the user_answer field (is a models.CharField without choices), and the TextInput field does not know what to do with the choices argument.
You can try to assing the choices directly to the widget:
form_class.fields['user_answer'].widget.choices = mc_choices
Or add a custom field to your model form:
class AskMCQuestionForm(forms.ModelForm):
user_answer = forms.ChoiceField(...)

Related

Django | Decimal Field is required even tho i set it to NULL=True

im trying to play a little bit around with django but i have run into problems...
I have a Decimal Field which is not required so i set it to "blank=True" and "null=True". But it still says its required :(
I also did all the migrations.
Here is my models.py
from django.db import models
weightUnit = {
('kg' , 'kilogram'),
('g', 'gram'),
('t', 'tons'),
('n', '-'),
}
class Product(models.Model):
pname = models.CharField(
max_length=50,
)
pdesc = models.TextField(
max_length=5000,
)
pprice = models.DecimalField(
max_digits=6,
decimal_places=2,
)
psn = models.CharField(
max_length = 30,
null=True,
blank=True,
)
pweightunit = models.CharField(
choices=weightUnit,
default='n',
null=True,
blank=True,
max_length=5,
)
pweight = models.DecimalField(
null=True,
blank = True,
max_digits=10000,
decimal_places=2,
)
plimage = models.ImageField(
blank=True,
null=True,
)
Here is my forms.py
from django import forms
from .models import weightUnit
class RawProductForm(forms.Form):
name = forms.CharField(label="Name")
desc = forms.CharField(label="Beschreibung")
price = forms.DecimalField(label="Stückpreis")
sn = forms.CharField(label="Seriennummer")
weightunit = forms.ChoiceField(choices=weightUnit, label="Gewichteinheit")
weight = forms.DecimalField(label="Gewicht")
image = forms.ImageField(label="Bild")
Here is my views.py
def product_add(request):
pf = RawProductForm()
if request.method == "POST":
pf = RawProductForm(request.POST)
if pf.is_valid():
print(pf.cleaned_data)
Product.objects.create(**pf.cleaned_data)
else:
print(pf.errors)
context = {
"productform" : pf,
}
return render(request, "product_add.html", context)
You are working with a simple Form, not a ModelForm [Django-doc], so that means that it will not inspect the model at all. It will simply render a form. A ModelForm will inspect the model and construct a form based on that that you can customize.
class RawProductForm(forms.ModelForm):
class Meta:
model = Product
labels = {
'name': 'Name',
'desc': 'Beschreibung',
'price': 'Stückpreis',
'sn': 'Seriennummer',
'weightunit': 'Gewichteinheit',
'weight': 'Gewicht',
'image': 'Bild',
}
A ModelForm also has a .save(…) method [Django-doc] which creates a model object based on the data in the form and saves it to the database.

django - How can I prefill formset forms data using database query result?

I am creating a student attendance form where need to get details of student name, student class and Id from student model based on teacher selecting student class in one form. I have tried using initial by using for loop on query data to prefill the form in formset, however it populates data for one record only. Below is the code for forms.py, models and views.py. Can someone help on this
forms.py
class student(models.Model):
studentid = models.AutoField(primary_key=True)
Gender = models.CharField(max_length=6, choices=gender, null=True)
Name = models.CharField(max_length=100, null=True)
DOB = models.DateField(null=True)
Image = models.ImageField(null=True, upload_to='images')
Status = models.CharField(max_length=10, choices=statchoice, null=True)
Father_name = models.CharField(max_length=100, null=True)
Mother_name = models.CharField(max_length=100, null=True)
Address = models.CharField(max_length=200, null=True)
Contact_no = models.IntegerField(null=True)
Email = models.EmailField(null=True)
Admission_class = models.CharField(max_length=40, null=True, choices=grade)
Admission_date = models.DateField(null=True)
Current_class = models.CharField(max_length=40, null=True, choices=grade)
Leaving_date = models.DateField(null=True, blank=True)
objects = models.Manager()
def __str__(self):
return str(self.studentid)
class student_attendance(models.Model):
Student_ID = models.CharField(max_length=100, null=True)
Student_Name = models.CharField(max_length=100, null=True)
Student_class = models.CharField(max_length=100, null=True, choices=grade)
Attendance_date = models.DateField(null=True, auto_now_add=True, blank=True)
Attendance_status = models.CharField(choices=attendance, null=True, max_length=10)
objects = models.Manager()
Views.py
def student_attend(request):
if request.method == 'POST':
data = request.POST.get('studentGrade')
formset_data = student.objects.filter(Current_class=data)
AttendanceFormSet = formset_factory(std_attendance, extra=(len(formset_data))-1)
for element in formset_data:
formset = AttendanceFormSet(initial=[
{'Student_ID': element.studentid, 'Student_Name':element.Name, 'Student_class':element.Current_class, 'Attendance_status':"Present"}
])
param = {'formset':formset}
return render(request, 'home/student_attendance.html', param)
return render(request, 'home/student_attendance.html')
form.py:
class student_register(ModelForm):
class Meta:
model = student
fields = '__all__'
class std_attendance(ModelForm):
class Meta:
model = student_attendance
fields = '__all__'
Each iteration in your loop you override the formset, that is why only a single form is filled, you need to fill the param with all the forms inside the loop this way:
initial = []
for element in formset_data:
initial.append({'Student_ID': element.studentid, 'Student_Name':element.Name, 'Student_class':element.Current_class, 'Attendance_status':"Present"}
formset = AttendanceFormSet(initial=initial)

The label in Django Forms doesn't change its name

I am trying to change my label in Forms. But despite trying, I can't get a label change for consumer field. I also don't see a typo made by me.
models.py
class Offer(models.Model):
owner = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
customer = models.ForeignKey(Customer, on_delete=models.CASCADE, verbose_name='Klient')
seller = models.ForeignKey(Seller, on_delete=models.CASCADE, verbose_name='Sprzedawca')
vat = models.ForeignKey(Vat, on_delete=models.CASCADE, verbose_name='Stawka VAT')
annual_usage_kw = models.DecimalField(max_digits=8, decimal_places=2, blank=True, null=True, verbose_name='Roczne zużycie KW')
monthly_usage_kwh = models.DecimalField(max_digits=8, decimal_places=2, blank=True, null=True, verbose_name='Miesięczne zużycie KWH')
monthly_usage_zl = models.DecimalField(max_digits=8, decimal_places=2, blank=True, null=True, verbose_name='Miesieczne zużycie PLN')
excepted_power = models.DecimalField(max_digits=8, decimal_places=2, blank=True, null=True, verbose_name='Oczekiwana moc KW')
roof_orientation = models.ForeignKey(RoofConstruction, on_delete=models.CASCADE, verbose_name='Konstrukcja dachu')
price_per_kw = models.ForeignKey(PricePerKw, on_delete=models.CASCADE, verbose_name='Cena za KW')
product = models.ManyToManyField(Product, verbose_name='Produkt')
inverter = models.ManyToManyField(Inverter, blank=True, verbose_name='Inverter')
number_of_product = models.IntegerField(blank=True, null=True, verbose_name='Liczba produktów (opcjonalnie)')
employer_margin_price = models.IntegerField(blank=True, null=True, verbose_name='Marża cenowa pracownika')
accessories = models.ManyToManyField(Accesorie, blank=True, verbose_name='Akcesoria')
forms.py
class OfferParametersForm(forms.ModelForm):
class Meta:
model = Offer
fields = ('customer', 'vat', 'annual_usage_kw', 'monthly_usage_kwh', 'monthly_usage_zl', 'excepted_power',
'roof_orientation', 'price_per_kw')
labels = {'customer': 'Klient',
'vat': 'VAT',
'annual_usage_kw': 'Roczne zużycie KW',
'monthly_usage_kwh': 'Miesięczne zużycie KWH',
'monthly_usage_zl': 'Miesieczne zużycie PLN',
'excepted_power': 'Oczekiwana moc KW',
'roof_orientation': 'Konstrukcja dachu',
'price_per_kw': 'Cena za KW',
}
I use my form as method {{ form.as_p }}. I guess I might be making some stupid mistakes. But I don't see the wrong setting and my label is still costumer instead of klient. How to change costumer label to klient.
views.py
def parameters(request):
#basic
step = 2
step_percentages = 33
template_name = 'Nowa oferta'
object_id = request.session.get('costumer_id')
#form
OfferParametersForm.base_fields['customer'] = forms.ModelChoiceField(queryset=Customer.objects.filter(owner=request.user))
if request.method == 'POST':
form = OfferParametersForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
qd = QueryDict(mutable=True)
qd.update(customer=cd['customer'], vat=cd['vat'], annual_usage_kw=cd['annual_usage_kw'],
monthly_usage_kwh=cd['monthly_usage_kwh'], monthly_usage_zl=cd['monthly_usage_zl'],
excepted_power=cd['excepted_power'], roof_orientation=cd['roof_orientation'],
price_per_kw=cd['price_per_kw'])
return HttpResponseRedirect(
'{}?{}'.format(reverse('app:products'), qd.urlencode())
)
else:
form = OfferParametersForm(initial={'customer': object_id,
'vat': 1})
context = {'step': step,
'step_percentages': step_percentages,
'template_name': template_name,
'form': form}
return render(request, 'app/parameters.html', context)

Ways to change dropdown choices in django-filter

I'm trying to change the dropdown values for the user field. I want to show the email addreses , instead of the nombre + apellido. Because in my models I have the str that returns nombre + apellido, those are the values displayed in the dropdown. How can I change those values without changing the str in the Tutor model? Tryed to do a CustomManager but didn't work.
MODEL:
class Tutor(models.Model):
user = models.OneToOneField(
User, on_delete=models.CASCADE, primary_key=True)
nombre = models.CharField(max_length=50, blank=False, null=True)
apellido = models.CharField(max_length=50, blank=False, null=True)
biografia = models.TextField()
curriculum = models.FileField(upload_to="curriculums/", blank=True, null=True)
foto = models.ImageField(blank=True, null=True)
carrera = models.ManyToManyField(Carrera, blank=True)
linea_invest = models.ManyToManyField(Linea_Invest, blank=True)
correo = models.EmailField(blank=True, null=True)
numero_celular = models.CharField(max_length=20, blank=True, null=True)
class Meta:
verbose_name_plural = "Tutores"
verbose_name = "Tutor"
def __str__(self):
return '%s %s' % (self.nombre, self.apellido)
FILTER
class TutorFilter(django_filters.FilterSet):
nombre = CharFilter(field_name="nombre", label="Nombre",lookup_expr='icontains')
apellido = CharFilter(field_name="apellido", label="Apellido",lookup_expr='icontains')
carrera = ModelMultipleChoiceFilter(field_name= "carrera", queryset= Carrera.objects.all())
user = ModelChoiceFilter(field_name = "user", label = "correo", queryset = Tutor.objects.all())
class Meta:
model = Tutor
fields = ("nombre", "apellido", "carrera","user")
In your TutorFilter. Change
user = ModelChoiceFilter(field_name = "user", label = "correo", queryset = user.objects.all())
How I solved:
def get_tutores():
tutores = []
for tut in Tutor.objects.all():
tutores.append((tut.user.id,tut.user.email,))
return tutores
class TutorFilter(django_filters.FilterSet):
nombre = CharFilter(field_name="nombre", label="Nombre",lookup_expr='icontains')
apellido = CharFilter(field_name="apellido", label="Apellido",lookup_expr='icontains')
carrera = ModelMultipleChoiceFilter(field_name= "carrera", queryset= Carrera.objects.all())
user = ChoiceFilter( label = "correo", choices=get_tutores())
class Meta:
model = Tutor
fields = ("nombre", "apellido", "carrera","user")
See how I didn't need to change the str method in the model Tutor to display in the dropdown the tutor's emails as choices, because instead of using ModelChoiceFilter I changed to ChoiceFilter . Didn't know that you can call a function in the choices argument in the ChoiceFilter.

How can I toggle a form having prefilled content with an edit button in django

I have a form that users can fill to leave a review. On the same page, the reviews are displayed with a button to edit the review. When the edit button is clicked, I would like for the form to be pre-filled with the appropriate review data, so that it can be edited and updated in the database.
models
class Clinic(models.Model):
practitioner = models.OneToOneField(User, on_delete=models.CASCADE)
lat = models.FloatField(null=True, blank=True)
lng = models.FloatField(null=True, blank=True)
web = models.CharField(null=True, blank=True, max_length=128)
name = models.CharField(max_length=128, )
phone = PhoneNumberField()
description = models.TextField(max_length=5000)
street = models.CharField(max_length=128, )
city = models.CharField(max_length=128, )
def __str__(self):
return self.name
def save(self):
super().save()
class Reviews(models.Model):
title = models.CharField(max_length=128)
body = models.TextField(max_length=500)
author = models.ForeignKey(User, on_delete=models.CASCADE)
clinic = models.ForeignKey(Clinic,
null=True,
blank=True,
on_delete=models.CASCADE)
Form
class ReviewForm(forms.ModelForm):
class Meta:
model = Reviews
fields = (
'title',
'body',
)
View
def clinic_profile(request, clinic_id):
clinic = Clinic.objects.filter(pk=clinic_id)
form = ReviewForm(request.POST)
if request.method == 'POST':
if form.is_valid():
r_clinic = Clinic.objects.get(pk=clinic_id)
title = form.cleaned_data.get("title")
body = form.cleaned_data.get("body")
review = Reviews(title=title,
body=body,
author=request.user,
clinic=r_clinic)
review.save()
messages.success(request, f'Thank you for leaving a review!')
clinic_reviews = Reviews.objects.filter(clinic=clinic_id)
latlng = {
"lat": clinic[0].lat,
"lng": clinic[0].lng,
"name": clinic[0].name
}
def get_mods():
profile = Profile.objects.filter(user=Clinic.objects.get(
pk=clinic_id).practitioner)
mods = profile[0].mods.all().values('name') if profile else []
mods = [(q['name']) for q in mods]
return mods
return render(
request, 'clinic_profile.html', {
'clinic': clinic,
'mods': get_mods,
'latlng': latlng,
'api_key': api_key,
'reviews': clinic_reviews,
'form': form,
})
Screenshot