Loop through queryset and store data

Hi,

I have a list of products and for each product i make a GET request against a api to pull in product data. Such as current price and percent changed.

I then what to present the data in a table but i can’t find a way to loop through each product, make the request and store the data to be shown within a table.

I dont want to store the data in a model cause the data from the request will change daily, so it kinda needs to be realtime.

I’ve tried a few things, but can’t get it working.

results = []

    for item in products:        
        data = pt.get_product_by_id(item.product_slug)
        price = (data['product_data']['current_price']['GBP'])       
        day_change_percentage = (data['product_data']['change_percentage_24h'])
        results.append({item:price,item:day_change_percentage})

and then

{{% for item in results %}}
...

Is it even possible to do this?

Yes, it’s possible to do the following in a view:

  • Retrieve data from the database
  • Iterate over that data
  • Make an api call using the data
  • Augment the data
  • Render the results

What exactly are you trying and what is going wrong?

Note: Regarding the code posted, the problem there appears to be some confusion with the syntax in what you’re trying to append to results. What are you trying to append there? A dict? If so, it’s not going to work the way you’re trying because you can’t use an object as the key and you can’t have multiple instances of the same key in a dict.

Hey Ken,

Basically, for each of my users they have a list of products. I am showing that list in a table, which you very kindly helped with (you’ve basically helped build my entire app. :slight_smile: )

As part of the list of items in the table, i am making a call out to an api that returns the current price and the change from yesterday.

So in my view i am getting the list of their products and then making the api call. I then need to take the response of each call for each product and show in the same table as the list of their products

Product Name | Current Price | % Changed |
product 1       API Reponse   Api Response 
product 2       API Reponse   Api Response  
product 3       API Reponse   Api Response   

I was just trying to see if i can append the reponse of each request to the api to a variable so i can reference that variable in my template.

It doesn’t work.

Yes, you can do that.

You have at least two options for doing this:

  • Add the data to the objects in the result set
  • Create a new list of everything you want to render in the response.

Your post indicates you’re trying to do the second option.
The problem with the snippet you posted is this line:

for the reasons specified in my previous response.

Yep this is what i was trying to do. Is that the correct way (The way you would do it?)

So doing the append might be ok, but not using Item as the key? So it needs to be item.something?

You need to have a different key for each value.

Take a step back from Django for a moment and review what and how Python dictionaries work. Then think about how you want to represent your data within results. Then, and only then, think about how you want to build that structure within your view.

I think i understand dictionaries, i know each key is unique and that data can be added/removed/changed after a dictionary has been created.

Within my view i added results = dict{} which i could then append the data to.

I think I’m also going to get into a mess cause i am trying to show both the list of products linked to that user, but that isn;t in this loop.

That’s actually not what you posted:

results is a List, not a Dict. Each element within results is a dict, but results itself is not a dict. (You do not “append” to a dict. You add keys.)

Don’t worry about that yet.

Looking at:

Substitute numeric values for those “API Response” strings, and show me what you think a dictionary would look like to represent just this one row.

Sorry, i have been trying different approaches, getting mixed up.

I want the value in api response to be just the number, but i expect it will be key:value

I’m suggesting you ignore all other considerations at the moment.

Take the snippet I clipped previously of the one row of your representation, and replace that text “API Response” with numbers that make sense to you, and then show the Python code that would created your desired dictionary with that sample.

Product Name | Current Price | % Changed |
product 1            20            1.5
results = dict()
   for item in products:        
        data = pt.get_product_by_id(item.product_slug)
        price = (data['product_data']['current_price']['GBP'])       
        day_change_percentage = (data['product_data']['change_percentage_24h'])
        results.add({item.product_price:price,item.day_change_percentage:day_change_percentage})
{% for each ... %}
Product Name | Current Price | % Changed |
product 1 {{results.product_price}} {{results.day_changed_percentage}}

Im not really sure Ken.

But i see this wont work cause im not defining what the different keys are. So i need to understand how i create a new key/value for each item in products

Forget the Django specific code at the moment.

You have this data:

What Python code could you write to create a dictionary of this data? Just this data - don’t rely upon anything other than what’s quoted here.

If necessary, review some documentation on Python dictionaries. Perhaps the tutorial section in the official Python docs at 5. Data Structures — Python 3.10.2 documentation

Im not sure, but i could just do items = {'ProductName':'product 1', 'CurrentPrice:20','% Changed':1.5}?

But that still have the issue of the keyName not being unique

Yes!

Starting from:

Now, if you keep results as a list, you can create this list, with each element being this dictionary:

results = [
   {'ProductName':'product 1', 'CurrentPrice':20, '% Changed':1.5},
   {'ProductName':'product 2', 'CurrentPrice':30, '% Changed':2.5},
   {'ProductName':'product 3', 'CurrentPrice':40, '% Changed':3.5},
]

Remember, the key names only need to be unique in a dictionary.
In this case, you’re creating multiple dictionaries, all with the same keys to make it easier to refer to them in your template.

:slight_smile:

Right so i have created my list containing my dictionary using:

results = []
results.append = ({'productName':product ...})

That works so im hoping that is the correct way. My next hurdle is looping through whats in Holding and results to create the list of products in 1 table with the current price.

I assume i can do the same with results and append the output of products into the same list of dictionaries?

Close but not quite. append is a method on a list. It should be:
results.append({'productName':product ...})

You can build this dictionary with more fields from your model than just the name. You could also build the dictionary with a reference to the object itself.
Example:
If product is an instance of Product, then {'product': product} is a valid dictionary.

Im not quite sure on this.

for the results dictionary the key/values are appended within a for loop over products.

    profile = Profile.objects.get(user = request.user)
    products = profile.products.all()
for item in products:
...
results.append ({'productName':product ...})

but for holdings i am using holdings = profile.holding_set.all()

How do i add holdings to results so that i can use {% for item in results %} in my template to show current price and the price within holding

Unfortunately, the snippets provided make it difficult to answer your question in context. Please post the complete view.

Sorry Ken, here is the view

@login_required
def index(request):

    pt = productAPI()
    profile = Profile.objects.get(user = request.user)
    products = profile.products.all()
    holdings = profile.holding_set.all()
    results=[]
    for item in products:
        if item.product_slug is not None:
            data = pt.get_product_by_id(item.product_slug)
            price = (data['market_data']['current_price']['GBP'])
            day_change_percentage = (data['market_data']['price_change_percentage_24h'])
            results.append({'price':price,'day_change_percentage':day_change_percentage})
        else:
            pass    

    
    return render(request, 'index.html',{"holdings":holdings,"results":results})

Can i just add "holdings.product_name":holdings_product_name to the results? within the for loop

I’m looking for the models for these and am not seeing them in a prior reply in this post.

Is there a relationship between products and holdings? If not, what you’re asking doesn’t seem to make sense to me. If there is, then you should be using that relationship to retrieve the holdings instead of the global query.