title: django orm: select_related, fooling reverse foreign key with a fake foreign key addition to the model, what can go wrong?
body: <p>I am trying to learn how to use Django's ORM  for more advanced queries, instead of using raw sql.</p>
  
  <p><code>select_related</code> makes joins to reduce database hits, in principle it could make the joins that I would do manually. </p>
  
  <p>But there is a problem: It doesn't use reverse foreign key relationships to make the sql. For the schema I have this is a nuisance. I have found what looks like a surprisingly easy work around, and I'm worried that it will be incorrect in ways I don't understand.</p>
  
  <p>I'm using a legacy DB, and it is read-only, and therefore unmanaged by the ORM, and there are no consequences for cascade settings. I have made models for its tables via manage.py analysedb which did a very good job; I have a 6000 line model file, and only needed to spend ten minutes fixing things. </p>
  
  <p>One tweak I did was a hack to fool <code>select_related</code> by creating a foreign key relationship which is actually a reverse FK relationship. This means I have two entries in my model pointing to the same database column, which is the primary key (correct) and also now a foreign key. I exploit the "new" column in <code>select_related</code>.</p>
  
  <p>The main table for my query is Service. It has foreign key relationships to a number of other tables, and that works well with select_related. </p>
  
  <p>The column servrecid_1 is my artificial addition. The other two columns are two of the genuine FKs; there are more.</p>
  
  <pre><code>class Service(models.Model):
      servrecid = models.AutoField(db_column='ServRecID', primary_key=True)
      servrecid_1 = models.ForeignKey('RecServ', models.DO_NOTHING, to_field='servrecid',
                                      db_column='ServRecID')  # Field name made lowercase.
  
      visitrecordid = models.ForeignKey('Visit', models.DO_NOTHING, db_column='VisitRecordID', blank=True,
                                        null=True)  # Field name made lowercase.
      itemno = models.ForeignKey(Fees, models.DO_NOTHING, db_column='ItemNo', to_field='itemno')
      ...
      class Meta:
          managed = False  # same for all the models
  
  
  class RecServ(models.Model):
      allocationid = models.AutoField(db_column='AllocationID', primary_key=True)  # Field name made lowercase.
      servrecid = models.ForeignKey('Service', models.DO_NOTHING, db_column='ServRecID')  # Field name made lowercase.
      receiptno = models.ForeignKey(Receipt, models.DO_NOTHING, db_column='ReceiptNo')  # Field name made lowercase.
  </code></pre>
  
  <p>(There are more relations than I show in the snippets above)</p>
  
  <p>With this, I can now do queries like this:</p>
  
  <pre><code>q = models.Service.objects.select_related('visitrecordid__servdoctor').select_related('visitrecordid__invoiceto') \
          .select_related('visitrecordid__patientno').select_related('itemno').select_related(
      'servrecid_1__receiptno').all()[:5]
  </code></pre>
  
  <p>which creates a query with these joins:</p>
  
  <pre><code>    ... FROM [SERVICE] INNER JOIN [REC_SERV] ON ([SERVICE].[ServRecID] = [REC_SERV].[ServRecID])
   INNER JOIN [RECEIPT] ON ([REC_SERV].[ReceiptNo] = [RECEIPT].[ReceiptNo]) 
  LEFT OUTER JOIN [VISIT] ON ([SERVICE].[VisitRecordID] = [VISIT].[VisitRecordID]) 
  LEFT OUTER JOIN [CM_PATIENT] ON ([VISIT].[PatientNo] = [CM_PATIENT].[PATIENT_ID]) 
  LEFT OUTER JOIN [DOCTOR] ON ([VISIT].[ServDoctor] = [DOCTOR].[DoctorCode]) 
  LEFT OUTER JOIN [INVOICETO] ON ([VISIT].[InvoiceTo] = [INVOICETO].[InvoiceTo]) 
  INNER JOIN [FEES] ON ([SERVICE].[ItemNo] = [FEES].[ItemNo])
  </code></pre>
  
  <p>The first join only appears because of my false FK. The SQL looks fine to me, I think I have solved my problem.</p>
  
  <p>Should this actually work? What will happen now with this mutual foreign key relationship between both tables?</p>