Django検索で姓と名で分けたフィールドをフルネームで検索させたい

## 概要
Djangoで検索ボックスを作っている時に、姓だけで検索、名だけで検索はできるがフルネームで検索したいという気分だったのでやり方を調べてみました。

モデルについては社員が複数人おり、複数のオフィスに属する可能性があるのでmanyToManyで作成しております。

```python:models.py
from django.db import models


class Office(models.Model):
    name = models.CharField("営業所名", max_length=50)
    code = models.CharField("営業所記号", max_length=10, null=True, blank=True)

    def __str__(self):
        return self.name

class Employee(models.Model):
    employeeNo = models.CharField(
        "社員番号",
        null=True,
        blank=True,
        max_length=5,
        unique=True
    )
    lastName = models.CharField("姓", max_length=30)
    firstName = models.CharField("名", max_length=30)
    lastName_furigana = models.CharField("姓フリガナ", max_length=30)
    firstName_furigana = models.CharField("名フリガナ", max_length=30)
    belong_to_office = models.ManyToManyField(Office)
    date_of_employment = models.DateField("入社日", blank=True, null=True)
    date_of_leaving = models.DateField("退社日", blank=True, null=True)
    created_at = models.DateTimeField("作成日", auto_now_add=True)
    updated_at = models.DateTimeField("更新日", auto_now=True)

    def __str__(self):
        return self.lastName + self.firstName
```

``` python:views.py
from django.views.generic import ListView
from django.db.models.functions import Concat
from django.db.models import Q
from .models import Employee, Office

class EmployeeListView(LoginRequiredMixin, ListView):
    model = Employee
    template_name = "manager/employee_list.html"
    paginate_by = 50

    def get_queryset(self):

        q_word = self.request.GET.get('query')

        if q_word:
            # 空白文字を完全に削除する
            q_word = q_word.replace(' ','')
            q_word = q_word.replace('　','')
            # フルネームフィールドを追加して検索条件に追加
            object_list = Employee.objects.annotate(full_name=Concat('lastName','firstName')).filter(
                Q(lastName__icontains=q_word) |
                Q(firstName__icontains=q_word) |
                Q(lastName_furigana__icontains=q_word) |
                Q(firstName_furigana__icontains=q_word) |
                Q(employeeNo__icontains=q_word) |
                Q(belong_to_office__name__icontains=q_word) |
                Q(belong_to_office__code__icontains=q_word) |
                Q(full_name__icontains=q_word)
            ).order_by('pk').distinct()

        else:
            object_list = Employee.objects.all().order_by('pk')
        return object_list
```

```django:employee_list.html

　　　　　　省略
            <div class="col-12 col-lg-6">

                <form action="" method="get">

                    <div class="input-group">

                        <input name="query" class="form-control" type="text" placeholder="検索条件を入力"
                            value="{{ request.GET.query }}" aria-label="Search for..."
                            aria-describedby="btnNavbarSearch" />
                        <button class="btn btn-primary" type="submit"><i class="fas fa-search"></i></button>
                    </div>
                </form>
            </div>
```

## ポイント
ポイントとしてはEmployee.object.annotateでfull_nameというフィールドを新しく追加してその中身に、元々のlastNameフィールドの値とfirstNameのフィールドをConcatを使って結合してから入れている所です。