How to call a view from within itself in a Django REST API?

Question:

I have this function in my Django REST API that handles the insertion of products. Sometimes a product will be a variational product (when product.type = 3), in which case I get all the permutations of these variations and want to insert a new product corresponding to each permutation into the database.

@api_view(['POST'])
def upsertProduct(request):
    productData = request.data['product']
    variations = productData.pop('variations', [])
    variationTypes = productData.pop('variationTypes', [])

    product, created = Product.objects.update_or_create(pk=productData['id'], defaults=productData)

    if (productData['type'].id == 3):
        variations_by_type = []
        for variationType in variationTypes:
            variations_by_type.append([variation for variation in variations if variation['variationType'] == variationType['id']])

        combinations = list(itertools.product(*variations_by_type))
        for combination in combinations:
            productData['name'] = product.name + ' (' + ' | '.join(' : '.join(i['name'] for i in item) for item in combination) + ')'
            productData['type'] = {'id': 5}
            productData['parent'] = product.id
            #Recursive call should go here
            #upsertProduct(request={'data': {'product': productData}})

My first attempt was to simply call the function as I did in the commented line. Django returned the following

AssertionError: The request argument must be an instance of
django.http.HttpRequest, not builtins.dict.

I then attempted making use of this HttpRequest object from Django, but can not figure out how to use it properly for this use case. I’ve also tried the standard request library in Python, without success, and I am also pretty sure that wouldn’t be an ideal solution even if it did work.

Asked By: Christiaan Louw

||

Answers:

In general, I wouldn’t create directly a HttpRequest object that would be used by a view somewhere else, because it contains much more information than the payload data, such as session, user, middleware, context info, etc.

What you could do in your code, is keeping the single request variable as is and make another function that handles a dictionary of data.

For example, taking what you wrote, that would give something like:

def handle_data(productData):
    """
    Handle a dictionary of data 
    """
    product, created = Product.objects.update_or_create(pk=productData['id'], defaults=productData)
    return product
    

@api_view(['POST'])
def upsertProduct(request):
    productData = request.data['product']
    variations = productData.pop('variations', [])
    variationTypes = productData.pop('variationTypes', [])

    product = handle_data(productData)

    if (productData['type'].id == 3):
        variations_by_type = []
        for variationType in variationTypes:
            variations_by_type.append([variation for variation in variations if variation['variationType'] == variationType['id']])

        combinations = list(itertools.product(*variations_by_type))
        for combination in combinations:
            productData['name'] = product.name + ' (' + ' | '.join(' : '.join(i['name'] for i in item) for item in combination) + ')'
            productData['type'] = {'id': 5}
            productData['parent'] = product.id
            handle_data(productData)
Answered By: Val Berthe