【问题标题】:Django: Adding an instance of object to all ForeignKey related modelsDjango:将对象实例添加到所有 ForeignKey 相关模型
【发布时间】:2018-07-30 16:42:58
【问题描述】:

我有模型Chamber

class Chamber(models.Model):
    chamber_name    = models.CharField(max_length=100)

及相关模型ChamberProperty

class ChamberProperty(models.Model):
    chamber         = models.ForeignKey(Chamber, on_delete=models.CASCADE)
    property_name   = models.CharField(max_length=50)
    property_value  = models.CharField(max_length=100, default=None)

现在一个Chamber可以有很多ChamberProperty。刚刚更改了要求,以便如果将 ChamberProperty 添加到 Chamber,它也会添加到所有未来的 Chamber 实例中, property_value (default=None) 为空,以便下次加载创建新 Chamber 实例的表单时,所有之前的 ChamberProperty.property_name 加载到表单中,并且为空。

示例表格:

第一次创建 Chamber 实例:

Chamber.chamber_name: Foo
ChamberProperty.property_name: Bar
ChamberProperty.property_value: Baz

第二次创建 Chamber 实例:

Chamber.chamber_name: Qux
ChamberProperty.property_name: Bar # Old property, retain the name
ChamberProperty.property_value: None # Old property, value empty
ChamberProperty.property_name: Quux # New property, added by a button
ChamberProperty.property_value: 700 # New property, value filled with input box

第三次创建 Chamber 实例:

Chamber.chamber_name: Corge
ChamberProperty.property_name: Bar # Old property, retain the name
ChamberProperty.property_value: None # Old property, value empty
ChamberProperty.property_name: Quux # Old property, retain the name
ChamberProperty.property_value: None # Old property, value empty
ChamberProperty.property_name: Ouier # New property, added by a button
ChamberProperty.property_value: Grault # New property, value filled with input box

如此等等。

澄清一下:如果您使用“ChamberProperty温度”创建腔室 A,那么下次您创建 腔室时,腔室 B 将已经具有“ChamberProperty 温度”。然后,您可以将新的 ChamberProperty 添加到 Chamber B,例如“Degrees”,具有任何值。然后,如果您创建一个新的 Chamber,即 Chamber C,它将已经具有“ChamberProperty Temperature AND Degrees”。

现在我意识到我必须将 ChamberProperty 实例递归地添加到所有其他 Chamber 实例。

使用 jQuery 脚本在表单中添加新的属性和值,我已经有了,例如:

<div class="card loading-card" id="card-loaded">
    <h3 class="card-header bg-primary text-white">
        Add Chamber
    </h3>
    <div class="card-body">
        <form class="form-horizontal" action="" method="post" enctype="multipart/form-data">
            {% csrf_token %}
            {{ properties_formset.management_form }}
        <!-----------Chamber------------>
            <table>
                <tr>
                    <td style="vertical-align:top">
                        <table>
                            <tr>
                                {% for field in chamber_form %}
                                    <td>{{ field|as_crispy_field }}</td>
                                {% endfor %}
                            </tr>
                        </table>
                    </td>
                    <br />
                    <!-----------Chamber Properties------------>
                    <td><p>&nbsp &nbsp &nbsp</p></td>
                    <td>
                        <table class="new-chamber-properties" id="propertiestable">
                        <script type="text/html" id="property-template">
                            <div id="property-__prefix__">
                                <table>
                                    <tr>
                                        {% for field in properties_formset.empty_form %}
                                            <td>{{ field|as_crispy_field }}</td>
                                        {% endfor %}
                                    </tr>
                                </table>
                            </div>
                        </script>

                        <div id="property-form">
                            <tr>
                                {% for properties_form in properties_formset %}
                                    <div id="property-{{ forloop.counter0 }}"></div>
                                {% endfor %}
                            </tr>
                        </div>
                        <tr>
                            <td>
                                <a href="#" id="add-property-button" class="btn btn-outline-primary add-item">Add Properties</a>
                            </td>
                            <td>
                                <a href="#" id="remove-property-button" class="btn btn-outline-danger remove-item">Remove Properties</a>
                            </td>
                            <td><button class="btn btn-primary" type="submit">Submit</button></td>
                        </tr>
                        </table>
                    </td>
                </tr>
            </table>
        </form>
    </div>
</div>

还有 jQuery:

<script>
    $(document).ready(function () {
        $('.add-item').click(function (ev) {
            ev.preventDefault();
            var count = $('#property-form').children().length;
            console.log(count)
            var tmplMarkup = $('#property-template').html();
            var compiledTmpl = tmplMarkup.replace(/__prefix__/g, count);
            $('div#property-form').append(compiledTmpl);

            // update form count
            $('#id_form-TOTAL_FORMS').attr('value', count + 1);

            // some animate to scroll to view our new form
            $('html, body').animate({ scrollTop: $("#add-property-button").position().top - 200 }, 800);
        });

        for (var i = 0; i < 4; i++) {
            var tmplMarkup = $('#property-template').html();
            var compiledTmpl = tmplMarkup.replace(/__prefix__/g, i);
            $('div#property-form').append(compiledTmpl);
            // update form count
            $('#id_form-TOTAL_FORMS').attr('value', i + 1);
        }
        document.getElementById("id_form-0-property_name").value = "Process";
        document.getElementById("id_form-1-property_name").value = "Type";
        document.getElementById("id_form-2-property_name").value = "Model";
        document.getElementById("id_form-3-property_name").value = "Electrode Diameter";
        document.getElementById("card-loaded").style.visibility = "visible";

        $('.remove-item').click(function (ev) {
            ev.preventDefault();
            var count = $('#property-form').children().length;
            console.log(count);
            if (count > 0) {
                var successCount = count - 1;
                console.log(successCount);
                var formlist = $('#property-form')[0];
                while (count > successCount) {
                    var childNode = formlist.lastChild;
                    formlist.removeChild(childNode);
                    count = $('#property-form').children().length;
                }
                // update form count
                $('#id_form-TOTAL_FORMS').attr('value', count);

                // some animate to scroll to view our new form
                $('html, body').animate({ scrollTop: $("#remove-property-button").position().top - 200 }, 800);
            }
        });
    });
</script>

我什至不知道该怎么做。

我在想可能是这样的,当表单加载时,检索该客户的所有 ChamberProperty 实例,但是如果我将这些值设置为空,它会更改所有其他的值Chamber 实例也是如此。

有什么帮助吗?

【问题讨论】:

  • "...如果一个 ChamberProperty 被添加到一个 Chamber,它也会被添加到所有未来的 Chamber 实例中”。您是指新的 ChamberProperty 实例,还是具有新名称但尚未出现的实例?
  • 这将是 ChamberProperty 的一个新实例,与正在创建的 Chamber 相关,但与之前的所有 ChamberProperty.property_name b> 预填充和空值。
  • 您还可以查看在不迁移数据库的情况下对可以添加/删除键的属性使用 JSONField。

标签: jquery django django-models django-forms


【解决方案1】:

问题是您当前的模型不能反映您的要求。什么构成属性?显然它只是名称,而不是它的价值。该值应保存在单独的模型中,而不是与名称和腔室相关联:

class ChamberProperty(models.Model):
    name = models.CharField(max_length=50)

class ChamberPropertyValue(models.Model):
    chamber = models.ForeignKey(Chamber, on_delete=models.CASCADE)
    property = models.ForeignKey(ChamberProperty, on_delete=models.CASCADE)
    value = models.CharField(max_length=100, default=None)

创建新房间后,您将立即为数据库中存在的每个ChamberProperty 添加一个ChamberPropertyValue。这样,旧房间将保持其状态有任何新的名称/属性与之关联。在创建新的chamber 后,此代码 sn-p 应该进入您的表单验证:

for prop in ChamberProperty.objects.all():
    ChamberPropertyValue.objects.get_or_create(property=prop, chamber=chamber)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-08-06
    • 1970-01-01
    • 2021-10-29
    • 2019-02-25
    • 2011-01-15
    • 1970-01-01
    • 1970-01-01
    • 2020-01-19
    相关资源
    最近更新 更多