I've been reading lots of questions like this on stackoverflow but none seem to work. All I want to do is make a filtered form dropdown. I'm not sure how do go about doing it. I get the error that main is not defined... but I'm sure that's because it's not initialized or something? I'm very confused lol.
My form code looks like this:
class AssignForm(ModelForm):
class Meta():
model = Address
fields = ['overseer','publisher', 'status']
def __init__(self, *args, **kwargs,):
super(AssignForm, self).__init__(*args, **kwargs)
self.fields['publisher'].queryset = Publisher.objects.filter(service_group=main)
Here is my View:
def assignment(request, pk_a):
assign = Address.objects.get(id=pk_a)
num = request.user.overseer.publisher_set.first()
main = num.service_group.id
print(main)
I would like to use the variable: main inside my form dropdown so I can limit the dropdown relative to the overseer. How can this be accomplished? Thanks!
form = AssignForm(main, request.POST, instance=assign)
context = {'form':form,}
return render(request, 'sms/assign.html', context )
Change your form to
class AssignForm(ModelForm):
class Meta():
model = Address
fields = ['overseer','publisher', 'status']
def __init__(self, main, *args, **kwargs,):
super(AssignForm, self).__init__(*args, **kwargs)
self.fields['publisher'].queryset = Publisher.objects.filter(service_group=main)
and change your Form instantiation in views to
form = AssignForm(main, request.POST, instance=assign)
Related
I'm using Django 4.0 and I'm trying to create a web app where the user selects a choice from a dropdown Django form. However, the choices will vary depending on the question and I want the form to be able to adapt to this.
This is what I have in forms.py:
class QuestionAnswerForm(forms.Form):
def __init__(self, q_id, *args, **kwargs):
self.q_id = q_id
super(QuestionAnswerForm, self).__init__(*args, **kwargs)
q_id = self.q_id # this line throws an error
question = Question.objects.get(pk=q_id)
choice = forms.ChoiceField(choices=get_choices(question))
However, I get the error: name 'self' not defined. I just want to know an easy way to pass the question id to the form so that the get_choices function can then return the choices that need to be displayed on the form.
In views.py, the start of my view for the question sets the form in this way:
def question_detail_view(request, q_id):
print(f"Question id is {q_id}")
form = QuestionAnswerForm(request.POST or None, q_id=q_id)
My question is: how do I access the q_id in the QuestionAnswerForm class?
I found out how to do it using Passing **kwargs to Django Form:
forms.py:
class QuestionAnswerForm(forms.Form):
def __init__(self, *args, **kwargs):
q_id = kwargs.pop('q_id')
super(QuestionAnswerForm, self).__init__(*args, **kwargs)
if q_id:
self.fields['choice'].choices = get_choices(Question.objects.get(pk=q_id))
choice = forms.ChoiceField()
views.py:
def question_detail_view(request, q_id):
form = QuestionAnswerForm(request.POST or None, q_id=q_id)
I believe one solution to this is that when creating your models:
Create question model
Create choice model and link it to a particular question
I am creating my form in Form.py like this:
class pdftabelModelForm(forms.ModelForm):
class Meta:
model = pdftabel_tool_
fields = ['apn', 'owner_name']
apn = forms.ModelChoiceField(queryset= Field.objects.values_list('name', flat=True), empty_label="(Choose field)")
owner_name = forms.ModelChoiceField(queryset= Field.objects.values_list('name', flat=True), empty_label="(Choose field)")
But due to some reasons like 'self' is not available in form.py. I can only access it in views.py. So I want to make it like
class FieldForm(ModelForm):
class Meta:
model = pdftabel_tool_
fields = (
'apn',
'owner_name',)
How can I make these fields as dropdown like I did in my forms.py?
Why are you set on doing it in views.py? forms.py is the appropriate place to do this.
Instead of redefining your fields, you should use the form's __init__ method to override the querysets for your fields, like so:
class pdftabelModelForm(forms.ModelForm):
class Meta:
model = pdftabel_tool_
fields = ['apn', 'owner_name']
def __init__(self, *args, **kwargs):
super(pdftabelModelForm, self).__init__(*args, **kwargs)
self.fields['apn'].queryset = X
self.fields['owner_name'].queryset = X
EDIT: if you need to pass extra parameters to your form, update the init method to this:
def __init__(self, *args, **kwargs):
self.layer_id = self.kwargs.pop('layer_id')
super(pdftabelModelForm, self).__init__(*args, **kwargs)
self.fields['apn'].queryset = X
self.fields['owner_name'].queryset = X
And when you initialize your form from views.py, pass the parameter:
form = pdftableModelForm(layer_id=X)
I have an issue with my Create view. I initialise it like this:
class OutputCreateView(LoginRequiredMixin, generic.CreateView):
template_name = 'rcapp/common_create_update.html'
form_class = OutputForm
model = Output
def get_context_data(self, **kwargs):
context = super(OutputCreateView, self).get_context_data(**kwargs)
# self.form_class.fields['activity_ref'].queryset = Activity.objects.filter(rc_ref=ResultsChain.objects.get(pk=self.kwargs['rc']).pk)
context['is_authenticated'] = self.request.user.is_authenticated
return context
def form_valid(self, form):
# code code code
return redirect("/portal/edit/" + str(self.kwargs['rc']) + "/#outputs-table")
I have a ForeignKey Field in my model and I wanted to filter options for current view.
My form is set like this:
class OutputForm(forms.ModelForm):
class Meta:
model = Output
fields = ['value', 'activity_ref']
widgets = {
'value': forms.Select(choices=(#Choises here
,), attrs={"onChange":'select_changed()', 'class':'selector'})
}
I need to change a queryset for the activity_ref field.
You can see a commented line in get_context_data, it's where I tried to do this. But it didn't work. How can I get what I need?
You need to pass the choices / queryset to your form.
in OutputCreateView
def get_form_kwargs(self, *args, **kwargs)
filter_key = self.kwargs['rc']).pk
return {'filter_key': key}
Like this, it will give an error in when your form gets created, because of the unexpected argument. To get around that and to make use of it, override the init method.
In your OutputForm
def __init__(self, *args, **kwargs)
kwargs.pop('filter_key')
super()._init__(*args, **kwargs)
self.fields['value'] = forms.Select(queryset=Activity.objects.filter(rc_ref=ResultsChain.objects.get(pk=self.kwargs['rc']).pk),
attrs={"onChange":'select_changed()', 'class':'selector'})
You don't need to set the widgets value, as it is being done in the init method.
I'm creating a view which loads differents forms according to an argument given using the getattr() function:
form = getattr(forms, service.form)
but in the form I need my username to filter my files, so I have this:
class MyForm(forms.Form):
filename = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple)
K = forms.CharField(label='K', max_length=1)
fullOut = forms.CharField(label='fullOut', max_length=1)
def __init__(self, *args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs)
self.user = kwargs.pop('user', None)
self.fields['filename'].queryset = userFile.objects.filter(self.user)
The problem is that I don't know how to pass the 'request.user' in my getattr() funtion. I know that if it was static it should be something like:
form = MyForm(user=request.user)
But I have tried somethings like:
form = getattr(forms, service.form, user=request.user)
And it doesn't work.I'm trying this but any idea of how list user files in a form will be welcomed.
Thanks in advance.
This doesn't have anything to do with you using getattr, the problem is in your __init__ method. You need to pop user before calling super().
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user', None)
super(MyForm, self).__init__(*args, **kwargs)
You should instantiate the form as you usually do:
form = MyForm(user=request.user)
It doesn't matter whether MyForm is declared in the same module:
class MyForm(forms.Form):
my_field = forms.CharField()
form = MyForm(user=request.user)
or if you get the form class dynamically using getattr
MyForm = getattr(forms, service.form)
form = MyForm(user=request.user)
Database:
Document has many Sections, Sections has many Comments
On each document page, there is a comment form that lets you pick the section (using a ModelChoiceField). The problem is that the ModelChoiceField will contain ALL sections for all documents.
So to limit them I do this:
class CommentForm(ModelForm):
def __init__(self, *args, **kwargs):
super(CommentForm, self).__init__(*args, **kwargs)
if self.instance:
logger.debug(self.instance.document_id) # Prints "None"
self.fields['section'].queryset = Section.objects.filter(document=self.instance.document)
# ^^^ Throws DoesNotExist as self.instance.document is None
and my view is just:
form = CommentForm()
How do I pass CommentForm a document id?
Edit: Tried in my view:
d = Document.objects.get(id=id)
c = Comment(d)
form = CommentForm(c)
but document_id is still None in CommentForm
You can pass the document id when initialising the form:
class CommentForm(ModelForm):
def __init__(self, doc_id=None, *args, **kwargs):
if doc_id:
self.fields['section'].queryset = Section.objects.filter(document__id=doc_id)
and in the view
def my_view(request):
...
doc = Document.objects(...)
form = CommentForm(doc_id = doc.id)
EDIT
I edited the second line of the view, which I think deals with your comment? (make doc.id) a keyword arguement