15

I'm making a Django app with custom users. I've outlined the key components of my problem below, missing code is denoted by '...'. My custom user model has a foreign key relationship as follows:

class MyCustomUser(models.AbstractBaseUser, models.PermissionsMixin)
    ...
    location = models.ForeignKey(Location)

class Location(models.Model)
    name = models.CharField(max_length=50, blank=True, null=True)

I've written a custom user form that includes this field as follows:

class MyCustomUserCreationForm(models.ModelForm)
    ...
    location = forms.ModelChoiceField(Location.objects.all())

This all appears to be working correctly, however, there is no plus button to the right of the select field for location. I want to be able to add a location when I create a user, in the same way that you can add polls when creating choices in the Django tutorial. According to this question, I might not see the green plus if I don't have permission to change the model, but I am logged in as a superuser with all permissions. Any idea what I'm doing wrong?

4

4 回答 4

18

您需要RelatedFieldWidgetWrapper在模型表单中设置一个包装器:

RelatedFieldWidgetWrapper(可在 django.contrib.admin.widgets 中找到)在管理页面中用于包含外键控件添加新相关记录的功能。(英文:将绿色的小加号放在控件的右侧。)

class MyCustomUserCreationForm(models.ModelForm)
    ...
    location = forms.ModelChoiceField(queryset=Location.objects.all())

    def __init__(self, *args, **kwargs):
        super(MyCustomUserCreationForm, self).__init__(*args, **kwargs)
        rel = ManyToOneRel(self.instance.location.model, 'id') 
        self.fields['location'].widget = RelatedFieldWidgetWrapper(self.fields['location'].widget, rel, self.admin_site)

我可能会在示例代码中出错,因此请参阅这些帖子和示例:

于 2013-09-03T22:45:16.853 回答
9

我根据上面的答案创建了方法:

def add_related_field_wrapper(form, col_name):
    rel_model = form.Meta.model
    rel = rel_model._meta.get_field(col_name).rel
    form.fields[col_name].widget = 
    RelatedFieldWidgetWrapper(form.fields[col_name].widget, rel, 
    admin.site, can_add_related=True, can_change_related=True)

然后从我的表单中调用此方法:

class FeatureForm(forms.ModelForm):
    offer = forms.ModelChoiceField(queryset=Offer.objects.all(), required=False)
    package = forms.ModelChoiceField(queryset=Package.objects.all(), required=False)
    def __init__(self, *args, **kwargs):
        super(FeatureForm, self).__init__(*args, **kwargs)
        add_related_field_wrapper(self, 'offer')
        add_related_field_wrapper(self, 'package')

这在 Django 1.8.2 上运行良好。

于 2015-08-20T07:20:09.610 回答
2

谷歌在搜索如何在具有外键关系的自定义表单中的字段旁边获取“+”图标时将我指向此页面,所以我想我会添加。

对我来说,使用django-autocomplete-light“添加另一个”功能做得很好。

于 2014-03-21T13:29:39.633 回答
1

您甚至不需要走那么远,此外,这些答案可能已经过时,因为它们中没有一个对我有用。

我为解决这个问题所做的是,只要您的模型中已经有 ForeignKey 字段,那么您就可以创建您的自定义 ModelChoiceField:

class LocationModelChoiceField(forms.ModelChoiceField):
    def label_from_instance(self, obj):
        return "%" % (obj.name)

接下来的关键是不要在 ModelForm 中为 ModelChoiceField 创建自定义字段(即location = forms.ModelChoiceField(Location.objects.all())

换句话说,把它排除在外,在你的 ModelForm 中有这样的东西:

class UserAdminForm(forms.ModelForm):

    class Meta:
        model = User
        fields = '__all__'

最后,在您的 ModelAdmin 中:

class UserAdmin(admin.ModelAdmin):
    model = User
    form = UserAdminForm

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == 'location':
        return LocationModelChoiceField(queryset=Location.objects.order_by('name')) # if you want to alphabetize your query
    return super().formfield_for_foreignkey(db_field, request, **kwargs)
于 2018-12-15T18:18:50.943 回答