Python/Django Class based saving I'm creating multiple Django apps with vote possibilities, so I made an app vote to handle all this votes. In my templates I'm including an ajax-function named vote. To know on which model I'm liking I add app_name and model_name to the vote function (I made some templatetags to get these values). In my views.py I use model = apps.get_model(app_name, model_name) to get the model class. But now I'm worried a hacker could do something with the app_name and model_name values.

vote/ajax.html (only function):

function vote(bool){
    $.ajax({
        type: "post",
        timeout: 8000,
        url: '{% url 'ajax:vote' %}',
        dataType: 'json',
        data: {
            'csrfmiddlewaretoken': getCookie('csrftoken'),
            'model_name': "{{ model|get_model_name }}",
            'app_name': "{{ model|get_app_name }}",
            'voted': bool,
            'id': "{{ model.id }}",
        },
        success: function(data) {
            if (!data.error){
                if (bool){
                    $(".half .fa-thumbs-up").removeClass("far").addClass("fas");
                    $(".half #count").text(parseInt($(".half #count").text()) + 1);
                } else {
                    $(".half .fa-thumbs-down").removeClass("far").addClass("fas");
                    $(".half #count").text(parseInt($(".half #count").text()) - 1);
                }
            }
        }
    });
}


ajax/views.py:

def vote(request):
    try:
        app_name = request.POST.get("app_name")
        model_name = request.POST.get("model_name")
        id = request.POST.get("id")
        votedFor = True if request.POST.get("voted") == "true" else False
    except ValueError:
        return JsonResponse({"error": True})

    model = apps.get_model(app_name, model_name)

    if model is None or id is None:
        return JsonResponse({"error": True})

    try:
        usable_model = model.objects.get(id=id)
    except model.DoesNotExist:
        return JsonResponse({"error": True})

    try:
        usable_model.vote._meta.get_field("votes")
    except FieldDoesNotExist:
        return JsonResponse({"error": True})

    usable_model.vote.vote(request, votedFor)
    return JsonResponse({"error": False})


vote/functions:

def vote(self, request, votedFor):
    if request.user.is_authenticated:
        if not UserVoted.objects.filter(User=request.user, Vote=self).exists():
            UserVoted.objects.create(User=request.user, Vote=self, votedFor=votedFor)
            self._like_or_dislike(votedFor)
            return True
        return False
    ip = get_client_ip(request)
    if ip:
        if not UserVoted.objects.filter(ip=ip, Vote=self).exists():
            UserVoted.objects.create(ip=ip, Vote=self, votedFor=votedFor)
            self._like_or_dislike(votedFor)
            return True
        return False
    return False

def _like_or_dislike(self, votedFor):
    if votedFor is not None:
        Vote.objects.filter(id=self.id).update(votes=F('votes') + 1) if votedFor else Vote.objects.filter(id=self.id).update(votes=F('votes') - 1)
        return True
    return False


I already manipulated app_name and model_name and the server didn't crash but I don't know what a hacker can do. Can he crash my server when he manipulate these values? (maybe "ajax-injection" or something like this?)
Question


  But now I'm worried a hacker could do something with the app_name and model_name values.
  
  Can he crash my server when he manipulate these values? (maybe "ajax-injection" or something like this?)


I'm not sure what the best approach to this would be. Perhaps it would be wise to define a list of the values that are acceptable for a user to pass there, though maybe that wouldn't be sufficient.

Other review points


function vote(bool){



The name bool is not very descriptive. Given that it is used as the value for the voted parameter a name like voted would be more appropriate. And if your code complies with ecmascript-6 standards you could simply write
    voted

in the list of parameters as a shorthand for voted: voted



The success handler looks like this:


success: function(data) {
    if (!data.error){
        if (bool){
            $(".half .fa-thumbs-up").removeClass("far").addClass("fas");
            $(".half #count").text(parseInt($(".half #count").text()) + 1);
        } else {
            $(".half .fa-thumbs-down").removeClass("far").addClass("fas");
            $(".half #count").text(parseInt($(".half #count").text()) - 1);
        }



There is quite a bit of redundancy in both cases. Also parseInt() calls should pass a radix1.

if (!data.error){
    const thumbClass = '.fa-thumbs-' + bool ? 'up' : 'down';
    $(".half " + thumbClass).removeClass("far").addClass("fas");
    const toAdd = bool ? 1 : -1;
    $(".half #count").text(parseInt($(".half #count").text(), 10) + toAdd);




In the vote function in ajax/views.py there is this line:


votedFor = True if request.GET.get("voted") == "true" else False



This could be simplified to just:

votedFor = request.GET.get("voted") == "true"


1https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt#Octal_interpretations_with_no_radix