You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django:如何为非外键字段实现ForeignKeyRawIdWidget效果?

Got it, let's break down how to add that popup-style raw ID selector for your Slum model's name field in a custom form. The ForeignKeyRawIdWidget is built for foreign keys, but we can roll our own custom widget based on Django's core RawIdWidget to replicate that exact behavior for non-foreign-key fields. Here's a step-by-step solution:

1. Ensure your Slum model is registered in the admin

The popup selector relies on the admin's changelist page for Slum entries. If you haven't already, register the model so the popup has a page to pull from:

from django.contrib import admin
from .models import Slum

@admin.register(Slum)
class SlumAdmin(admin.ModelAdmin):
    list_display = ('name', 'id')  # Include name so it's visible in the popup selection

2. Create a custom widget extending RawIdWidget

We'll override key methods to make the widget target your name field, display the selected name instead of just an ID, and link to the correct admin popup:

from django.contrib.admin.widgets import RawIdWidget
from django.contrib import admin
from django.urls import reverse
from .models import Slum

class SlumNameRawIdWidget(RawIdWidget):
    def __init__(self, *args, **kwargs):
        self.model = Slum
        # For Django <2.0, replace `remote_field` with `rel`
        super().__init__(rel=self.model._meta.pk.remote_field, *args, **kwargs)

    def label_for_value(self, value):
        # Show the selected Slum's name next to the input (instead of just ID)
        if value:
            try:
                slum = self.model.objects.get(pk=value)
                return slum.name
            except self.model.DoesNotExist:
                return ""
        return ""

    def get_url(self):
        # Point the popup to the Slum admin changelist with popup mode enabled
        return reverse(f"admin:{self.model._meta.app_label}_{self.model._meta.model_name}_changelist") + "?_popup=1"

3. Use the custom widget in your custom form

Since you're using a non-ModelForm, define your field with the new widget. We'll add a clean method to convert the selected Slum ID (stored by the widget) to the actual name value your form needs:

from django import forms
from .widgets import SlumNameRawIdWidget

class YourCustomForm(forms.Form):
    slum_name = forms.CharField(widget=SlumNameRawIdWidget(admin_site=admin.site))

    def clean_slum_name(self):
        # Convert the selected Slum ID to its name for form submission
        slum_id = self.cleaned_data.get("slum_name")
        if slum_id:
            try:
                slum = Slum.objects.get(pk=slum_id)
                return slum.name
            except Slum.DoesNotExist:
                raise forms.ValidationError("Invalid slum selected.")
        return ""

4. Optional: Styling tweaks

The widget will render with the same magnifying glass icon and layout as the default ForeignKeyRawIdWidget. If you need to adjust the look, you can override the widget's render method or add custom CSS, but the default should match Django's admin styling out of the box.

内容的提问来源于stack exchange,提问作者Abhijit Ghate

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:59:16