class Translations(models.Model): " " text = models.TextField(null=True, blank=True) lng = models.SlugField(max_length=32, choices=settings.LANGUAGES, db_index=True) des = models.ForeignKey("Designations", db_index=True, related_name='translations') class Meta: verbose_name = _("translation") verbose_name_plural = _("translations") ordering = ['lng'] # db_table='mlang_translations' class Designations(models.Model): " () id" class Meta: verbose_name = _("designation") verbose_name_plural = _("designations") # db_table='mlang_designations' class Page(MPTTModel): content = models.ForeignKey('mlang.Designations', null=True, blank=True, related_name="+") keywords = models.ForeignKey('mlang.Designations', null=True, blank=True, related_name="+") description = models.ForeignKey('mlang.Designations', null=True, blank=True, related_name="+") title = models.ForeignKey('mlang.Designations', null=True, blank=True, related_name="+") code = models.CharField(max_length=256, db_index=True) parent = TreeForeignKey('self', null=True, blank=True) # db_table='flatpages_page'
1 + , *
. Page.objects.raw(""" select fpage.id id, content_translated.text content_translated, title_translated.text title_translated, keywords_translated.text keywords_translated, description_translated.text description_translated from flatpages_page fpage left join mlang_translations content_translated on fpage.content_id=content_translated.des_id and content_translated.lng=%s left join mlang_translations description_translated on fpage.description_id=description_translated.des_id and description_translated.lng=%s left join mlang_translations keywords_translated on fpage.keywords_id=keywords_translated.des_id and keywords_translated.lng=%s left join mlang_translations title_translated on fpage.title_id=title_translated.des_id and title_translated.lng=%s """, params=["ru", "ru", "ru", "ru"])
django orm left join
order to get an equivalent SQL query, but the python / django way. qs = Page.objects.filter(id__isnull=False) # , . for field in Page._meta.local_fields: if field.rel is not None and field.rel.to is Designations: join = qs.query.join( (Page._meta.db_table, Translations._meta.db_table, ((field.name+'_id', 'des_id'),)), nullable=True, # LEFT JOIN join_field=Translations._meta.get_field_by_name('des')[0] ) qs = qs.extra( select={ field.name+"_translated": join+'.text' }, where=[join+".lng=%s"], params=['ru'] )
'join_cols' is a tuple of tuples containing columns to join on ((l_id1, r_id1), (l_id2, r_id2))
SELECT ... FROM flatpages_pages, mlang_translations t1, mlang_translations_t2, ..... where t1.lng='ru' AND t2.lng='ru' AND ......
def translate(model, lng, exclude=None): if exclude is not None and not isinstance(exclude, (list, tuple, set, frozenset,)): raise TypeError('exclude must be iterable') fields = [] for field in model._meta.fields: if field.rel is not None and field.rel.to is Designations: if exclude is not None and field.name in exclude: continue fields.append( [field.name, map(lambda x: x[1], field.rel.get_joining_columns())[0]] ) if not fields: return {} return dict( tables=[ '"{trans._meta.db_table}" AS "trans_{pos}"'.format(trans=Translations, pos=pos) for pos, val in enumerate(fields) ], select={ column[0] + "_translated": "trans_{0}.text".format(pos) for pos, column in enumerate(fields) }, where=[ "{model._meta.db_table}.{column[1]}=trans_{pos}.des_id and trans_{pos}.lng=%s".format(pos=pos, column=column, model=model) for pos, column in enumerate(fields) ], params=[lng] * len(fields) )
Page.objects.extra(**translate(Page, lng))
JoinInfo = namedtuple('JoinInfo', 'table_name rhs_alias join_type lhs_alias ' 'join_cols nullable join_field')
LEFT OUTER JOIN table alias ON main_table.field=alias.field
qs = Page.objects.filter(id__isnull=False) # for field in Page._meta.local_fields: if field.rel is not None and field.rel.to is Designations: alias = qs.query.join( (Page._meta.db_table, Translations._meta.db_table, ((field.name+"_id", 'des_id',),)), nullable=True, join_field=Translations._meta.get_field_by_name("des")[0] ) qs = qs.extra( select={field.name+"_translated": alias+'.text'}, where=["{0}.lng='{1}' or {0}.lng is null".format(alias, 'ru')], # or lng is null )
Source: https://habr.com/ru/post/230507/
All Articles