Flo Win Flo Win - 3 months ago 18
MySQL Question

Django forgets .using database on resolving foreign key

I have a model for my legacy database created by manage.py inspectdb, which accesses the database named 'edlserver' in settings, one of many databases used for the project. I cannot change the database layout.

It has the following classes (among other irrelevant ones):

One for Logging entries.

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'


Another one for Jobs (that the job field references)

class Jobs(models.Model):
job_type = models.ForeignKey(JobTypes, models.DO_NOTHING, db_column='id_job_type')
time_start = models.DateTimeField()
time_end = models.DateTimeField(blank=True, null=True)
pid = models.IntegerField(blank=True, null=True)
title = models.CharField(max_length=255)

class Meta:
managed = False
db_table = 'jobs'


And another one for JobTypes.

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

class Meta:
managed = False
db_table = 'job_types'


The view for django-rest-framework looks like this

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')


It uses the Filter:

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


and the Serializer:

class EDLLogsSerializer(serializers.HyperlinkedModelSerializer):
time = serializers.DateTimeField()
job_name = serializers.SerializerMethodField()
message = serializers.SerializerMethodField()

class Meta:
model = Logs
fields = ('job_name','time', 'message')

def get_job_name(self, obj):
return obj['id_job__id_job_type__name']

def get_message(self, obj):
return obj.msg


Problem is I get a
TypeError: 'Logs' object is not subscriptable
in
get_job_name()
in the Serializer, coming from the psycopg2 module - the database is a MySQL database, however. The fact that the first query has a queryset with len > 0 during debugging shows that the model is okay, and django uses the MySQL backend for getting the data. On resolving the foreign key something goes wrong and the (i think) default database gets used, which is PostGreSQL.

Is this a bug?

If not, what can I do? I was thinking about a router, which would resolve a Meta field. That would mean a lot of change to other models so I'd like to not do this. Any ideas?

EDIT: settings for databases

'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': '',
}

Answer

Foreign keys add an attribute to the model that is itself a model instance. To follow the complete relation from Logs to JobType, simply use attribute lookups:

def get_job_name(self, obj):
    return obj.job.job_type.name
Comments