-1

I'm currently doing something like this in my views.py:

def home(request):
    ingredients = Ingredience.objects.all()
    drinks = Ingredience.objects.filter(category_id=1)
    fruits =  Ingredience.objects.filter(category_id=2)
    etc.
    meats = Ingredience.objects.filter(category_id=25)

    return render_to_response('home.html', {'ingredients': ingredients, 'drinks': drinks, 'fruits': fruits, 'meats': meats,}, context_instance=RequestContext(request))

And this is my models.py:

from django.db import models

class IngredienceCategory(models.Model):
    name = models.CharField(max_length=30)

    def __unicode__(self):
        return self.name


class Ingredience(models.Model):
    name = models.CharField(max_length=30)
    category = models.ForeignKey(IngredienceCategory, null=True, blank=True)

    def __unicode__(self):
        return self.name


class Food(models.Model):
    name = models.CharField(max_length=30)
    ingredients = models.ManyToManyField(Ingredience)

    def __unicode__(self):
        return self.name

Is there some trick in django to generate the template objects (i.e. drinks, fruits, meats) dynamically? I don't even know where to start but I thought doing something like this: loop through all ingredients objects and return dictionary which would hold items grouped by category (as in the first example).

There are 2 problems I'm trying to solve with this:

  1. The code for each category object is almost the same so there is a lot of redundancy.
  2. I have to update views.py every time I add new category to the database.

EDIT: In my template I need to be able to access each object (i.e. drinks, fruits, meats etc.) by its own variable (e.g. {{ drinks }}.

finspin
  • 4,021
  • 6
  • 38
  • 66
  • What do you mean, dynamically? Dynamically based on what? – Daniel Roseman Jul 08 '12 at 10:06
  • @DanielRoseman By dynamically I mean that I wouldn't have to type the objects manually one by one in views.py but they would be generated automatically based on the data in the database. Not sure if I'm clear enough. – finspin Jul 08 '12 at 10:14
  • 1
    I still don't really understand what the problem is, I'm afraid. Of course it's possible to get the categories from the database, with Category.objects.all(). Where exactly are you stuck? – Daniel Roseman Jul 08 '12 at 10:19
  • @DanielRoseman I edited my original post. In my template I need to be able to access each object (i.e. drinks, fruits, meats etc.) by its own variable (e.g. {{ drinks }}. Currently I'm doing it by specifying each object manually in my view. I would like to do it automatically. Does this clarify the problem? – finspin Jul 08 '12 at 10:27

1 Answers1

1

Okay, based on your comments, you want to be able to access fruits, meats, etc in your template. Here is one possible solution that's neither incredibly pythonic nor efficient, but that's just to make it easier to understand:

ingredients = Ingredience.objects.all()
context = {}
for i in ingredients:
    context[i.category.name + 's'] = context.get(i.category.name + 's', []) + [i]
return render_to_response('home.html', context, context_instance=RequestContext(request))

Then you could access it as fruits, meats, etc. Does Django have something for what you're looking for exactly? Not as far as I know, it's quite a rare use-case - but maybe some others could provide an answer to that. Essentially what you're trying to achieve is some clever maneuvering of a context dictionary object so that the categories become the keys. If that's the case, you might find some use also looking at this SO question.

Update: Just to clarify what I'm doing in the code above: I create a dictionary called context, and then proceed to loop through all the ingredients. For every ingredient, I add a dictionary entry for the category name, containing an array with the Ingredient. If the name is already in the context dictionary, then it just appends this Ingredient. It does this until all the ingredients have been added to an array accessible by the name of the category it is in.

Community
  • 1
  • 1
Herman Schaaf
  • 46,821
  • 21
  • 100
  • 139
  • By 'vague', I mean I don't know what you are trying to do in the template. Also, do you mean by 'dynamic' that you just want one query and still have all the separate ingredients accessible? – Herman Schaaf Jul 08 '12 at 10:18
  • Thanks for your answer. I'm currently using regrouping but the problem with it is that I'm not able to control each category separately. Simplified example: in left sidebar I want to display items from categories 1, 2, 3 and in right sidebar from categories 4, 5, 6. As far as I understand this is not possible with regroup. – finspin Jul 08 '12 at 10:21
  • Your last edit is spot on in terms of what I'm trying to achieve: turn category names into dictionary keys. Thanks for clarifying this. Regarding the actual solution you posted I can't seem to get it working. To be honest my Django/Python skills are rather limited so I might not fully understand what you are doing there. 1. You are adding 's' to the category names, to my understanding this is not necessary but it's probably just a detail. 2. category.name is in different model than ingredients, are you really able to access it by i.category.name? – finspin Jul 08 '12 at 11:19
  • Also, I'd like to test the outpout of context but I'm not sure how. – finspin Jul 08 '12 at 11:20
  • Yes, you really are able to access related models simply by i.category.name (if `i` has a field named `category`, and the `Category` model has a field named `name`). And yes, the `s` can definitely be left out - in fact, I'd recommend leaving it out - it's just so that it gives you `fruits` instead of `fruit` (singular). Printing context: just use `print context`, and see what the output is in the console running Django – Herman Schaaf Jul 08 '12 at 11:35
  • Perfect, I got it working! The only problem was that dictionary entries were capitalized (because entries in the database are capitalized) while my templates were calling lowercase variables. Once I changed the for loop to 'context[i.category.name.lower()] = context.get(i.category.name.lower(), []) + [i]' it started to work. Thanks a lot for your help on this! – finspin Jul 08 '12 at 17:47