Django ORM LEFT JOIN SQL
Добрый день) Подскажите пожалуйста, в django models в Foreign Key, при создании соединения, создается ячейка в базе _id по которой в последствии выполняются JOIN запросы, подскажите как указать свою ячейку по которой делать JOIN, не могу создать таблицы в уже созданной базе данных
I need a banal simple LEFT JOIN without connection with _id.
Or specify another cell in the database for JOIN instead of _id, for example
CastleModels.id = ClanModels.hasCastle
class ClanInfoModels(models.Model):
clan_id = models.IntegerField()
name = models.CharField(max_length=80)
class Meta:
db_table = 'clan_subpledges'
managed = False
class ClanModels(models.Model):
clan_id = models.IntegerField()
hasCastle = models.IntegerField(primary_key=True)
class Meta:
db_table = 'clan_data'
managed = False
class CastleModels(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=11)
class Meta:
db_table = 'castle'
managed = False
ordering = ['id']
need sql query =
SELECT castle.name, castle.id, clan_subpledges.name
as 'name_clan'
FROM замок
LEFT JOIN clan_data ON clan_data.hasCastle = castle.id
LEFT JOIN clan_subpledges ON clan_subpledges.clan_id = clan_data.clan_id
Просто назовите свое поле.
class ClanModels(models.Model):
clan_id = models.IntegerField()
hasCastle = models.ForeignField('CastleModels', db_column='hasCastle', on_delete=models.Cascade)
Вы можете использовать Subquery для решения вашей проблемы, но не должны. Я думаю, что проблема вашего кода в том, что модели определены неправильно. Это должно быть так:
class ClanInfo(models.Model):
clan = models.ForeignKey('Clan')
name = models.CharField(max_length=80)
class Meta:
db_table = 'clan_subpledges'
managed = False
class Clan(models.Model):
id = models.IntegerField(primary_key=True)
hasCastle = models.ForeignKey('Castle')
class Meta:
db_table = 'clan_data'
managed = False
class Castle(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=11)
class Meta:
db_table = 'castle'
managed = False
ordering = ['id']
Тогда вы можете просто запросить следующим образом:
Castle.objects.values('name', 'id', 'clan__claninfo__name')
Чтобы узнать, как работает обратный запрос, пожалуйста, прочитайте документацию. FYI: Я удалил Models
из каждого имени класса модели, потому что вам не нужно добавлять Models к имени класса, идентифицируя его как модель.
Кроме того, если вы настаиваете на сохранении существующего кода, то следующий код может работать, используя subquery:
from django.db.models import OuterRef, Subquery
outer_query = ClanInfo.objects.filter(clan_id=OuterRef('id'))
CastleModels.objects.annotate(clan_subpledges=Subquery(outer_query.values('name')[:1]).values('id', 'name', 'clan_subpledges')
Используйте преимущества опции db_column
в определении модели Django.
db_column: Имя колонки базы данных, которую следует использовать для этого поля.
Ваш SQL можно записать как
from django.db.models import F
from .models import CastleModels
queryset = CastleModels.objects.values('name', 'id', name_clan=F('clanmodels__claninfomodels__name'))
Я не могу полностью вывести дизайн вашей модели, но если
- замок может содержать ноль или несколько кланов, а
clan_id
фактически является первичным ключом клана.
Тогда модели могут быть определены как:
class CastleModels(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=11)
class Meta:
db_table = 'castle'
managed = False
ordering = ['id']
class ClanModels(models.Model):
clan_id = models.IntegerField(primary_key=True)
hasCastle = models.ForeignKey(CastleModels, on_delete=models.DO_NOTHING, db_column='hasCastle')
class Meta:
db_table = 'clan_data'
managed = False
class ClanInfoModels(models.Model):
clan_id = models.OneToOneField(ClanModels, on_delete=models.DO_NOTHING, db_column='clan_id')
name = models.CharField(max_length=80)
class Meta:
db_table = 'clan_subpledges'
managed = False