Django 管理员:如何“预填充”基于父模型的内联外键字段

发布于 2025-01-01 06:24:40 字数 1491 浏览 1 评论 0原文

关于这个问题的一些评论表明有更简单和最新的解决方案。 (我没有找到任何)

(类似这样的评论:“是的,它已经解决了。只需在参数中传递相关实例,它就会预先填充它......”让我觉得现在很容易,但我仍然做不到工作)

问题是我想向参与给定事件并由管理人员选择的一些用户发送通知。 工作人员位于事件页面上,选择事件并保存它,然后内联中的 fk 字段应预先填充涉及的用户名。 (并等待工作人员检查它们或取消检查它们以接收电子邮件通知)

出于可用性原因,这应该采取内联形式至关重要,因为已经有很多页面需要浏览以从工作人员收集所有必要的信息。

有什么想法吗?

class When(models.Model):
    ...
    Date = models.DateTimeField(unique=True)
    Nameofevent = models.ForeignKey(Event, to_field='Name') #the Event model gets then username from models.ManyToManyField(User, through='Role')
    ...
    def getteam(self):
        teamlist = self.Nameofevent.Roleinevent.all() # gathering users which are involved
        return teamlist
    getteamresult = property(getteam)

class Notice(models.Model): #this will go to the inline
    ...
    Who = models.ForeignKey(User, blank=True)
    To_notice_or_not_to_notice = models.BooleanField(default=False)
    ...

class NoticeInline(admin.TabularInline):
    model = Notice
    extra = 9

class WhenAdmin(admin.ModelAdmin):
    list_display = ('Date', ...)
    readonly_fields = ('getteamresult', ) #this is to make clear i have access to what i want and i can display it. prints out as [<User: someone>, <User: someoneelse>]
    inlines = [NoticeInline] #but i want the User objects to prepopulate foreign field here in inline model
admin.site.register(When,WhenAdmin)

Some comments on this question indicate there is more straightforward and up-to-date solution. (I didn't find any)

(comments like: "Yes it's solved. Just pass the related instance in parameter, and it will prepopulate it..." makes me think it is easy now, but still I can't make it work)

The thing is that I want to send notice to some users which are involved in given event and selected by admin staff.
Staff-member is on the page of event, selects the event and saves it, than fk fields in inline should prepopulate with involved usernames. (and waiting to staff-member to check them or uncheck them to receive e-mail notice)

For usability reasons it's critical that this should take form of inline since there are allready lot of pages to go through to gather all necessary informations from staff.

Any ideas?

class When(models.Model):
    ...
    Date = models.DateTimeField(unique=True)
    Nameofevent = models.ForeignKey(Event, to_field='Name') #the Event model gets then username from models.ManyToManyField(User, through='Role')
    ...
    def getteam(self):
        teamlist = self.Nameofevent.Roleinevent.all() # gathering users which are involved
        return teamlist
    getteamresult = property(getteam)

class Notice(models.Model): #this will go to the inline
    ...
    Who = models.ForeignKey(User, blank=True)
    To_notice_or_not_to_notice = models.BooleanField(default=False)
    ...

class NoticeInline(admin.TabularInline):
    model = Notice
    extra = 9

class WhenAdmin(admin.ModelAdmin):
    list_display = ('Date', ...)
    readonly_fields = ('getteamresult', ) #this is to make clear i have access to what i want and i can display it. prints out as [<User: someone>, <User: someoneelse>]
    inlines = [NoticeInline] #but i want the User objects to prepopulate foreign field here in inline model
admin.site.register(When,WhenAdmin)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

小兔几 2025-01-08 06:24:40

我不认为内联是解决此类问题的方法。如果应提示工作人员向参与事件的用户发送电子邮件,并且需要控制实际通知哪些用户,那么您应该使用中间视图。

首先,您需要一个可以让您选择属于​​该活动的用户的表单。最初,我们将 users 字段设置为所有用户,但在表单的 __init__ 方法中,我们将采用“event”kwarg 并根据该字段过滤该字段。

class UserNotifyForm(forms.Form):
    users = forms.ModelMultipleChoiceField(queryset=User.objects.all(), widget=forms.CheckboxSelectMultiple())

    def __init__(self, *args, **kwargs):
        event = kwargs.pop('event')
        super(UserNotifyForm, self).__init__(*args, **kwargs)
        if event:
            self.fields['users'].queryset = event.users.all()

其次,您在 ModelAdmin 上创建一个视图,其行为就像普通表单视图一样:

def notify_users_view(self, request, object_id):
    event = get_object_or_404(Event, id=object_id)
    if len(request.POST):
        form = UserNotifyForm(request.POST, event=event)
        if form.is_valid():
            users = form.cleaned_data.get('users')
            # send email
            return HttpResponseRedirect(reverse('admin:yourapp_event_changelist'))
    else:
        form = UserNotifyForm(event=event)

    return render_to_response('path/to/form/template.html', {
        'event': event,
        'form': form,
    }, context_instance=RequestContext(request))

您当然需要为此创建模板,但这很简单。该表单已设置为显示复选框列表,每个用户对应一个复选框,因此您可以在那里获得所需的所有信息。

第三,将此视图绑定到您的 ModelAdmin 的网址中:

def get_urls(self):
    urls = super(MyModelAdmin, self).get_urls()

    info = (self.model._meta.app_label, self.model._meta.module_name)

    my_urls = patterns('',
        (r'^(?P<object_id>\d+)/notify/

第四,覆盖 change_view 以在保存后重定向到此视图:

def change_view(self, request, object_id, extra_context=None):
    response = super(MyModelAdmin, self).change_view(request, object_id, extra_context=extra_context)
    if len(request.POST):
        info = (self.model._meta.app_label, self.model._meta.module_name)
        response['Location'] = reverse('admin:%s_%s_notify', args=(object_id,))
    # Note: this will effectively negate the 'Save and Continue' and
    # 'Save and Add Another' buttons. You can conditionally check
    # for these based on the keys they add to request.POST and branch
    # accordingly to some other behavior you desire.
    return response
, self.notify_users_view, name='%s_%s_notify' % info) ) return my_urls + urls

第四,覆盖 change_view 以在保存后重定向到此视图:

I don't believe inlines are the the way to go for something like this. If the staff-member should be prompted to email users involved in the event, and needs control over which ones are actually notified, then you should use an intermediate view.

First, you need a form that will let you select users that belong to the event. Initially, we set the users field to just be all users, but in the form's __init__ method we'll take the "event" kwarg and filter the field based on that.

class UserNotifyForm(forms.Form):
    users = forms.ModelMultipleChoiceField(queryset=User.objects.all(), widget=forms.CheckboxSelectMultiple())

    def __init__(self, *args, **kwargs):
        event = kwargs.pop('event')
        super(UserNotifyForm, self).__init__(*args, **kwargs)
        if event:
            self.fields['users'].queryset = event.users.all()

Second, you create a view on your ModelAdmin, that will behave just as a normal form view would:

def notify_users_view(self, request, object_id):
    event = get_object_or_404(Event, id=object_id)
    if len(request.POST):
        form = UserNotifyForm(request.POST, event=event)
        if form.is_valid():
            users = form.cleaned_data.get('users')
            # send email
            return HttpResponseRedirect(reverse('admin:yourapp_event_changelist'))
    else:
        form = UserNotifyForm(event=event)

    return render_to_response('path/to/form/template.html', {
        'event': event,
        'form': form,
    }, context_instance=RequestContext(request))

You'll of course need to create template for this, but that's simple enough. The form is already set up to show a list of checkboxes, one for each user, so you have all the info you need there.

Third, tie this view into your ModelAdmin's urls:

def get_urls(self):
    urls = super(MyModelAdmin, self).get_urls()

    info = (self.model._meta.app_label, self.model._meta.module_name)

    my_urls = patterns('',
        (r'^(?P<object_id>\d+)/notify/

Fourth, override the change_view to redirect to this view after save:

def change_view(self, request, object_id, extra_context=None):
    response = super(MyModelAdmin, self).change_view(request, object_id, extra_context=extra_context)
    if len(request.POST):
        info = (self.model._meta.app_label, self.model._meta.module_name)
        response['Location'] = reverse('admin:%s_%s_notify', args=(object_id,))
    # Note: this will effectively negate the 'Save and Continue' and
    # 'Save and Add Another' buttons. You can conditionally check
    # for these based on the keys they add to request.POST and branch
    # accordingly to some other behavior you desire.
    return response
, self.notify_users_view, name='%s_%s_notify' % info) ) return my_urls + urls

Fourth, override the change_view to redirect to this view after save:

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文