更新时间:2023-12-02 15:10:04
我设法实现了类似的功能,如下所示:
I have managed to implement similar functionality a bit like this:
from django.forms.models import BaseInlineFormSet
from django.forms.models import inlineformset_factory
class RawQueryAdapter(object):
"""
Implement some extra methods to make a RawQuery
compatible with FormSet, which is expecting a QuerySet
"""
ordered = True
def __init__(self, qs):
self.qs = qs
self.db = qs.db
def filter(self, *args, **kwargs):
return self
def __len__(self):
return len(list(self.qs))
def __getitem__(self, key):
return self.qs[key]
class BaseRatingFormSet(BaseInlineFormSet):
def __init__(self, *args, **kwargs):
sql = """
SELECT r.id, %s as product_id, m.id as metric_id
FROM myapp_metric m
LEFT JOIN myapp_rating r ON m.id = r.metric_id
AND r.product_id = %s
"""
id = kwargs['instance'].id or 'NULL'
qs = RawQueryAdapter(Rating.objects.raw(sql % (id, id)))
super(BaseRatingFormSet, self).__init__(queryset=qs, *args, **kwargs)
def _construct_form(self, i, **kwargs):
pk_key = "%s-%s" % (self.add_prefix(i), self.model._meta.pk.name)
if self.data.get(pk_key) == '':
# Skip parent (BaseModelFormSet) implementation as it won't work
# with our injected raw data
if i < self.initial_form_count() and not kwargs.get('instance'):
kwargs['instance'] = self.get_queryset()[i]
return super(BaseModelFormSet, self)._construct_form(i, **kwargs)
return super(BaseRatingFormSet, self)._construct_form(i, **kwargs)
RatingFormSet = inlineformset_factory(
Product, Rating,
can_delete=False,
max_num=0,
formset=BaseRatingFormSet,
)
条件必须在左联接中完成,而不是在WHERE中完成,否则您将缺少行.
The condition must be done in the LEFT JOIN, not the WHERE, otherwise you will have missing lines.