Django – 基于函数的视图更新记录 – 错误 – 记录已存在

huangapple go评论58阅读模式
英文:

Django - Function Based View update record - error - Record Already exists

问题

MODELS.PY:

class Currency(models.Model):
    currency_code = models.CharField(max_length=3)
    currency_name = models.CharField(max_length=80)

    class Meta:
        verbose_name_plural = "货币"

    def __str__(self):
        return self.currency_code


class Forex(models.Model):
    currency_code = models.ForeignKey(Currency, on_delete=models.CASCADE)
    forex_rate = models.DecimalField(max_digits=8, decimal_places=4)
    last_updated_on = models.DateTimeField(auto_now=True)

    class Meta:
        verbose_name_plural = "外汇汇率"

    def __str__(self):
        return self.currency_code.currency_code

FORMS.PY:

class UpperCase(forms.CharField):
    def to_python(self, value):
        if value:
            return value.upper()


class CurrencyForm(forms.ModelForm):
    currency_code = UpperCase(
        label="货币代码",
        min_length=3,
        max_length=3,
        error_messages={"required": "货币代码不能为空"},
        required=True,
    )
    currency_name = UpperCase(
        label="货币名称",
        min_length=5,
        max_length=80,
        error_messages={"required": "货币名称不能为空"},
        required=True,
    )

    class Meta:
        model = Currency
        fields = ["currency_code", "currency_name"]

    # 检查重复的第二种方法正常工作
    def clean_currency_code(self):
        currency_code = self.cleaned_data.get("currency_code")
        if Currency.objects.filter(currency_code=currency_code).exists():
            raise forms.ValidationError(
                "货币代码 {} 已经存在!".format(currency_code)
            )
        return currency_code

VIEWS.PY:

def currency_edit(request, id):
    obj = Currency.objects.get(id=id)
    if request.method == 'POST':
        form = CurrencyForm(data=request.POST, instance=obj)
        if form.is_valid():
            form.save()
            return redirect('currency_list_page')
    else:
        form = CurrencyForm(instance=obj)
    return render(request, 'main/currency_edit.html', locals())

URLS.PY:

urlpatterns = [
    path('currency_list/', views.currency_list, name='currency_list_page'),
    path('currency_add/', views.currency_add, name='currency_add_page'),
    path('currency_edit/<int:id>/', views.currency_edit, name='currency_edit_page'),
    path('currency_delete/<int:id>/', views.currency_delete, name='currency_delete_page'),
]

CURRENCY_EDIT.HTML:

<form action="{% url 'currency_edit_page' id %}" class="row g-3 mt-3" method="POST" novalidate>
    {% csrf_token %}
    <div class="row">
        {{id}}
        {{form.currency_code}}
        {{form.currency_name}}
    </div>
    <div class="col-12">
        <button class="btn btn-success" type="submit"><i class="fa-solid fa-floppy-disk"></i> 保存</button>
        <a class="btn btn-danger" href="{% url 'currency_list_page' %}">
            <i class="fa-solid fa-reply"></i> 取消</a>
    </div>
</form>
英文:

I am trying to update an existing record using Django 4.2, Crispy Forms, and Function Based View. The field currency_code in the table Currency is used as a ForeignKey in another table(s). I cannot update the currency record without getting the message that the record already exists. What am I doing wrong and where? Below is the code and screenshot:

Django – 基于函数的视图更新记录 – 错误 – 记录已存在

Django – 基于函数的视图更新记录 – 错误 – 记录已存在

MODELS.PY:

class Currency(models.Model):
    currency_code = models.CharField(max_length=3)
    currency_name = models.CharField(max_length=80)

    class Meta:
        verbose_name_plural = &quot;Currencies&quot;

    def __str__(self):
        return self.currency_code


class Forex(models.Model):
    currency_code = models.ForeignKey(Currency, on_delete=models.CASCADE)
    forex_rate = models.DecimalField(max_digits=8, decimal_places=4)
    last_updated_on = models.DateTimeField(auto_now=True)

    class Meta:
        verbose_name_plural = &quot;Forex Rates&quot;

    def __str__(self):
        return self.currency_code.currency_code

FORMS.PY:

class UpperCase(forms.CharField):
    def to_python(self, value):
        if value:
            return value.upper()


class CurrencyForm(forms.ModelForm):
    currency_code = UpperCase(
        label=&quot;Currency Code&quot;,
        min_length=3,
        max_length=3,
        error_messages={&quot;required&quot;: &quot;Currency Code Cannot Be Blank&quot;},
        required=True,
    )
    currency_name = UpperCase(
        label=&quot;Currency Name&quot;,
        min_length=5,
        max_length=80,
        error_messages={&quot;required&quot;: &quot;Currency Name Cannot Be Blank&quot;},
        required=True,
    )

    class Meta:
        model = Currency
        fields = [&quot;currency_code&quot;, &quot;currency_name&quot;]

    # Method 2 for checking duplicates working ok
    def clean_currency_code(self):
        currency_code = self.cleaned_data.get(&quot;currency_code&quot;)
        if Currency.objects.filter(currency_code=currency_code).exists():
            raise forms.ValidationError(
                &quot;Currency Code {} already exists!&quot;.format(currency_code)
            )
        return currency_code

VIEWS.PY:

def currency_edit(request, id):
    obj = Currency.objects.get(id=id)
    if request.method == &#39;POST&#39;:
        form = CurrencyForm(data=request.POST, instance=obj)
        if form.is_valid():
            form.save()
            return redirect(&#39;currency_list_page&#39;)
    else:
        form = CurrencyForm(instance=obj)
    return render(request, &#39;main/currency_edit.html&#39;, locals())

URLS.PY:

urlpatterns = [
    path(&#39;currency_list/&#39;, views.currency_list, name=&#39;currency_list_page&#39;),
    path(&#39;currency_add/&#39;, views.currency_add, name=&#39;currency_add_page&#39;),
    path(&#39;currency_edit/&lt;int:id&gt;&#39;, views.currency_edit, name=&#39;currency_edit_page&#39;),
    path(&#39;currency_delete/&lt;int:id&gt;&#39;, views.currency_delete, name=&#39;currency_delete_page&#39;),
]

CURRENCY_EDIT.HTML

&lt;form action=&quot;{% url &#39;currency_edit_page&#39; id %}&quot; class=&quot;row g-3 mt-3&quot; method=&quot;POST&quot; novalidate&gt;
    {% csrf_token %}
    &lt;div class=&quot;row&quot;&gt;
        {{id}}
        {{form.currency_code}}
        {{form.currency_name}}
    &lt;/div&gt;
    &lt;div class=&quot;col-12&quot;&gt;
        &lt;button class=&quot;btn btn-success&quot; type=&quot;submit&quot;&gt;&lt;i
                class=&quot;fa-solid fa-floppy-disk&quot;&gt;&lt;/i&gt; Save
        &lt;/button&gt;
        &lt;a class=&quot;btn btn-danger&quot; href=&quot;{% url &#39;currency_list_page&#39; %}&quot;&gt;
            &lt;i class=&quot;fa-solid fa-reply&quot;&gt;&lt;/i&gt; Cancel&lt;/a&gt;
    &lt;/div&gt;
&lt;/form&gt;

答案1

得分: 1

抱歉,看起来我错过了你的表单clean_currency_code上的缩进(下次提问时要小心),这就是问题所在。

当您尝试编辑时,表单将引发您设置的验证。因为该函数将在.is_valid调用上运行,您还在编辑view上调用它,当然,如果您试图编辑第二个字段currency_name,那么code将不会更改,因此仍然存在。

如果currency_code字段应该是唯一的,请在您的模型上使用唯一字段选项,让框架为您工作:

models.py

class Currency(models.Model):
    currency_code = models.CharField(max_length=3, unique=True)
    currency_name = models.CharField(max_length=80)

forms.py

class UpperCase(forms.CharField):
    ...


class CurrencyForm(forms.ModelForm):
    class Meta:
        model = Currency
        fields = ["currency_code", "currency_name"]

    currency_code = UpperCase(
        label="Currency Code",
        min_length=3,
        max_length=3,
        error_messages={"required": "Currency Code Cannot Be Blank"},
        required=True,
    )
    currency_name = UpperCase(
        label="Currency Name",
        min_length=5,
        max_length=80,
        error_messages={"required": "Currency Name Cannot Be Blank"},
        required=True,
    )
英文:

Sorry, it seems that I missed indentation on your form clean_currency_code (careful with that next time asking a question), there is where the problem lies.

When you try to edit, form will raise the validation you set up. Because the function will run on .is_valid calls, which you also call on edit view and of course if you are trying to edit the second field currency_name then the code will not change and thus exists.

If currency_code field is supposed to be unique, then use the unique field option on your model and let the framework work for you:

models.py

class Currency(models.Model):
    currency_code = models.CharField(max_length=3, unique=True)
    currency_name = models.CharField(max_length=80)

forms.py

class UpperCase(forms.CharField):
    ...


class CurrencyForm(forms.ModelForm):
    class Meta:
        model = Currency
        fields = [&quot;currency_code&quot;, &quot;currency_name&quot;]

    currency_code = UpperCase(
        label=&quot;Currency Code&quot;,
        min_length=3,
        max_length=3,
        error_messages={&quot;required&quot;: &quot;Currency Code Cannot Be Blank&quot;},
        required=True,
    )
    currency_name = UpperCase(
        label=&quot;Currency Name&quot;,
        min_length=5,
        max_length=80,
        error_messages={&quot;required&quot;: &quot;Currency Name Cannot Be Blank&quot;},
        required=True,
    )

huangapple
  • 本文由 发表于 2023年5月26日 11:44:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/76337532.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定