2
\$\begingroup\$

I have been looking over this block of code for hours trying to simplify it. Would there be a better way to check all those conditions before creating a transaction object without using so many if-elses?

def create(self, validated_data):

    user = self.context['request'].user
    if user.role == 'super_admin':  # ref PR 25.1
        return Transaction.objects.create(**validated_data)
    elif user.role == 'user' or user.role == 'org_admin' or user.role == 'site_admin':  # ref PR 25.4
        if check_user_institution_exists(validated_data['user_institution'].id):
            if check_user_belongs_to_institution(validated_data['user_institution'].id, None, user.id) > 0:
                if check_upload_permission(validated_data['user_institution'].id):
                    return Transaction.objects.create(**validated_data)
                else:
                    raise serializers.ValidationError({'Error': 'You do not have upload permission for this '
                                                                'institution.'})
            else:
                raise serializers.ValidationError({'Error': 'You do not belong to this institution.'})
        else:
            raise serializers.ValidationError({'Error': 'This user institution does not exist.'})
    else:
        raise serializers.ValidationError({'Error': 'You are not assigned a role.'})
\$\endgroup\$
2
  • \$\begingroup\$ Are you possibly missing an else for the outer-most if, elif? \$\endgroup\$ Commented Oct 1, 2018 at 14:20
  • \$\begingroup\$ You're right, I have edited my question \$\endgroup\$ Commented Oct 1, 2018 at 14:21

1 Answer 1

3
\$\begingroup\$
  1. You don't need to use elif you can change that to just an if.
  2. You can simplify code blocks by using guard clauses that have the following layout:

    if a:
        ...
    else:
        raise b
    

    To:

    if not a:
        raise b
    
    ...
    
  3. You can use a in [b, c] rather than a == b or a == c.
  4. As commented by Michel Billaud, "The code will be shorter with an auxiliary variable id = validated_data['user_institution'].id".

Employing the above would get the following which I find to be much easier to read.

def create(self, validated_data):
    user = self.context['request'].user
    if user.role == 'super_admin':  # ref PR 25.1
        return Transaction.objects.create(**validated_data)

    if user.role not in ['user', 'org_admin', 'site_admin']:  # ref PR 25.4
        raise serializers.ValidationError({'Error': 'You are not assigned a role.'})

    id_ = validated_data['user_institution'].id
    if not check_user_institution_exists(id_):
        raise serializers.ValidationError({'Error': 'This user institution does not exist.'})

    if check_user_belongs_to_institution(id_, None, user.id) <= 0:
        raise serializers.ValidationError({'Error': 'You do not belong to this institution.'})

    if not check_upload_permission(id_):
        raise serializers.ValidationError({'Error': 'You do not have upload permission for this '
                                                    'institution.'})

    return Transaction.objects.create(**validated_data)
\$\endgroup\$
3
  • \$\begingroup\$ The code will be shorter with an auxiliary variable id = validated_data['user_institution'].id \$\endgroup\$ Commented Oct 1, 2018 at 14:32
  • \$\begingroup\$ @MichelBillaud That's right, I'll add that now :) \$\endgroup\$ Commented Oct 1, 2018 at 14:33
  • \$\begingroup\$ also, the last three tests could be delegated to a function call assert_user_institution_allows_upload(id_,institution_) whose role is to raise some exception if user is not allowed. \$\endgroup\$ Commented Oct 3, 2018 at 14:56

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.