代码之家  ›  专栏  ›  技术社区  ›  Snoeren01

在Django ORM中引用非主外键

  •  1
  • Snoeren01  · 技术社区  · 3 年前

    如果外键引用的不是主键,而是具有唯一约束的另一列,我如何根据Django的ORM中另一个表中的条件来选择一个表的条目?
    相应的SQL命令为:

    SELECT TableMoon.name
    FROM TableMoon JOIN TablePlanet
    ON TableMoon.planet = TablePlanet.name
    WHERE classification = 'inner_planet';
    

    预期的答案是:月球、火卫一、Deimos

    我试图在Django ORM中用“planet”或“planet_id”重写上面的SQL命令,但每次都得到一个空的QuerySet:

    Tablemoon.objects.filter(planet__classification='inner_planet').values('name')
    #Out: <QuerySet []>
    
    Tablemoon.objects.filter(planet_id__classification='inner_planet').values('name')
    #Out: <QuerySet []>
    

    背景
    我有一个Django应用程序,它连接到一个遗留的sqlite数据库。我不允许修改数据库方案。数据库如下所示:

    TablePlanet  
    ------------------------------------  
    planet_id |  name   | classification  
    ------------------------------------  
    1         | Mercury | inner_planet  
    2         | Venus   | inner_planet  
    3         | Earth   | inner_planet  
    4         | Mars    | inner_planet  
    5         | Jupiter | outer_planet  
    6         | Saturn  | outer_planet  
    7         | Uranus  | outer_planet  
    8         | Neptune | outer_planet  
    
    TableMoon  
    ------------------------  
    moon_id | planet  | name
    ------------------------  
    1       | Earth   | Moon  
    2       | Mars    | Phobos  
    3       | Mars    | Deimos  
    4       | Jupiter | Io  
    5       | Jupiter | Europa  
    6       | Jupiter | Ganymede  
    

    该列 TablePlanet.name 具有唯一约束。该列 TableMoon.planet 具有引用的外键约束 TablePlanet.name 。

    这是表的SQL代码:

    CREATE TABLE tablePlanet (
      planet_id INTEGER PRIMARY KEY,
      name TEXT UNIQUE NOT NULL,
      classification TEXT
    );
    
    CREATE TABLE tableMoon (
      moon_id INTEGER PRIMARY KEY,
      planet TEXT,
      name TEXT,
      FOREIGN KEY (planet) REFERENCES tablePlanet(name)
    );
    

    我的models.py文件如下

    from django.db import models
    
    
    class Tableplanet(models.Model):
        planet_id = models.AutoField(primary_key=True, null=False)
        name = models.TextField(unique=True)
        classification = models.TextField(blank=True, null=True)
    
        class Meta:
            managed = False
            db_table = 'tablePlanet'
    
    
    class Tablemoon(models.Model):
        moon_id = models.AutoField(primary_key=True, null=False)
        planet = models.ForeignKey('Tableplanet', models.DO_NOTHING,
                                   db_column='planet', blank=True, null=True)
        name = models.TextField(blank=True, null=True)
    
        class Meta:
            managed = False
            db_table = 'tableMoon'
    

    让我困惑的第一件事是Django对行星列的命名,在一种情况下是“planet”,在另一种情况中是“planet_id”:

    Tablemoon._meta.get_fields()
    #Out: (<django.db.models.fields.AutoField: moon_id>,
    #Out:  <django.db.models.fields.related.ForeignKey: planet>,
    #Out:  <django.db.models.fields.TextField: name>)
    
    Tablemoon.objects.all().values()[0]
    #Out: {'moon_id': 1, 'planet_id': 'Earth', 'name': 'Moon'}
    

    我很感激你在这方面的任何建议!

    1 回复  |  直到 3 年前
        1
  •  2
  •   willeM_ Van Onsem    3 年前

    你的 ForeignKey 需要指定正确的 to_field=…  [Django-doc] ,因为它不引用 Tableplanet :

    class Tablemoon(models.Model):
        moon_id = models.AutoField(primary_key=True, null=False)
        planet = models.ForeignKey(
            'Tableplanet',
            models.DO_NOTHING,
            db_column='planet',
            blank=True,
            null=True,
            to_field='name',
        )
        name = models.TextField(blank=True, null=True)
    
        class Meta:
            managed = False
            db_table = 'tableMoon'

    笔记 :型号通常没有 Table 前缀模型不是表,它作为表存储在关系数据库中,但即使这样,它也有额外的逻辑,如验证器、管理器等。