Python Django忘记了。使用数据库解析外键

Python Django忘记了。使用数据库解析外键,python,mysql,django,django-rest-framework,serialization,Python,Mysql,Django,Django Rest Framework,Serialization,我有一个由manage.py inspectdb创建的遗留数据库模型,该模型访问设置中名为“edlserver”的数据库,该数据库是项目使用的众多数据库之一。我无法更改数据库布局 它有以下类别(除其他无关类别外): 一个用于记录条目 class Logs(models.Model): time = models.DateTimeField() job = models.ForeignKey(Jobs, models.DO_NOTHING, db_column='id_job') ms

我有一个由manage.py inspectdb创建的遗留数据库模型,该模型访问设置中名为“edlserver”的数据库,该数据库是项目使用的众多数据库之一。我无法更改数据库布局

它有以下类别(除其他无关类别外):

一个用于记录条目

class Logs(models.Model):
  time = models.DateTimeField()
  job = models.ForeignKey(Jobs, models.DO_NOTHING, db_column='id_job')
  msg = models.TextField()

  class Meta:
    managed = False
    db_table = 'logs'
作业的另一个(作业字段引用的)

还有一个是针对工作类型的

class JobTypes(models.Model):
  name = models.CharField(max_length=255)
  max_processes = models.IntegerField()

  class Meta:
    managed = False
    db_table = 'job_types'
django rest框架的视图如下所示

class EDLLogList(generics.ListAPIView):
  serializer_class = EDLLogsSerializer
  filter_backends = (filters.DjangoFilterBackend, )
  filter_class = EDLLogsFilter    

  def get_queryset(self):
    if not 'job_name' in self.request.GET:
      raise ParameterRequired('job_name')
    else:
      return Logs.objects.all().using('edlserver')
它使用过滤器:

class EDLLogsFilter(filters.FilterSet):
  time_start = django_filters.DateTimeFilter(name="time", lookup_type='gte')
  time_end   = django_filters.DateTimeFilter(name="time", lookup_type='lte')
  job_name   = django_filters.MethodFilter()      

  class Meta:
    model = Logs
    fields = ()

  def filter_job_name(self, queryset, job_name):
    try:
      q = queryset.filter(job__job_type__name=job_name)[:10000]
    except:
      raise InternalError()

    if len(q) < 1 and 
       len(JobTypes.objects.all().using('edlserver').filter(name=job_name)) < 1:
         raise InvalidParameter(job_name, 'job_name')
    else:
        return q
问题是我在序列化程序的
get\u job\u name()
中得到了一个
TypeError:“Logs”对象不可下标,它来自psycopg2模块-但是,该数据库是一个MySQL数据库。在调试期间,第一个查询有一个len>0的queryset,这表明该模型是正常的,django使用MySQL后端获取数据。在解析外键时,出现了一些问题,使用了(我认为)默认数据库,即PostGreSQL

这是虫子吗

如果没有,我能做什么?我在考虑一个路由器,它可以解析一个元字段。这将意味着对其他车型有很多改变,所以我不想这样做。有什么想法吗

编辑:数据库的设置

'default': {
    'ENGINE': 'django.db.backends.postgresql_psycopg2',
    'NAME': 'pic',
    'USER' : 'pic-5437',
    'PASSWORD' : '',    
    'HOST' : 'host1.url.com',
    'PORT' : '5432'    
},
'...' : {
    ...
},
'edlserver': {
    'ENGINE': 'django.db.backends.mysql',
    'HOST': 'host2.url.com',
    'NAME': 'edl',
    'USER': 'edl_ro',
    'PASSWORD': '',
}

问题是这里的obj是
日志的一个实例

def get_job_name(self, obj):
   return obj['id_job__id_job_type__name']
Django模型看起来像字典,闻起来像字典,但它们不是字典。正确的用法是:

  return obj.job.job_type.name
我建议您打开一个django shell,加载一个而不是日志,使用help()命令并尝试使用路径


至于第二个问题,查询使用了错误的数据库,您需要定义或添加查询。

外键向模型添加一个属性,该属性本身就是模型实例。要遵循从
日志
作业类型
的完整关系,只需使用属性查找:

def get_job_name(self, obj):
    return obj.job.job_type.name
这将是正常的用例。如果使用了多个数据库,并且django在解析外键时使用了错误的数据库,则可以手动执行此操作:

 return JobTypes.objects.all().using('edlserver').filter(id=
   Jobs.objects.all().using('edlserver').filter(id=
   obj.job_id)[0].job_type_id)[0].name
另一种选择是在模型中引入元字段,如下所示:

import django.db.models.options as options
options.DEFAULT_NAMES = options.DEFAULT_NAMES + ('in_db',)

class MyModel(models.Model):
  class Meta:
    in_db = 'edlserver'
然后需要一个数据库路由器:

class DatabaseMetaRouter(object):
def db_for_read(self, model, **hints):
    """
    Route to the given in_db database in Meta
    """
    if hasattr(model._meta, 'in_db'):
        return model._meta.in_db
    else:
        return 'default'

def db_for_write(self, model, **hints):
    """
    Route to the given in_db database in Meta
    """
    if hasattr(model._meta, 'in_db'):
        return model._meta.in_db
    else:
        return 'default'

def allow_relation(self, obj1, obj2, **hints):
    """
    Always allow
    """
    return True

def allow_migrate(self, db, app_label, model_name=None, **hints):
    """
    Always allow
    """
    return True

请使用settings.py的databases部分更新您的问题,并删除不必要的模型这些模型都是必需的,因为它们显示了外键关系。我在数据库里编辑过。我刚刚试过<代码>属性错误:“日志”对象没有属性“id\u作业\u id\u作业\u类型\u名称”
列出结果。我还尝试了
return obj.job.job\u type.name
,结果是
psycopg2.ProgrammingError:relationship“jobs”不存在第1行:…bs.“.time\u end”,“jobs”,“jobs”,“pid”,“jobs”,“title”来自“jobs”,WHE…
。我在项目的另一个地方有点符号,它用于auth模型(在默认数据库中).我投了+1票。但我也投了反对票。对不起,我真的很高兴你能提供帮助。@e4c5不要假设。我投了反对票,因为你的答案是错误的,使OP走上了错误的轨道。模型实例上的下列关系使用简单属性访问,只有查询查找使用双下划线语法。@knbk很好,我混淆了查询y和这里的实例,但在您投票时,我只是复制粘贴了OP的代码,原始答案解决了原始问题。使用()有先例好的。这仍然会产生完全相同的错误:
psycopg2.ProgrammingError:relation“jobs”不存在第1行:…bs“.”time_end“,”jobs“,”pid“,”jobs“,”title”从“作业”WHE…
。但是,如果我使用
手动遵循关系,使用('edlserver')
我会得到正确的值。所以我得出结论,真的是django不知道该使用什么数据库。如果我手动操作,速度方面是否存在差异?
import django.db.models.options as options
options.DEFAULT_NAMES = options.DEFAULT_NAMES + ('in_db',)

class MyModel(models.Model):
  class Meta:
    in_db = 'edlserver'
class DatabaseMetaRouter(object):
def db_for_read(self, model, **hints):
    """
    Route to the given in_db database in Meta
    """
    if hasattr(model._meta, 'in_db'):
        return model._meta.in_db
    else:
        return 'default'

def db_for_write(self, model, **hints):
    """
    Route to the given in_db database in Meta
    """
    if hasattr(model._meta, 'in_db'):
        return model._meta.in_db
    else:
        return 'default'

def allow_relation(self, obj1, obj2, **hints):
    """
    Always allow
    """
    return True

def allow_migrate(self, db, app_label, model_name=None, **hints):
    """
    Always allow
    """
    return True