如何选择在ModelForm上显示的ForeignKey的字段?

时间:2019-08-24 04:40:57

标签: django django-models modelform

我有以下型号:

class DirectoryDoctors (models.Model):
    num = models.AutoField(primary_key=True)
    name = models.CharField(max_length=100)
    designation = models.CharField(
        choices=design_choices, max_length=30, default='unspecified')
    mobile = models.CharField(max_length=15, default='')
    alternate = models.CharField(max_length=15, default='', blank=True)
    email = models.CharField(max_length=50, default='', blank=True)
    dob = models.DateField(null=True, blank=True)
    specialty = models.ForeignKey(SpecialtyChoices, on_delete=models.DO_NOTHING,null=True)
    institution = models.ForeignKey(DirectoryHospital, on_delete=models.DO_NOTHING)

    def __str__(self):
        st = f"{self.name}"
        return st

class DhanwantriComplaint(models.Model):
    num = models.AutoField(primary_key=True)
    sender = models.ForeignKey(DirectoryDoctors, blank=False, null=False, on_delete=models.PROTECT)
    location = models.ForeignKey(DirectoryHospital, blank=False, null=False, on_delete=models.PROTECT)
    complainttype = models.ForeignKey(DhanwantriComplaintCode, blank=False, null=False, on_delete=models.PROTECT)
    details = models.CharField(max_length=10000)
    since = models.CharField(max_length=100, blank=True, null=True)
    alertDNO = models.BooleanField(default=True)
    alertZNO = models.BooleanField(default=True)
    alertSNO = models.BooleanField(default=True)
    ITMinformed = models.BooleanField(default=False)
    ITMvisited = models.BooleanField(default=False)
    prevticketid = models.CharField(max_length=100, blank=True, null=True)
    raisedon = models.DateTimeField(default=timezone.now)
    lastupdate = models.DateTimeField(default=timezone.now)
    closed = models.BooleanField(default=False)
    closedon = models.DateTimeField(blank=True, null=True)

我有Modelform:

class DhanwantriComplaintForm(ModelForm):
    class Meta:
        model = DhanwantriComplaint
        fields = [           
            'sender',
            'location',
            'complainttype',
            'details',
            'since',
            'alertDNO',
            'alertZNO',
            'alertSNO',
            'ITMinformed',
            'ITMvisited',
            'prevticketid',
            ]
        widgets = {
            'details': forms.Textarea(attrs={
                'rows': 10,
                'cols': 15
            }),
            'sender': forms.TextInput(),
        }

视图:

@login_required
def complaint_dhanwantri_new(request):
    items = LinkSection.objects.all()
    docuser = DoctorUser(request)
    print(f'docuser is {docuser}. type is {type(docuser)}')

    form = DhanwantriComplaintForm(
        initial={
            'sender': docuser,
            'location': docuser.institution,
        }
    )
    if request.method == 'POST':
        print(f'Received POST: {request.POST.get}')
        form = DhanwantriComplaintForm(request.POST)
        if form.is_valid():
            print("Form is valid")
        else:
            print("Form is not valid")

    return render(
        request, 'app/complaints/complaint.html', {
            'rnd_num': randomnumber(),
            'fileitems': items,
            'form': form,
            'docuser': docuser,
            'total_docs': DirectoryDoctors.objects.count(),
            'total_institutions': DirectoryHospital.objects.count()
        })  

以及我模板中的以下代码:

<div class="form-group row">
    <label for="inputEmail3" class="col-sm-3 col-form-label">Sender: </label>
    <div class="col-sm-21">
    {% render_field form.sender|append_attr:"readonly:readonly" type="text" class+="form-control" %}
    </div>
</div>
<div class="form-group row">
      <label for="inputEmail3" class="col-sm-3 col-form-label">Location: </label>
      <div class="col-sm-21">
          {{ form.location|add_class:"form-control" }}
      </div>
</div>

问题在于,当呈现表单时,不显示模型DirectoryDoctors的字段名称,而是显示pk值,如下所示。

Dhanwantri image 显示表单时如何控制显示哪个字段?

1 个答案:

答案 0 :(得分:0)

这是因为senderDhanwantriComplaint模型中的外键。它只能填充某些值(DirectoryDoctors模型的主键)。因此,它自然应该是带有某些选项的选择字段(呈现为下拉列表)。 Django会将FK字段呈现为下拉列表,默认情况下,相关模型的__str__表示形式为display,而PK为值。但是你在这里强迫django

'sender': forms.TextInput(),

将其呈现为文本字段。并且由于该字段的原始值只是一个数字(FK),因此它在字段中显示了该数字。

但是,如果要使用TextInput作为外键,则必须像这样修改表单行为

    def __init__(self, initial=None, instance=None, *args, **kwargs):
        if initial is None:
            initial = {}

        if 'sender' in initial:
            initial['sender'] = initial['sender'].name
        elif instance is not None:
            initial['sender'] = instance.sender.name
        super(PatientForm, self).__init__(initial=initial, instance=instance, *args, **kwargs)

    def clean(self):
        cleaned_data = super(PatientForm, self).clean()
        sender = cleaned_data.pop('sender')
        sender = DirectoryDoctors.objects.filter(name=sender).first()
        if sender is None:
            raise forms.ValidationError('Sender does not exist')
        cleaned_data['sender'] = sender
        return cleaned_data

上述解决方案的约束条件是DirectoryDoctors的{​​{1}}应该是唯一的。否则它将/将造成混乱。