I'm using ModelMultipleChoiceField with a large number of objects.
I want to show only the selected objects and let the user remove a choice with js.
To add choices the user will open a popup similar to ManyToManyRawIdWidget.
I can limit the queryset to the selected choices in the init of the form with:
def __init__(self, *args, **kwargs):
super(FormName, self).__init__(*args, **kwargs)
self.fields['field_name'].queryset = self.instance.field_name
But this will require manual setting on every form.
Is it possible to extend the ModelMultipleChoiceField to get the queryset from the field choices?
I think that I need to extend ModelChoiceIterator but couldn't understand how to access the module instance.
Thanks
i am not sure if this is what you are looking for, but if you want the same "list-shuttle" than in auth/user/permissions you should try this;
class MyForm(forms.ModelForm):
myfield = forms.ModelMultipleChoiceField(
queryset = Category.objects.all(),
widget = admin.widgets.FilteredSelectMultiple(
_('myfield'), False),
required = False,
)
class MyAdmin(admin.ModelAdmin):
form = MyForm
Related
I want to overwrite the __str__ method in Django admin when using the autocomplete_fields = () but the returned values are using __str__.
I have a form something like
class MyAdminForm(forms.ModelForm):
placement = forms.Select(
choices = Organisation.objects.active(),
)
class Meta:
model = Lead
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['placement'].label_from_instance = lambda obj: f'{str(obj)} {obj.post_code}'
This will provide back a Select with the organisation name and post code in the dropdown fields. But there are some 80k choices so I need to using autocomplete. Within within admin.py I have
class LeadAdmin(admin.ModelAdmin):
form = LeadAdminForm
autocomplete_fields = ('placement',)
As soon as I add the autocomplete_fields I lose my postcode and it reverts to just showing the __str__
Hoa can I used autocomplete_fields and overwrite the __str__ method?
This question is answered through Benbb96 comment above which I've copied here so I can close it
So maybe this answer can help you :
stackoverflow.com/a/56865950/8439435 – Benbb96
I have a custom queryset on a model manager:
class TenantManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(myfield=myvalue)
class TenantModel(TenantModelMixin, models.Model):
objects = TenantManager()
class Meta:
abstract = True
I use the abstract TenantModel as a mixin with another model to apply the TenantManager. E.g.
class MyModel(TenantModel):
This works as expected, applying the TenantManager filter every time MyModel.objects.all() is called when inside a view.
However, when I create a ModelForm with the model, the filter is not applied and all results (without the filter are returned. For example:
class AddPersonForm(forms.ModelForm):
class Meta:
model = MyModel
fields = ('person', )
Why is this and how to I ensure the ModelManager is applied to the queryset in ModelForm?
Edit
#Willem suggests the reason is forms use ._base_manager and not .objects (although I can not find this in the Django source code), however the docs say not to filter this kind of manager, so how does one filter form queries?
Don’t filter away any results in this type of manager subclass
This
manager is used to access objects that are related to from some other
model. In those situations, Django has to be able to see all the
objects for the model it is fetching, so that anything which is
referred to can be retrieved.
If you override the get_queryset() method and filter out any rows,
Django will return incorrect results. Don’t do that. A manager that
filters results in get_queryset() is not appropriate for use as a base
manager.
You can do it in two ways:
First: When creating the form instance, add the queryset for the desired field.
person_form = AddPersonForm()
person_form.fields["myfield"].queryset = TenantModel.objects.filter(myfield="myvalue")
Second: Override the field's queryset in the AddPersonForm itself.
class AddPersonForm(forms.ModelForm):
class Meta:
model = MyModel
fields = ('person', )
def __init__(self, *args, **kwargs):
super(AddPersonForm, self).__init__(*args, **kwargs)
self.fields['myfield'].queryset = TenantModel.objects.filter(myfield="myvalue")
I'm not sure why your code doesn't properly works. Probably you haven't reload django app. You could load queryset in __init__ of your form class
class AddPersonForm(forms.ModelForm):
person = forms.ModelMultipleChoiceField(queryset=None)
class Meta:
model = MyOtherModel
fields = ('person', )
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['person'].queryset = MyModel.objects.all()
I am adding an extra field to a Django ModelForm like that:
class form(forms.ModelForm):
extra_field = forms.CharField(label='Name of Institution')
class Meta:
model = db_institutionInstitution
fields = ['conn_kind','time','inst_name2']
The form is actually working fine, but I cant prepopulate it. I use it in a modelformset_factory:
formset = modelformset_factory(db_institutionInstitution,form=form)
I manually run through a queryset and add the entry in the dictionary needed for the additional form in the formset. However, when I call:
formset1 = formset(prefix='brch',queryset=qs1)
the extra_field is not prepopulated as intended (the rest is working fine).
Can anyone help?
If you want to set a default.
extra_field = forms.CharField(label='Name of Institution', initial="harvard")
If you want to dynamically set a value put it on form initialization:
def __init__(self, *args, **kwargs):
super(form, self).__init__(*args, **kwargs)
self.fields['extra_field'].initial = "harvard"
I'm overriding the admin form of a model to modify the choices of a ForeignKey field.
When selecting a choice in the admin form, and saving, I get a ValueError:
Cannot assign "u'6'": "MyModel1.mymodel2" must be a "MyModel2" instance
where 6 is the id of the selected choice.
The new choices is built as ((<choice_1_id>, <choice_1_label>), (<choice_2_id>, <choice_2_label>),...), and I get the same html for the rendered select widget as if I don't modify the choices (apart from the ordering of course).
If I comment self.fields['mymodel2'] = forms.ChoiceField(choices=choices) in MyModel1AdminForm.__init__() I get no error...
Anybody could help?
models.py
class MyModel1(models.Model):
mymodel2 = ForeignKey(MyModel2)
# more fields...
admin.py
class MyModel1AdminForm(forms.ModelForm):
class Meta:
model = MyModel1
def __init__(self, *args, **kwargs):
super(MyModel1AdminForm, self).__init__(*args, **kwargs)
# create choices with ((<choice_1_id>, <choice_1_label>), (<choice_2_id>, <choice_2_label>),...)
self.fields['mymodel2'] = forms.ChoiceField(choices=choices, widget=SelectWithDisabled) # http://djangosnippets.org/snippets/2453/
class MyModel1Admin(admin.ModelAdmin):
form = MyModel1AdminForm
my_site.register(MyModel1, MyModel1Admin)
mymodel2 is the Foreign Key field. You need to supply the queryset if you want to change the choices instead of adding your custom choices:
self.fields['mymodel2'].queryset = MyModel2.objects.all()
If you need to construct the choices manually something like
choices = MyModel2.objects.values_list('pk', 'title')
should work with a standard ChoiceField, where title is the field of the model you want to use as label/verbose name for your choice.
Looking at the snippet you are using values_list won't work so you could fallback to a list comprehension:
[(c.pk, {'label': c.title, 'disabled': False}) for c in MyModel2.objects.all()]
Though you obviously need some more logic to decide whether a choice is enabled or disabled.
I ended up overriding ModelChoiceField:
class MyModelChoiceField(forms.ModelChoiceField):
def label_from_instance(self, obj):
level = getattr(obj, obj._mptt_meta.level_attr)
return {'label': obj.name), 'disabled': check_disabled(obj)}
I'm using django modelform inheritence in my modelform but it seems to be not working here is my code sample
class ArticleForm(forms.ModelForm):
title = forms.CharField(required=True)
sites = forms.ModelMultipleChoiceField(required=True, queryset= Sites.objects.all().order_by('name'), widget=forms.SelectMultiple())
class ArticleAddForm(ArticleForm):
class Meta(ArticleForm.Meta):
exclude = ('sites',)
i want to exclude "sites" from "ArticleAddForm" but while validating it is raising form validation error sites field required please help?
ModelForms don't handle inheritance so well, I believe.
Probably the best ou can do is remove the required flag in the child class:
def __init__(self, *args, **kwargs):
super(ArticleAddForm, self).__init__(*args, **kwargs)
self.base_fields['sites'].required = False
self.base_fields['sites'].widget = HiddenInput() # if you want
In your view, you need to initialize the ArticleAddForm with an Article object to fill the blank fields, i.e. the excluded fields. For example:
sites = Sites.objects.all() # modify this according to your needs
article = Article(title='', sites=sites)
form = ArticleAddForm(request.POST, instance=article)
form.save()