Opened 18 years ago
Last modified 2 months ago
#2750 assigned Bug
ManyToManyField ignores 'default' option
Reported by: | Owned by: | Wim Feijen | |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | |
Severity: | Normal | Keywords: | |
Cc: | orzel@…, Chris Chambers, Rafał Selewońko, chris+django@…, anubhav9042@…, josh.smeaton@… | Triage Stage: | Accepted |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | yes |
Easy pickings: | no | UI/UX: | no |
Description
It doesn't seem possible to use the 'default' option to pre-select values in the admin site for a ManyToManyField. I've tried a string value, a list of strings, and even (following a recommendation from someone on #django) passing a list of the actual objects. It would be nice to either have this functionality added or to update the docs to reflect the fact that 'default' has no effect on ManyToManyFields.
-Basil
Change History (26)
comment:1 by , 17 years ago
Component: | Core framework → Database wrapper |
---|---|
Triage Stage: | Unreviewed → Design decision needed |
comment:2 by , 17 years ago
I need this :
publish_on = models.ManyToManyField(Site, verbose_name=_('publish on'), default=Site.objects.get_current)
:-P
comment:3 by , 17 years ago
Triage Stage: | Design decision needed → Someday/Maybe |
---|
comment:4 by , 16 years ago
I've created a patch for getting some default behavior in the admin for many to many fields.
Actually i had the same use case as semente. When using multiple sites the default site is not automatically selected. And it's quite a nag to have to select it each and every time. So when using the below ManyToManyFieldWithDefault you can use it as:
publish_on = ManyToManyFieldWithDefault(Site, verbose_name=_('publish on'), default=Site.objects.get_current)
And it will automatically select the current_site when no other sites are selected. (Except for when blank=True and null=True)
from django import oldforms from django.db import models from django.utils.functional import curry class SelectMultipleFieldWithDefault(oldforms.SelectMultipleField): def __init__(self, default_choice=None, *args, **kwargs): self.__default_choice = default_choice super(SelectMultipleFieldWithDefault, self).__init__(*args, **kwargs) def render(self, data): if not data and self.__default_choice: data = [self.__default_choice.id] return super(SelectMultipleFieldWithDefault, self).render(data) class ManyToManyFieldWithDefault(models.ManyToManyField): def __init__(self, *args, **kwargs): if not kwargs.get('blank', False) and not kwargs.get('null', False): self.__default_choice = kwargs.get('default', None) else: self.__default_choice = None super(ManyToManyFieldWithDefault, self).__init__(*args, **kwargs) def get_manipulator_field_objs(self): if self.rel.raw_id_admin: return [oldforms.RawIdAdminField] else: choices = self.get_choices_default() return [curry(SelectMultipleFieldWithDefault, size=min(max(len(choices), 5), 15), choices=choices, default_choice=self.__default_choice)]
comment:5 by , 16 years ago
I can thus: default=str(Site.objects.get_current().id)
but it is strange, why str?
(in django 1.0)
follow-up: 7 comment:6 by , 16 years ago
hmm, but the manner above doesn't works when save (obviously), only in admin interface. :-P
comment:7 by , 16 years ago
Replying to Guilherme M. Gondim <semente@taurinus.org>:
hmm, but the manner above doesn't works when save (obviously), only in admin interface. :-P
Please, ignore this. The tip above works (#5), my problem was with a bug in my code.
comment:8 by , 16 years ago
Cc: | added |
---|
I have the same problem here. I have a set of strings i want the user to select from, in the admin interface. By default i want all strings to be selected. (the user needs to 'opt-out', not 'opt-in').
if in my model i do
stuff = models.ManyToManyField(Stuff, default=Stuff.objects)
or
stuff = models.ManyToManyField(Stuff, default=Stuff.objects.all())
then i get randomly choosen selected items from Stuff. Rather weird : it's not all, it's not none (as where there's no default=), but just random...
comment:9 by , 14 years ago
+1 in favor of documentation update to reflect the status of default and null in relation to M2Ms.
With signals and a million other tools its easy to get this default and I'm not certain that I agree with the meaning or obviousness of 'default' when it comes to this field.
comment:10 by , 14 years ago
Cc: | added |
---|
comment:11 by , 14 years ago
Severity: | normal → Normal |
---|---|
Type: | defect → Bug |
comment:12 by , 14 years ago
Cc: | added |
---|
comment:15 by , 13 years ago
Cc: | added |
---|
comment:16 by , 11 years ago
Cc: | added |
---|
comment:17 by , 10 years ago
https://github.com/django/django/pull/3108
I'm of the opinion that default
for ManyToManyField doesn't make sense. The default value of a field is used when a model is saved without a user value. M2M fields can not have a value when being saved (values must be added with the RelatedManager), so the default value would always be applied if implemented.
I think the underlying problem of pre-selecting values in the admin for m2m form fields is orthogonal to whether or not m2m model fields should respect the default option.
comment:18 by , 10 years ago
Has patch: | set |
---|---|
Triage Stage: | Someday/Maybe → Accepted |
comment:19 by , 10 years ago
Cc: | added |
---|
comment:20 by , 10 years ago
Patch needs improvement: | set |
---|
There are failing tests and usage of this in Django's test suite that need to be removed.
comment:21 by , 10 years ago
Has patch: | unset |
---|
While I don't think default
makes sense for m2m models, it appears that forms make use of the default option, so we can't simply check/warn and document. This will involve some deeper investigation with regards to how forms use the m2m default. I'll try to look into this a little more.
follow-up: 23 comment:22 by , 8 years ago
Has there been any movement on this? When you say forms make use of the default option, what do you mean?
comment:23 by , 7 years ago
Replying to Philip James:
Has there been any movement on this? When you say forms make use of the default option, what do you mean?
what is meant here is:
the default
option for a ManyToManyField
is not used when saving the object (when calling <object>.save()
, or other): even if it is set (e.g. to a callable returning an object list), the field will be set to an empty list when saving.
However, this default
option value is used in Django Form
set up to edit this object. In particular, in Django Admin, a the multivalue drop-down will include for the field, that will contain all the objects returned by the callable defined as the default
value - and they will be all selected. If the user saves the object without any edit (by pushing the form's "save" button), then the field will indeed be set to all the values.
The current behavior is a little misleading, I think (and I'm not the only. one, from previous comments): I would expect the options set if the model's fields to be used in the model's methods; if an option is only used for forms, I would expect it to be set in the form, not in the model. There may be design reasons for the current behavior though ?
In any case, this should probably be documented in the ManyToManyField
documentation ?
comment:24 by , 4 years ago
Patch needs improvement: | unset |
---|
comment:25 by , 2 months ago
Has patch: | set |
---|---|
Owner: | changed from | to
Status: | new → assigned |
There is a new doc update PR that needs review, setting the right flags.
comment:26 by , 2 months ago
Patch needs improvement: | set |
---|
The decision is whether the functionality should be added or the docs should just be updated.