Filling a choice field with objects from a query - python

I have a ModelForm, which I'm trying to have a dynamic select in it.
My ModelForm in forms.py:
class AuxiForm(forms.ModelForm):
class Meta:
model = Auxi
fields = ["tipAux"]
widgets = {
'tipAux': forms.Select(attrs={'class': 'form-control', 'placeholder': 'Tipo'}),
}
labels = {
'tipAux': 'Tipo',
}
and I want to have a choicefield which should be dynamic, filling itself by a query from an other class called TipoAux.
TipoAux in models.py:
class TipoAux(models.Model):
denom = models.CharField(max_length=30, null=True)
def __str__(self): # Python 3
return self.denom
Conclusion: I'm my form I should have a dynamic select which collects its options from TipoAux class
Like this:
Options = (
(1, 'First option',
(2, 'Second option',
)
But getting its options from my DB, and not having to add them manually.

To have this structure you should follow and do the next steps:
Create a Model called TipoAux:
class TipoAux(models.Model):
denom = models.CharField(max_length=50)
def __str__(self):
return self.name
Then immediately run migrate since the other table will depend on this (if you do not have this table yet).
Then create the other things like the other Model (this is what you are actually most interested in with your question):
class Auxi(models.Model):
# we get the TipoAux choice values from the TipoAux table and creating a list of that
all_tipoaux = TipoAux.objects.values()
TIPAUX_CHOICES = [(d['id'], d['denom']) for d in all_tipoaux]
tipAux = models.IntegerField(choices=TIPAUX_CHOICES, null=True, verbose_name='Tipo')
Then your Form (first just make it simple, do not use select widget and label yet, since it’s automatically created due to the model):
from .models import Auxi
class AuxiForm(forms.ModelForm):
class Meta:
model = Auxi
fields = ["tipAux"]
Then your view something like this:
from django.shortcuts import render, redirect
from django.http import HttpResponseRedirect, HttpResponse, HttpRequest
from django.urls import reverse
from .forms import AuxiForm
from .models import Auxi
def tipo(request):
if request.method == 'POST':
form = AuxiForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('myappname:index'))
else:
form = AuxiForm()
return render(request, 'myappname/auxiform.html', {'form': form})
You have to run migration again to create the Auxi table
Then you will just create a url path to the view in urls.py and do not forget to register your models in the admin.py.
from .models import TipoAux, Auxi
admin.site.register(TipoAux)
admin.site.register(Auxi)
Then you have to go to your admin page of your site and create some items in the TipoAux table for having some option values.
And this is the visual end result of the above (recorded my results in gif):
I hope this will be in help of you. Cheers. ;)

Related

Django Forms - How would I implement a form that dynamically changes its fields depending on model objects in the database?

I have 3 models :
from django.db import models
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
pass
class Certification(models.Model):
def __str__(self):
return f'{self.name}'
name = models.CharField(max_length=30)
shortName = models.CharField(max_length=10)
score = models.IntegerField(null=True, blank=True)
class ActiveCertification(models.Model):
def __str__(self):
return f'{self.user} | {self.sensor}'
user = models.ForeignKey(User, on_delete=models.CASCADE)
certification = models.ForeignKey(Certification, on_delete=models.CASCADE)
value = models.BooleanField()
In my database, there are a few different Certification objects, but there is bound to be more in the future.
My ActiveCertification model is used to identify which user has which certification.
Now, the problem I am facing is that I wish that each user could fill out which certifications they have in a form. I basically need the form to look like this :
Certification 1 [ ]
Certification 2 [ ]
Certification 3 [ ]
Certification 4 [ ]
ect...
[ Submit ]
([ ] representing a checkbox)
Basically, I need that when user A uses this form, he checks the certifications he has, and that upon submitting, the ActiveCertification table would fill/update the userA/certification pairs.
At first, I started doing a form like this :
from django import forms
class ActiveCertificationForm(forms.Form):
certification1 = forms.BooleanField(required=False)
certification2 = forms.BooleanField(required=False)
certification3 = forms.BooleanField(required=False)
certification4 = forms.BooleanField(required=False)
But quickly realized that this is a terrible solution, as when new certifications would be added to the database, the form wouldn't automatically update.
I tried looking in the Django documentation for help, and tried to implement the form with the ModelChoiceField field, but it doesn't really work, as it produces a dropdown list, and I need a checkbox list.
Any help would be greatly appreciated. Thanks in advance !
There are two possibilities:
model formsets and using a forms.ModelMultipleChoiceField with a CheckBoxSelectMultiple widget.
formsets
forms.py:
from django.forms import modelformset_factory
from yourapp.models import ActiveCertification
ActiveCertificationFormSet = modelformset_factory(ActiveCertification, fields=('certification', 'value',))
views.py
from django.shortcuts import render
from yourapp.forms import ActiveCertificationFormSet
from yourapp.models import ActiveCertification
def your_view(request, *args, **kwargs):
active_certs = ActiveCertivication.objects.filter(user=request.user)
context = {
'certification_formset': ActiveCertificationFormSet(
queryset=active_certs,
),
}
return render(request, 'certification_template.html', context)
ModelMultipleChoiceField
from django import forms
class CertificationForm(forms.Form):
certifications = forms.ModelMultipleChoiceField(
widget=forms.CheckBoxSelectMultiple(),
)
See the respective documentation linked above for more details.

Django ModelForm fails to save "many to many" records using ModelForm and save_m2m

I am new to Django and using this project to learn it. I am able to save the Journal record but the many to many relationship does not work.
This 'create' view displays the correct form including the multi-select box with all of the cryptos listed (from Crypto model). When submitting the form the many-to-many records do not save but the Journal saves fine.
I have found a bunch of different answers to this, some are for python 2.7, but this is the simplest method based on the [Django documentation][1]. Any help is greatly appreciated.
Also, the relationship works fine in the Admin section, so I am thinking it has something to do with the Forms and/or the View & saving.
models.py
from django.db import models
from crypto.models import Crypto as CryptoModel
class Journal(models.Model):
title = models.CharField(max_length=200, help_text='Journal Title', blank=False, null=False)
content = models.TextField(max_length=2000, help_text='Journal Content (HTML OK)', blank=False, null=False)
crypto_id = models.ManyToManyField(CryptoModel, blank=True)
created = models.DateTimeField(help_text='Created', auto_now_add=True, null=True)
def __str__(self):
return self.title ## String for representing the Model object, usually name field or title
forms.py
from django.forms import ModelForm, ModelMultipleChoiceField, widgets
from journal.models import Journal as JournalModel
from crypto.models import Crypto as CryptoModel
class JournalForm(ModelForm):
# select multiple items box
cryptos = ModelMultipleChoiceField(widget=widgets.SelectMultiple(attrs={'size': 30}), queryset=CryptoModel.objects.all())
class Meta:
model = JournalModel
fields = [
"title",
"content",
]
labels = {
'title': 'Journal Title',
}
required = [
"title", # same as model
"content", # same as model
]
views.py
from journal.forms import JournalForm
from django.utils import timezone
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render, redirect, get_object_or_404
from journal.models import Journal as JournalModel
def Create(request):
if request.method == "POST":
form = JournalForm(request.POST) # form instance
context = {'form': form} # if errors, keep the form data on next page load
journal = form.save(commit=False) # False needed for many-to-many
journal.title = form.cleaned_data["title"]
journal.content = form.cleaned_data["content"]
journal.created = timezone.now()
journal.save() # save the form journal data, now we have a PK
form.save_m2m() # save the 'form' using ManytoMany method
return HttpResponseRedirect('/journal/')
form = JournalForm()
context = {'form': form}
return render(request, 'journal/create.html', context)
models.py 2
from django.db import models
from crypto.models import Crypto
class Journal(models.Model):
title = models.CharField(max_length=200, help_text='Journal Title', blank=False, null=False)
content = models.TextField(max_length=2000, help_text='Journal Content (HTML OK)', blank=False, null=False)
crypto_id = models.ManyToManyField(Crypto, blank=True)
created = models.DateTimeField(help_text='Created', auto_now_add=True, null=True)
def __str__(self):
return self.title ## String for representing the Model object, usually name field or title
forms.py 2
from django.forms import ModelForm, ModelMultipleChoiceField, widgets
from journal.models import Journal
from crypto.models import Crypto
class JournalForm(ModelForm):
# select multiple items box
cryptos = ModelMultipleChoiceField(widget=widgets.SelectMultiple(attrs={'size': 30}), queryset=Crypto.objects.all())
class Meta:
model = JournalModel
fields = [
"title",
"content",
"cryptos",
]
views.py 2
from journal.forms import JournalForm
from django.utils import timezone
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render, redirect, get_object_or_404
from journal.models import Journal
def Create(request):
if request.method == "POST":
form = JournalForm(request.POST) # form instance
context = {'form': form} # if errors, keep the form data on next page load
journal = form.save(commit=False) # False needed for many-to-many
journal.created = timezone.now()
journal.save() # save the form journal data, now we have a PK
journal.crypto_id.set(form.cleaned_data.get("cryptos")) # must be after "save"
form.save_m2m() # save the 'form' using ManytoMany method
return HttpResponseRedirect('/journal/')
form = JournalForm()
context = {'form': form}
return render(request, 'journal/create.html', context)
hope this solve your problem just but this line after save your journal instance
journal.crypto_id.set(form.cleaned_data.get("cryptos"))
You've called your model and form fields different things; Django can't know they relate to the same field. The form name - crypos - is the correct one, you should rename your model field to that.
Also, you haven't specified the field in the fields list, so Django won't even try to set it on the model.
Note that in your view you don't need to set title or content, that's what form.save does for you already.
Thank you abdullah, adding "journal.crypto_id.set(form.cleaned_data.get("cryptos"))" to the VIEW fixed the issue.
An additional note is that this must be places after the 'journal' form is saved but before the many to many is saved.
I updated the "models.py 2", "forms.py 2" and "views.py 2" section above. This is the working code.
you are always welcome.
yes but it after journal.save().
and set don't need to call save() from form.

Django Modelform doesn't accept selection on POST

The dropdown list appears correctly in the html, However I am unable to figure out why I run into the same error time after time when I try to submit / .
"Select a valid choice. That choice is not one of the available choices."
the problem context
I have two models defined in Django. One CourseModel database to hold all the offered courses and one registration database to link a course to a user.
models.py
from django.db import models
# Create your models here.
class CourseModel(models.Model):
course = models.CharField(max_length=100)
date = models.DateField(max_length=100)
time = models.TimeField()
location = models.CharField(max_length=100)
datetime = models.DateTimeField()
class RegistrationModel(models.Model):
name = models.CharField(max_length=100)
adress = models.CharField(max_length=100)
city = models.CharField(max_length=100)
email = models.EmailField(max_length=100)
course = models.ForeignKey('self', on_delete=models.CASCADE)
def __str__(self):
return self.name
I use modelForm to create a registration form, where the user can subscribe for a course from a dropdown list.
forms.py
from django.forms import ModelForm, RegexField
from home.models import RegistrationModel, CourseModel
from django import forms
import datetime
class RegistrationForm(ModelForm):
def __init__(self, *args, **kwargs):
super(RegistrationForm, self).__init__(*args, **kwargs)
self.fields['course'].queryset = CourseModel.objects.exclude(date__lt=datetime.datetime.today()).values_list('datetime', flat=True)
self.fields['course'].empty_label = None
class Meta:
model = RegistrationModel
fields = '__all__'
views.py
from django.shortcuts import render, redirect
from home.forms import RegistrationForm
from .models import CourseModel
import datetime
def home(request):
return render(request, 'home/home.html')
def registration(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
crs = request.POST.get('course')
print(crs)
if form.is_valid():
cleanform = form.save(commit=False)
cleanform.course = crs
cleanform.save()
return redirect('home')
else:
form = RegistrationForm()
return render(request, 'home/registration.html', {'form': form})
In the RegistrationForm's __init__() method, your self.fields['course'].queryset = ...values_list('datetime', flat=True) returns datetime instances. See values_list() docs.
I believe this may cause the issue. I guess the queryset should return CourseModel instances, based on the Django docs:
ForeignKey is represented by django.forms.ModelChoiceField, which is a ChoiceField whose choices are a model QuerySet.
Also, your RegistrationModel.course field has a foreign key to 'self' instead of the CourseModel. Not sure if that is what you want.
Other examples of setting the field queryset can be found here.

Django form not selecting options

I have a django project, in the project i have a django forms.py which contain a field call category which select box input element that is generated as a result of a query on the database.
If I choose an option from the select dropdown from the database I keep getting the error:
**strong text**Select a valid choice. That choice is not one of the available choices
Below is the code:
Forms.py
from django import forms
#from django.contrib.auth.models import User
from signer.models import CreateSingleSigner
class CreateSingleSignerForm(forms.ModelForm):
category = forms.ModelChoiceField(
required = True,
help_text = 'category',
queryset=CreateSingleSigner.objects.all().values_list(
'category', flat=True
).distinct()
)
my views.
from django.shortcuts import render
from django.http import HttpResponse, HttpResponseRedirect
from signer.models import CreateSingleSigner
from signer.forms import CreateSingleSignerForm
from django.template import RequestContext
def singlesigner(request):
context = {}
if request.method == 'POST':
createsinglesigner_form = CreateSingleSignerForm(data=request.POST)
if createsinglesigner_form.is_valid():
createsinglesigner.category = request.POST['category']
createsinglesigner_form.save()
else:
print createsinglesigner_form.errors
else:
# context['createsinglesigner'] = CreateSingleSigner()
createsinglesigner_form =CreateSingleSignerForm()
return render(request, "signer/singlesigner.html", {"createsinglesigner_form":createsinglesigner_form}, RequestContext(request))
my models.py
from django.db import models
class CreateSingleSigner(models.Model):
category = models.CharField(max_length = 32)
Can someone tell me where I am going wrong?
Try one of ways below to fix problem:
Try to define conversion of unicode in your CreateSingleSigner model:
class CreateSingleSignerForm(forms.Form):
def __unicode__(self):
return self. category
Explanations:
ModelChoiceField will use __unicode__ representation of specified fields for displaying and validating your fields.
Try to set choices in __init__ method of your form
class CreateSingleSignerForm(forms.Form):
category = forms.ChoiceField(choices=[], required=False)
def __init__(self, *args, **kwargs):
super(CreateSingleSignerForm, self).__init__(*args, **kwargs)
self.fields['category'].choices = CreateSingleSigner.objects.all().values_list('category', flat=True).distinct()
Explanations: The queryset parameter for ModelChoiceField cannot be values_list, because it's going to save the relationships, so django have to use complete model objects, not certain values of model objects.

How to get information from one Django models object?

today I'm trying to get and print all my users emails, who had chose selection "Value1".
This is how my model.py looks like:
from django.db import models
class Vartotojas(models.Model):
email = models.EmailField()
option = models.CharField(max_length=30)
Forms.py :
from django import forms
from emailai.models import Vartotojas
class VartotojasForm(forms.Form):
email = forms.EmailField(max_length=100)
my_field = forms.MultipleChoiceField(choices=(('Value1','Value1'),('Value2','Value2')), widget=forms.CheckboxSelectMultiple())
def save(self):
mymodel = Vartotojas(
email=self.cleaned_data['email'],
option=self.cleaned_data['my_field'],
)
mymodel.save()
And finally my views.py "
from django.shortcuts import render
from django.http import HttpResponse
from django.http import HttpResponseRedirect
from emailai.models import Vartotojas
from renginiai.forms import VartotojasForm
def name(request):
if request.method == 'POST':
form = VartotojasForm(request.POST)
if form.is_valid():
a = Vartotojas.objects.filter(option="u'Value1'") # How to do it right?
# Now How To Get those object emails?
new_user = form.save()
return render(request, "Vartotojas-result.html", {
'form': form, #BLABLABLA,
})
else:
form = VartotojasForm()
return render(request, "Vartotojas-form.html", {
'form': form,
})
I commented my questions inside my views.py. I hope you will be able to help me. Thank you in advance!
I re-write my code with getlist. Now it looks like this:
views.py :
if form.is_valid():
email = form.cleaned_data['email']
option = request.POST.getlist('my_field')
new_user = form.save(email, option)
forms.py:
email = forms.EmailField(max_length=100)
my_field = forms.MultipleChoiceField(choices=(('Value1','Value1'),('Value2','Value2')), widget=forms.CheckboxSelectMultiple())
def save(self, email, option):
mymodel = Vartotojas(
email=email,
option = option,
)
mymodel.save()
As you see I pasted just most important places. By the way, users can choose 2 values, that's why I use checkbox. But still it not working.
I believe you want to use the values_list property like so:
Vartotojas.objects.filter(option=u"Value1").values_list("email", flat=True)
to get a list of all email addresses. You may also want to apply a distinct() to that if you're not already preventing duplicates. On a side note, look into ModelForms: it looks like that would save you a fair bit of the time/ code you have written for dealing with this. You could create a ModelForm based on your Vartotojas object and not have to write the explicit save() method you have.

Categories