Dynamically specify a ModelChoiceField queryset in Django

Introduction

There is a case where you want to control the items that can be selected according to the authority of the logged-in user for the list box that is referenced by the master.

↓ A memo of how to investigate and try using the model and form as a sample.

models.py


class Book(models.Model):
    name = models.charField('name',max_length=255)

forms.py


class SampleForm(forms.Form):
    book = forms.ModelChoiceField(label='book',queryset=Book.objects.all())

Overwrite queryset after form generation

Probably the simplest way.

python


form = SampleForm()
form.fields['book'].queryset = Book.objects.filter(...)

Receive queryset as an argument and overwrite it with __init__ of the form

forms.py


class SampleForm(forms.Form):
    book = forms.ModelChoiceField(label='book',queryset=Book.objects.none())
    def __init__(self, queryset=None, *args, **kwargs):
        super(SampleForm,self).__init__(*args,**kwargs)
        if queryset :
            self.fields['book'].queryset = queryset

python


form = SampleForm(queryset=Book.objects.filter(...))

Note that self.fields will not be generated unless you call super.__ init__.

What to do with the default queryset depends on the role of the form.

It is also possible to implement that the queryset itself is not received, only the data used for the filter condition is received, and the queryset is generated on the form side.

forms.py


class SampleForm(forms.Form):
    book = forms.ModelChoiceField(label='book',queryset=Book.objects.none())
    def __init__(self, permission=None, *args, **kwargs):
        super(SampleForm,self).__init__(*args,**kwargs)
        self.fields['book'].queryset = self.get_book_list(permission)

    def get_book_list(self, permission=None):
        if not permission :
            return Book.objects.none()

        if permission == AAA :
            query = Q(...)
        elif permission == BBB :
            query = Q(...)
        #Write as much as you need...

        return Book.objects.filter(query)

What you are doing is essentially the same. The point is that you can overwrite Form.fields ['field_name']. Queryset after processing Form.__ init__.

Digression

By playing with Form.fields, you can change various attributes of other fields after the form is created. Is it possible to add / remove the field itself?

Recommended Posts

Dynamically specify a ModelChoiceField queryset in Django
Dynamically add form fields in Django
Create a LINE Bot in Django
Install Django in a pipenv virtual environment
Implement a Custom User Model in Django
Dynamically add fields to Form objects in Django
Models in Django
Start Django in a virtual environment with Pipenv
Enable Django https in just a few lines
Build a Django environment with Vagrant in 5 minutes
Specify the view URL in your Django template
Configure a module with multiple files in Django
How to create a Rest Api in Django
Until you create a new app in Django
Forms in Django
How to specify a schema in Django's database settings
Specify a subcommand as a command line argument in Python
In Python, create a decorator that dynamically accepts arguments Create a decorator
Dynamically create tables in schema with Django, dynamically generate models
How to reference static files in a Django project
Create a Django schedule
dict in dict Makes a dict a dict
Start a Django project
Try running python in a Django environment created with pipenv
[Django] Manage settings like writing in settings.py with a model
A story about how to specify a relative path in python.
[Django3] Display a web page in Django3 + WSL + Python virtual environment
Specify a date range with a comparison operator in Python's datetime
I made a command to generate a table comment in Django
Until I return something with a line bot in Django!
Best practices for dynamically handling LINE Flex Messages in Django