0

Having trouble finding a totally clear answer to this question. In my learning, I was taught to not pass along the entire request object when trying to pass data from views.py to models.py (when using a django manager).

However, in my current scenario, I'm trying to setup validation methods in my models.py (using a Manager) whereby I utilize django-messages (https://docs.djangoproject.com/en/1.11/ref/contrib/messages/), to whom one requirement is the request object itself when generating custom errors, such as:

messages.add_message(request, REG_ERR, 'First and last name are required must be at least 2 characters.', extra_tags="reg_errors")

I am trying to keep all validations, error message generation, and creation or retrieval actions inside of my models.py using a manager (https://docs.djangoproject.com/en/1.11/topics/db/managers/), and simply hand back the relevant data to my views.py.

To achieve this, in my views.py, I create a dictionary with the full request object itself, I send this off for all validations/creations, and then check for errors upon the return, as a False is returned if any validation errors were flagged. Otherwise the success page will load with the new user.

views.py:

def register(request):
    if request.method == "POST":

        # Validate registration data submitted from registration form:
        validated = User.objects.register_validate(request)

        # If validation fails, load index page with request object 
        # (which `django messaging` has attached errors to):
        if validated == False:
                print "User could not be registered."
                # Send back index with updated request object:
                return render(request, "logreg/index.html")

        # If validation successful, create new user and send it along with success page:
        else:
            # Load success page with `validated` user (already returned as a `dict` obj.)
            return render(request, "logreg/success.html", validated)

models.py:

# Note: this function snippet is part of `class UserManager(models.Manager)`:
def register_validate(self, request):

    # Check if first_name or last_name is less than 2 characters:
    if len(request.POST["first_name"]) < 2 or len(request.POST["last_name"]) < 2:
        # Add error to Django's error messaging:
        messages.add_message(request, REG_ERR, 'First and last name are required must be at least 2 characters.', extra_tags="reg_errors")

    # ... more validations ...

    # Get current errors to check if any exist:
    errors = get_messages(request)

    # If no validation errors, hash password, create user and send new user back:
    if len(errors) == 0:
        # Hash Password:
        hashed_pwd = bcrypt.hashpw(request.POST["password"].encode(), bcrypt.gensalt(14))
        # Create new validated User:
        validated_user = {
            "logged_in_user": User(first_name=request.POST["first_name"], last_name=request.POST["last_name"], email=request.POST["email"], password=hashed_pwd)
        }
        # Save new User:
        validated_user["logged_in_user"].save()
        # Send newly created validated User back:
        return validated_user
    else:
       return False

Question:

Previously I had extracted all data from the request object via request.POST["my_data"] (did not pass the entire object but extracted what I needed into a custom dict), and was custom generating error messages. However, I wanted to practicing using django-messages, (of which requires the request object as a parameter, as this is what it attaches the errors to). Because I wanted all validations to occur in models.py, I sent my entire request object over (to then extract form data, but to also create new messages with django-messages).

Does passing the entire request object cause major drops in performance or is this bad practices? The fact that my learning lesson went so far out of the way to stress not passing the entire request object was a little confusing to me, especially considering to generate errors in my models.py via django-messages, I need access to the full object.

Any ideas?

Note: The other thought I had was to have my validation functions return a list of errors, to which I could iterate over and generate the django-messages errors (and using the request object in views.py), but this would place more logic/crunching on the controller, and was trying to keep everything nice and tight in the Manager (in models.py) for simplicity/organization.

Thanks in advance for reading, and let me know if I need to clarify any information here presented...was trying to provide a minimal chunk of my code to give context.

twknab
  • 1,741
  • 1
  • 21
  • 35
  • 1
    Validation functions are often carried out by forms (even if the form is not presented in the HTML, the incoming data can be used to initialise a form which then does validation on it using the already inbuilt form validation functions). You can then insert the resulting errors into Django messages if you need to do it that way. It seems like you are somewhat reinventing the wheel. – ChidG May 19 '17 at 02:53
  • 1
    In any case, you do not need to generate the message objects themselves in the model. You could just generate a set of validation errors in the model, pass them back to the view, and instantiate the messages there. – ChidG May 19 '17 at 02:55
  • 1
    I see, I have not yet learned about `djangoforms`, I hear this is the way most approach these things in real-life application. I'm manually performing validations per the requirement of the assignment I'm working on / probably a way to build base understanding prior to using forms. Alas. – twknab May 19 '17 at 02:55
  • Thank you @ChidG: That seems to be the consensus from others I talked to, to keep the django messages generation in the views.py and hand back from models.py a list of errors to be generated. I was trying for an all-in-one swoop approach, where django messages errors are created real-time, but this may not be best for security (so I've been advised). – twknab May 19 '17 at 02:56

1 Answers1

0

Attaching the entire request object does not necessarily hit performance, but it does open up security issues, as if the entire request is being sent to models.py, a spoofed request could interfere with intended functions.

From talking with other developers in a slack channel, it sounds like most people generate a list of errors in models.py, which is handed back to views.py, in which they invoke the django-messages module and create their messages. The primary argument is to limit access to the request object itself, keeping it from models.py and mitigating risk from spoofed requests.

twknab
  • 1,741
  • 1
  • 21
  • 35