Django : ModelForm with conditions

╄→гoц情女王★ 提交于 2019-12-22 08:36:23

问题


I'm trying to create a form variable. As default Player have the level 0 and he can just change is name. Later when he is level 1, he can change is name and is avatar. When he is level 3, he can change is name, is avatar and is job. Etc...

Models.py:

class Player(models.Model):
    level = models.SmallIntegerField(default=0) 
    name = models.CharField(max_length=50)
    avatar = models.URLField(default='http://default-picture.com/01.png')
    job =  models.TextField(null=True)

Fomrs.py:

class ProfileForm(forms.ModelForm):

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

Views.py:

def game(request, id):
    user = get_object_or_404(Player, id=id)
    if request.method == 'POST':
        form = ProfileForm(request.POST, instance=user)
        if form.is_valid():
            form.save()
            return HttpResponse('Success')
    else:
        form = ProfileForm(instance=user)
    return render(request, "page/template.html",
            {'form': form})

Template.html:

{{ form }}

It's possible to add condition for the render of the form before send it to the render engime ? Or I need to do it in my Template with conditions ?

I just when to allow the instanced object to have more or less positibilies in terms of one of these parameters (in the exemple is the level of the player).


回答1:


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



回答2:


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.




回答3:


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


来源:https://stackoverflow.com/questions/43001425/django-modelform-with-conditions

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!