Python 具有不同模型查询集的InlineFormSet
我们要做的是使用不同模型的一些查询集,用初始值填充一个内联表单列表。我们有产品、指标、某些类别或类型或评级,以及一个评级,用于存储实际评级并将指标与产品联系起来Python 具有不同模型查询集的InlineFormSet,python,django,forms,django-admin,django-forms,Python,Django,Forms,Django Admin,Django Forms,我们要做的是使用不同模型的一些查询集,用初始值填充一个内联表单列表。我们有产品、指标、某些类别或类型或评级,以及一个评级,用于存储实际评级并将指标与产品联系起来 class Product(models.Model): name = models.CharField(max_length=100) price = models.IntegerField(max_length=6) class Metric(models.Model): name = models.Cha
class Product(models.Model):
name = models.CharField(max_length=100)
price = models.IntegerField(max_length=6)
class Metric(models.Model):
name = models.CharField(max_length=80)
description = models.TextField()
class Rating(models.Model)
rating = models.IntegerField(max_length=3)
metric = models.ForeignKey(Metric)
product = models.ForeignKey(Product)
最终的结果是,我们将在产品管理页面上列出产品的所有可能评级。如果我们的数据库中有20个指标,当我们转到产品页面时,我们希望在页面上看到20个评级表格,每个表格都与不同的指标相关联。我们不能使用基于评级的查询集来填充页面,因为特定产品/指标组合的评级可能还不存在
我们一直在研究Django中的所有表单和表单集代码,希望找到一个简单的解决方案:
他只是重写BaseInlineFormSet中的某些内容并将其交给内联。也许我们可以做点像
class RatingInlineFormset(BaseInlineFormset):
有一些覆盖。有什么想法吗?您正在寻找管理员或前端解决方案吗?管理方法如下,您可以对其进行反向工程,以获得类似的前端解决方案:
# admin.py
class RatingInline(admin.StackedInline):
model = Rating
class ProductAdmin(admin.ModelAdmin):
inlines = [
RatingInline
]
class MetricAdmin(admin.ModelAdmin):
pass
class RatingAdmin(admin.ModelAdmin):
pass
admin.site.register(Product, ProductAdmin)
admin.site.register(Metric, MetricAdmin)
admin.site.register(Rating, RatingAdmin)
我已经实现了类似的功能,有点像这样:
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,
)
编辑:条件必须在左连接中完成,而不是在何处,否则将丢失行