8
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ビットスターAdvent Calendar 2021

Day 5

DjangoのORMでいろいろ試してみた

Last updated at Posted at 2021-12-04

MySQLでデータ取得する時はこうSQLを書くけど、DjangoのQuerySetを取得する時はどうするんだろうと思うことがあり、いろいろ試してみました。

環境

  • Django 2.2.3
  • Python 3.7.4

内部結合したテーブルのpk以外で検索したい

modelsはそれぞれコードと名前のフィールドを持ち、市テーブルに都道府県テーブルと紐づけるForeignKeyを設定しています。
紐づけるフィールドはpk(プライマリーキー)にするので、to_field等は指定していません。

models.py
from django.db import models

class Pref(models.Model):
    pref_cd = models.IntegerField(null=False, unique=True)
    pref_name = models.CharField(max_length=255, null=False)

    class Meta:
        db_table = 'pref'


class City(models.Model):
    pref = models.ForeignKey(
        Pref,
        on_delete=models.SET_NULL,
        null=True
    )
    city_cd = models.IntegerField(null=False)
    city_name = models.TextField(max_length=255, null=False)

    class Meta:
        db_table = 'city'
        unique_together = (('pref', 'city_cd'))

SQL

SELECT * 
FROM city 
    INNER JOIN pref ON pref.id = city.pref_id
WHERE pref.pref_name = '{都道府県名}';

QuerySet

<ForeignKeyを設定したフィールド名>__<検索したいフィールド名>で検索できます。

City.objects.filter(pref__pref_name='{都道府県名}')

内部結合したテーブルのpk以外でソートしたい

SQL

SELECT * 
FROM city 
    INNER JOIN pref ON pref.id = city.pref_id 
ORDER BY pref.pref_cd DESC;

QuerySet

検索と同じように<ForeignKeyを設定したフィールド名>__<ソートしたいフィールド名>でソートできます。

City.objects.order_by('pref__pref_cd').reverse().all()

ForeignKeyを設定していないテーブル同士で結合して検索したい

ForeignKeyは設定せず、市テーブルにも都道府県名を持つようにしています。

models.py
from django.db import models

class Pref(models.Model):
    pref_cd = models.IntegerField(null=False, unique=True)
    pref_name = models.CharField(max_length=255, null=False)

    class Meta:
        db_table = 'pref'


class City(models.Model):
    city_cd = models.IntegerField(null=False)
    city_name = models.TextField(max_length=255, null=False)
    pref_name = models.TextField(max_length=255, null=False)

    class Meta:
        db_table = 'city'

SQL

SELECT city_name 
FROM city 
    INNER JOIN pref ON pref.pref_name = city.pref_name 
WHERE pref.pref_cd = {都道府県コード};

QuerySet

City.objects.extra(
    tables=['pref'],
    where=['city.pref_name=pref.pref_name']
).extra(where=['pref.pref_cd={都道府県コード}']).all()

このクエリを出力してみるとわかりますが、
SQL的にはWHERE ((city.pref_name=pref.pref_name) AND (pref.pref_cd={都道府県コード})) と結合はしていません。
ほしいデータが取得できたからよしとしましたが、prefテーブルのデータは取得できないので注意です。

8
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?