การสร้างฟิลด์ตัวเลือกแบบไดนามิก


138

ฉันมีปัญหาในการพยายามทำความเข้าใจวิธีสร้างฟิลด์ตัวเลือกไดนามิกใน django ฉันมีโมเดลที่ตั้งค่าบางอย่างเช่น:

class rider(models.Model):
     user = models.ForeignKey(User)
     waypoint = models.ManyToManyField(Waypoint)

class Waypoint(models.Model):
     lat = models.FloatField()
     lng = models.FloatField()

สิ่งที่ฉันพยายามทำคือสร้างตัวเลือกฟิลด์ whos ค่าคือจุดอ้างอิงที่เชื่อมโยงกับผู้ขับขี่คนนั้น (ซึ่งน่าจะเป็นบุคคลที่ล็อกอิน)

ตอนนี้ฉันกำลังลบล้าง init ในแบบฟอร์มของฉันดังนี้:

class waypointForm(forms.Form):
     def __init__(self, *args, **kwargs):
          super(joinTripForm, self).__init__(*args, **kwargs)
          self.fields['waypoints'] = forms.ChoiceField(choices=[ (o.id, str(o)) for o in Waypoint.objects.all()])

แต่สิ่งที่ทำคือรายการจุดอ้างอิงทั้งหมดพวกเขาไม่เกี่ยวข้องกับผู้ขับขี่รายใดรายหนึ่ง ความคิดใด ๆ ? ขอบคุณ.

คำตอบ:


194

คุณสามารถกรองจุดอ้างอิงโดยส่งผู้ใช้ไปยังการเริ่มต้นฟอร์ม

class waypointForm(forms.Form):
    def __init__(self, user, *args, **kwargs):
        super(waypointForm, self).__init__(*args, **kwargs)
        self.fields['waypoints'] = forms.ChoiceField(
            choices=[(o.id, str(o)) for o in Waypoint.objects.filter(user=user)]
        )

จากมุมมองของคุณในขณะที่เริ่มแบบฟอร์มผ่านผู้ใช้

form = waypointForm(user)

ในกรณีของแบบจำลอง

class waypointForm(forms.ModelForm):
    def __init__(self, user, *args, **kwargs):
        super(waypointForm, self).__init__(*args, **kwargs)
        self.fields['waypoints'] = forms.ModelChoiceField(
            queryset=Waypoint.objects.filter(user=user)
        )

    class Meta:
        model = Waypoint

20
ใช้ ModelChoiceField ไม่ว่าจะเป็น ModelForm หรือไม่ แต่ก็ใช้ได้ในรูปแบบปกติเช่นกัน
Daniel Roseman

9
คุณจะทำอย่างไรเมื่อต้องการดึงข้อมูลคำขอออกมา waypointForm (request.POST) จะไม่ตรวจสอบความถูกต้องในรายการแรกเนื่องจากไม่มีข้อมูลที่จะตรวจสอบความถูกต้องอีกต่อไป
พันธุ์

1
@ Ashok จะใช้วิดเจ็ต CheckboxSelectMultiple ในอินสแตนซ์นี้ได้อย่างไร? สำหรับ modelform โดยเฉพาะ
wasabigeek

2
หากคุณต้องการที่จะใช้CheckboxSelectMultipleเครื่องมือที่มีนี้คุณจะต้องการใช้หรือMultipleChoiceField ModelMultipleChoiceFieldตอนแรกดูเหมือนว่าจะใช้ได้ChoiceFieldแต่ภายในจะพังเมื่อคุณพยายามบันทึกแบบฟอร์ม
coredumperror

1
ขอบคุณ @CoreDumpError - เพิ่งต่อสู้มาเกือบ 2 ชั่วโมงก่อนที่จะอ่านความคิดเห็นของคุณ (ทำ!) และในที่สุดสิ่งนี้ก็ทำให้ทุกอย่างทำงานได้ อื่น ๆ โปรดระวังการส่งแบบฟอร์มของคุณCheckboxSelectMultipleเสียหาย(ปัญหา Unicode) หากคุณวางแผนที่จะใช้วิดเจ็ตด้วยรหัสนี้ อย่าลืมเปลี่ยนChoiceFormเป็นMultipleChoiceForm
นุ่มนวล

11

มีของในตัวโซลูชั่นสำหรับปัญหาของคุณ: ModelChoiceField

โดยทั่วไปแล้วคุณควรลองใช้เสมอModelFormเมื่อคุณต้องการสร้าง / เปลี่ยนแปลงวัตถุฐานข้อมูล ทำงานได้ 95% ของเคสและสะอาดกว่าการสร้างการใช้งานของคุณเอง


8

ปัญหาคือเมื่อคุณทำ

def __init__(self, user, *args, **kwargs):
    super(waypointForm, self).__init__(*args, **kwargs)
    self.fields['waypoints'] = forms.ChoiceField(choices=[ (o.id, str(o)) for o in Waypoint.objects.filter(user=user)])

ในคำขออัปเดตค่าก่อนหน้านี้จะหายไป!


3

วิธีการส่งอินสแตนซ์ไรเดอร์ไปยังแบบฟอร์มขณะเริ่มต้น

class WaypointForm(forms.Form):
    def __init__(self, rider, *args, **kwargs):
      super(joinTripForm, self).__init__(*args, **kwargs)
      qs = rider.Waypoint_set.all()
      self.fields['waypoints'] = forms.ChoiceField(choices=[(o.id, str(o)) for o in qs])

# In view:
rider = request.user
form = WaypointForm(rider) 

2

ภายใต้โซลูชันการทำงานพร้อมฟิลด์ตัวเลือกปกติ ปัญหาของฉันคือผู้ใช้แต่ละคนมีตัวเลือก CUSTOM choicefield ของตนเองตามเงื่อนไขบางประการ

class SupportForm(BaseForm):

    affiliated = ChoiceField(required=False, label='Fieldname', choices=[], widget=Select(attrs={'onchange': 'sysAdminCheck();'}))

    def __init__(self, *args, **kwargs):

        self.request = kwargs.pop('request', None)
        grid_id = get_user_from_request(self.request)
        for l in get_all_choices().filter(user=user_id):
            admin = 'y' if l in self.core else 'n'
            choice = (('%s_%s' % (l.name, admin)), ('%s' % l.name))
            self.affiliated_choices.append(choice)
        super(SupportForm, self).__init__(*args, **kwargs)
        self.fields['affiliated'].choices = self.affiliated_choice

สิ่งที่ฉันกำลังมองหา! ขอบคุณ!
Raptor

ทำให้ชีวิตของฉันง่ายขึ้น .. ขอบคุณมาก .. :)
Aravind R Pillai

1

ตามที่ Breedly and Liang ชี้ให้เห็นโซลูชันของ Ashok จะป้องกันไม่ให้คุณได้รับค่า Select เมื่อโพสต์แบบฟอร์ม

วิธีการแก้ปัญหาที่แตกต่างกันเล็กน้อย แต่ยังไม่สมบูรณ์คือ:

class waypointForm(forms.Form):
    def __init__(self, user, *args, **kwargs):
        self.base_fields['waypoints'].choices = self._do_the_choicy_thing()
        super(waypointForm, self).__init__(*args, **kwargs)

สิ่งนี้อาจทำให้เกิดปัญหาการทำงานร่วมกันได้


1

คุณสามารถประกาศฟิลด์เป็นแอตทริบิวต์ชั้นหนึ่งของฟอร์มของคุณและตั้งค่าตัวเลือกแบบไดนามิก:

class WaypointForm(forms.Form):
    waypoints = forms.ChoiceField(choices=[])

    def __init__(self, user, *args, **kwargs):
        super().__init__(*args, **kwargs)
        waypoint_choices = [(o.id, str(o)) for o in Waypoint.objects.filter(user=user)]
        self.fields['waypoints'].choices = waypoint_choices

คุณยังสามารถใช้ ModelChoiceField และตั้งค่า Queryset บน init ในลักษณะที่คล้ายกัน


0

หากคุณต้องการฟิลด์ตัวเลือกแบบไดนามิกใน django admin สิ่งนี้ใช้ได้กับ django> = 2.1

class CarAdminForm(forms.ModelForm):
    class Meta:
        model = Car

    def __init__(self, *args, **kwargs):
        super(CarForm, self).__init__(*args, **kwargs)

        # Now you can make it dynamic.
        choices = (
            ('audi', 'Audi'),
            ('tesla', 'Tesla')
        )

        self.fields.get('car_field').choices = choices

    car_field = forms.ChoiceField(choices=[])

@admin.register(Car)
class CarAdmin(admin.ModelAdmin):
    form = CarAdminForm

หวังว่านี่จะช่วยได้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.