2

Let's say I have the following model:

class Folder(models.Model):
    name = models.CharField(default='untitled', max_length=255)
    parent = models.ForeignKey('self', null=True, blank=True)
    root = models.ForeignKey('self', null=True, blank=True)
    user = models.ForeignKey(settings.AUTH_USER_MODEL)

In my app, this class is used to represents two types of folders: a normal folder-object and a so called root_folder-object, which does not have a parent nor a root-FK set.

I created a custom ModelForm with custom clean(), which is working like a charm (according to unittests and manual testing):

class FolderForm(ModelForm):

    def __init__(self, *args, **kwargs):
        try:
            data = kwargs.get('data', None).copy()
        except AttributeError:
            data = None
        self.prefix = kwargs.get('prefix')
        user = kwargs.pop('user', None)

        if data is not None:
            if user is not None:
                data[self.add_prefix('user')] = user.id
            kwargs['data'] = data

        super(FolderForm, self).__init__(*args, **kwargs)

    def clean(self):
        # just working fine, so I won't include it here
        pass

    class Meta:
        model = Folder
        fields = '__all__'

So, because my root-folder is just a normal Folder-object with blank FKs, I don't want to even show these fields to the user while creation. I created another form for this:

class AddRootFolderForm(FolderForm):
    class Meta:
        model = Folder
        exclude = ['parent', 'root', 'user']

As you can see, I exclude user aswell, this value will be set in the view. Currently, this is my view code:

@login_required
def create_rootfolder(request):
    if request.method == 'POST':
        form = FolderForm(data = request.POST,
                          user = request.user)
    else:
        form = AddRootFolderForm()

    if form.is_valid():
        new = form.save()
        return redirect('show_rootfolder', root_id = new.id)

    return render(request, 'create_rootfolder.html',
                  { 'form': form })

This whole setup is working, but seems awful hackerish. Is there any better approach to hide certain fields from the user (meaning: Don't even show them as hidden fields), but include them in validation? My main problem is, that I can't use the same form for displaying and validating, because the excluded fields will not be validated, if I use AddRootFolderForm as single form instance.

I am aware that I can exclude the fields dynamically in the constructor, I even tried this, but it got my constructor bloated to 50 LOC, which seemed unclean.

So what would be the best approach to validate the model with all fields, even if they were not included in the form shown to the user?

Mischback
  • 843
  • 5
  • 18

1 Answers1

0

Why validate fields, not used in Form?

The cleaning process is the way to check the data posted by a user. The rest of the data, required for Model operations must be added after the form validation

 if form.is_valid():
     new = form.save(commit=False)
     new.user = request.user
     ...
     new.save()
igolkotek
  • 1,687
  • 18
  • 16
  • Following this (excellent) [answer on stackoverflow](http://stackoverflow.com/questions/12578908/separation-of-business-logic-and-data-access-in-django), I'm using the form to contain business logic. I.e. a user may only add folders to a _root-folder_, that is owned by himself. So to consider a (to be created) _folder_ **valid**, the folder's user must be identical to the folder's root-folder's user. – Mischback Jun 28 '15 at 10:04
  • Great. But clean procedure is not performed for the fields excluded from the form. Thus, you have to iterate all excluded clean_field procedures manually from the form clean procedure. Looks a bit ugly, sorry. – igolkotek Jun 28 '15 at 10:54
  • That's exactly my problem! If I exclude fields, they are not in `cleaned_data`, thus, I can not really validate them. I tried to tackle this problem by using different forms for display and validation, but it seems so not-pythonic, not DRY, so dirty. – Mischback Jun 28 '15 at 10:59
  • Sorry, I was incorrect. You do not need to validate them! Just use execute method as described to add your logics – igolkotek Jun 28 '15 at 11:10