具有不同模型的queryset的InlineFormSet [英] InlineFormSet with queryset of different model

查看:40
本文介绍了具有不同模型的queryset的InlineFormSet的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们想要做的是使用不同模型的某些查询集填充具有初始值的内联表单列表.我们有产品,指标(某些类别,类型或等级)和等级,其中存储了实际的等级并将指标与产品联系起来.

What we're trying to do is populate a list of inline forms with initial values using some queryset of a different model. We have products, metrics (some category or type or rating), and a rating, which stores the actual rating and ties metrics to products.

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个评分"表格,每个表格与一个不同的度量标准相关联.我们不能使用基于评级的查询集来填充页面,因为特定产品/指标组合的评级可能尚不存在.

The end result we're going for is a list of all possible ratings for a Product on the Product admin page. If we have 20 Metrics in our database, when we go to the Product page we want to see 20 forms for Ratings on the page, each one tied to a different Metric. We can't use a queryset based on Ratings to populate the page, because the Rating for a particular Product/Metric combination might not yet exist.

我们一直在研究Django中的所有表单和表单集代码,并希望提出这样简单的解决方案:

We've been looking at all the forms and formset code in Django, and are hoping to come up with a solution as simple as this:

http://www.thenestedfloat.com/articles/limiting-inline-admin-objects-in-django

他只是重写BaseInlineFormSet中的某些内容并将其提供给内联.也许我们可以制作

He just overrides something in BaseInlineFormSet and gives it to the inline. Maybe we can just make something like

class RatingInlineFormset(BaseInlineFormset):

带有一些替代.有什么想法吗?

With some overrides. Any ideas?

推荐答案

我设法实现了类似的功能,如下所示:

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.

这篇关于具有不同模型的queryset的InlineFormSet的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆