johannes
johannes

Reputation: 1448

Django 3: Filter queryset for letter or non-letter

In my database I have a table with items who's titles can start with a letter or a non-letter-character. For example a number or an "@" or a "#". The model looks like this:

class Items(models.Model):
    title = models.CharField(max_length=255)
    body = models.TextField

In my view I would like to separate the model into two objects. One objects that contains all the item with a title starting with a letter and an other object with all the other items:

class ItemsView(TemplateView):
    template_name = "index.html"

    def get_context_data(self, **kwargs):
        alpha_list = Items.objects.filter(title__startswith=<a letter>)
        other_list = Items.objects.filter(title__startswith=<not a letter>)

        context = {
            "list_a": alpha_list,
            "list_b": other_list
        }

        return context

I have been consulting the documents, stackoverflow and the holy google, but so far I have not been able to find a solution.

Any help is very much appreciated.

Upvotes: 5

Views: 1948

Answers (2)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477854

You can slightly optimize the regular expression to:

# starts with an A-Za-z
Item.objects.filter(title__regex='^[A-Za-z]')

# starts not with A-Za-z
Item.objects.exclude(title__regex='^[A-Za-z]')

but a more important question is of course, what is a letter here. Here it will not match non-latin characters, such as Cyrillic, Arabic, etc. Furthermore it will not match characters with diacritics like äöüßÄÖÜ, etc. You can add extra characters or character ranges to the character block (the [A-Za-z…]) part to work with extra characters.

You can for example make use of Latin-1 Supplement [wiki], Latin Extended-A [wiki], Latin Extended-B [wiki] and Latin Extended Addition [wiki] as well with:

# starts with a Latin character
Item.objects.filter(title__regex='^[A-Za-z\uC0-\u024F\u1E00-\u1EFF]')

But we might want to add Arabic, Cyrillic, etc. characters as well.

Upvotes: 2

Linh Nguyen
Linh Nguyen

Reputation: 3920

You can use regex to filter (use regex101.com to test your regex) and exclude to find other Items not start with a letter

start with a letter:

alpha_list = Items.objects.filter(title__regex=r'^[a-zA-Z].*$')

the other cases:

other_list = Items.objects.exclude(title__regex=r'^[a-zA-Z].*$')

Explanation:

/^[a-zA-Z].*$/

^ asserts position at start of the string 

a-z a single character in the range between a (index 97) and z (index 122) (case sensitive) 

A-Z a single character in the range between A (index 65) and Z (index 90) (case sensitive) 

.* matches any character (except for line terminators)

* Quantifier — Matches between zero and unlimited times, as many times as possible, giving back as needed 

$ asserts position at the end of the string, or before the line terminator right at the end of the string (if any)

Upvotes: 8

Related Questions