Django : ModelForm with conditions

孤人 提交于 2019-12-05 14:29:42

You can overwrite the form's __init__ method to remove or disable fields conditionally:

class ProfileForm(forms.ModelForm):
    ...
    def __init__(self, *args, **kwargs):
        super(ProfileForm, self).__init__(*args, **kwargs)
        if self.instance and self.instance.level < 3:
            self.fields['job'].disabled = True # still displays the field in the template
            # del self.fields['job'] # removes field from form and template
        if self.instance and self.instance.level < 1:
            self.fields['avatar'].disabled = True

Django pre_save signal can be used to solve this. Before saving the model, the hook on pre_save will be called. You can write conditions in there to check if the user is allowed to change the fields.

You'll also need to store a copy of the model to compare the state in pre_save, it can be done through post_init hook.

from django.dispatch import receiver , Signal
from django.db.models.signals import post_init , pre_save

@receiver(pre_init , sender = Player)
def cache(sender , instance , **kwargs):
    instance.__original_name = instance.name
    instance.__original_avatar = instance.avatar
    instance.__original_job = instance.job
@receiver(pre_save , sender= Player)
def check_update(sender , instance , **kwargs):
    if instance.level == 1:
        #Revert changes to avatar and job, and keep changes in the name
    if instance.level == 2:
        #Revert changes to job , and keep changes in the name and avatar
    if instance.level == 3:
        #Keep all changes

This way you can keep track of all the updating fields.

You can achieve this customizing your form in its init method

To the situations described Before, you can do some as:

class ProfileForm(forms.ModelForm):

    class Meta:
        model = Player
        fields = ['name', 'avatar', 'job']
        widgets = {
            'name': forms.TextInput(),
            'avatar': forms.TextInput(),
            'job': forms.Textarea(),
        }

    def __init__(self, *args, **kwargs):
        super(ProfileForm, self).__init__(*args, **kwargs)
        # checking if an instance exist
        if self.instance.id:
            # then at this point you can set as read only the fields about each case

            if self.instance.level < 1:
                self.fields["avatar"].widget.attrs["readonly"] = True
                self.fields["job"].widget.attrs["readonly"] = True
            elif self.instance.level >= 1 and self.instance.level < 3:
                self.fields["job"].widget.attrs["readonly"] = True
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!