I have some models classes. And some classes have bounding fields with another class. Each class have the field - author. I whould like that for each user the form bounding field shows only those data which was created these authors.
For example:
class “TypeJob” has field “author”.
User Jhon created a TypJob - “Painting”.
User Alex created a TypJob - “Cleaning”.
Class “Order” has bounding field - “name_typ_job”
When Jhon whould like create an order, he opens the form and click “name type job” field, he sees both type job: painting and cleaning.
I whould like that he sees and could choose only “painting”. Because he is it author.
Django 3
In your form you would define a queryset for the field that would filter the selections based upon your criteria.
See the queryset option in the ModelChoiceField.
Thank you for your answer!
But I don’t understand what exactly I should do. Please could you help me?
I wrote that
class OrderTestForm(forms.ModelForm):
class Meta:
model = Order
name_job = forms.ModelChoiceField(queryset=None)
qs = TypJob.objects.filter(author__id=user.id)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['name_job'].queryset = qs
But I have
name ‘user’ is not defined
name ‘author__id’ is not defined
I will also need to see the view that is using this form.
The form itself isn’t going to have all the information you need. You will need to pass the user object from the request object in the view into the form when you’re creating your instance of that form.
But in general, you’re on the right track.
Your view is, in part, going to look like this (if you’re using a function-based view instead of a class-based view):
def my_view(request):
...
form = MyForm(current_user=request.user)
...
Then your form would (in part) look something like this:
class MyForm(ModelForm):
class Meta:
model = MyModel
fields = ['a_field', 'another_field']
a_field = forms.ModelChoiceField(queryset=None)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['a_field'].queryset = MyOtherModel.objects.filter(user=kwargs['current_user'])
views.py
class OrderNewBigPrintView(LoginRequiredMixin, CustomSuccessMessageMixin, CreateView):
model = Order
template_name = 'new_order_bp.html'
form_class = OrderForm
success_url = reverse_lazy('orders')
success_msg = 'Ok'
def post(self, request, *args, **kwargs):
form = self.get_form(current_user=request.user)
forms.py
class OrderForm(forms.ModelForm):
class Meta:
model = Order
fields = '__all__'
name_job = forms.ModelMultipleChoiceField(queryset=None)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
qs = TypJob.objects.filter(user=kwargs['current_user'])
self.fields['name_job'].queryset = qs
I have error
‘NoneType’ object has no attribute ‘_prefetch_related_lookups’
I think I may need to see your models. Is ‘name_job’ one of the fields in your Order model?
What’s the get_form
function in your view doing? Is it passing the current_user through to the OrderForm initializer?
Thank you for advice.
I have resolved this issue.
forms.py
class OrderForm(forms.ModelForm):
class Meta:
model = Order
fields = '__all__'
def __init__(self, *args, **kwargs):
# get 'user' param from kwargs
user = kwargs.pop('user', None)
super().__init__(*args, **kwargs)
# set class attrs
for field in self.fields.values():
field.widget.attrs['class'] = 'form-control'
# set 'name_job' queryset
self.fields['name_job'].queryset = TypJob.objects.filter(author__id=user.id)
views.py
class OrderCreateView(LoginRequiredMixin, CustomSuccessMessageMixin, CreateView):
model = Order
template_name = 'new_order.html'
form_class = OrderForm
success_url = reverse_lazy('orders')
success_msg = 'Ok'
# this method will pass 'user' as param in kwargs to form __init__()
def get_form_kwargs(self):
kwargs = super(OrderCreateView, self).get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs