0

I am trying write a method for one of my models, that will end up with a list of boolean values based on a manytomany field. So I am looping though category id's and comparing them with a queryset, but I can't work out how to translate what I get in the shell to a function. I've been struggle with OOP for about 3 years now, which is why I started learning django in the first place.

but basically, in the django shell, I can do this to get the queryset I want:

p1 = Project.objects.get(id=2)
p1.update_categories.all().values_list('id', flat=True)

<QuerySet [1, 4]>

The problem I have is that this is for one project and I can't figure out how you translate that into something that will work for all instances. So far I have this:

def checkmark(self):
        '''
        Generates a list of True or False based on many to many field
        for Project and UpdateCategory
        '''
        checkmark = []

        # This is the line giving me issues
        queryset = Project.objects.filter(project=self, update_categories) 

        # this bit all works fine
        categories = UpdateCategory.objects.all().values_list('id', flat=True)
        for cat_id in categories:
            if cat_id in queryset:
                checkmark.append(True)
            else:
                checkmark.append(False)
        return checkmark

So what I am doing here is creating an empty list, "checkmark" (for want of a more descriptive variable name), then I am trying to recreate that same queryset in a variable "queryset", then I iterate over the different categories of which there are exactly 7 and append True if the category id is in the queryset and False if it's not. The result I am expecting is:

[True, False, False, True, False, False, False]

I've no idea if this is the right way to go about this, but if it works, it's a start.

2
  • Is this checkmark() a method of the Project model? Commented Aug 28, 2019 at 9:37
  • If so, why don't you just return self.update_categories.values_list('id', flat=True)? Commented Aug 28, 2019 at 9:38

1 Answer 1

2

You're making things much more complicated than they have to be:

# nb: the .all() is redundant, it's only needed if you don't
# apply any other selection
queryset = self.update_categories.values_list('id', flat=True)

Also note that the rest of this method is rather inefficient and that you can probably get the same results from the database itself (relational databases are much more than mere bitbuckets) using queryset annotations - or at least use sets and list comprehension:

mine = set(self.update_categories.values_list('id', flat=True))
cats = UpdateCategory.objects.values_list('id', flat=True)
checkmarks = [cat_id in mine for cat_id in cats]
Sign up to request clarification or add additional context in comments.

3 Comments

The original issue I have is that if I iterate over this in the template, it will only give the two True values, so iterating over these will put the data in the wrong place unless I do the logic in the template which will be cumbersome if even possible. This is to produce a tick mark or a cross based on if it is True or False, so I saw a list as the easiest way. EDIT: sorry didn't see the last bit, that looks much better, I'll check it out
"checkmarks = [cat_id in mine for cat_id in cats]", that's genius, I didn't know you could do that! Thank you.
@iFunction you should still look at queryset annotations - a SQL database can do the same computation, but much faster (and you'd have the flag directly set on the categorie object, which makes the template code simpler).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.