使用unique_together并保存经过身份验证的用户时出现问题

问题描述 投票:1回答:2

我的代码中有两个字段条目唯一性检查存在问题。

我使用unique_together定义了一个模型来检查每个用户的字段记录的唯一性,但它接受该用户添加的重复条目。

model.朋友

from django.db import models
from django.contrib.auth.models import User

class UserItem(models.Model):
    definer = models.ForeignKey(User, on_delete=models.CASCADE)
    item_name = models.CharField(max_length=50)
    .
    .
    class Meta:
        unique_together = ("definer", "item_name")

views.朋友

from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.views.generic.edit import CreateView, UpdateView, DeleteView

class RecordCreateView(LoginRequiredMixin, CreateView):
    model = UserItem
    template_name = 'item_new.html'
    #excluding "definer" field and inserting its value by form_valid
    fields = ['item_name', . . .]   

    def form_valid(self, form):
        form.instance.definer = self.request.user
        return super().form_valid(form)

我希望警告并阻止用户添加之前添加的相同“item_name”的新记录,但它接受它们(没有警告)。

当我用其他字段替换“definer”时,它工作正常,并警告重复记录。此外,当管理员添加记录时,它会起作用并且会出现预期的警告。

我想,这个问题是因为经过身份验证的用户在“unique_together =(”definer“,”item_name“)”已完成其角色之后被“def form_valid”插入为“definer”。另一方面,当“定义者”为空时,完成唯一性检查。

我该怎么做才能解决这个问题?

编辑:添加完整模型

```` Full Model in model.py
class UserItem(models.Model):
    item_type = models.CharField(max_length=12, verbose_name='Item type')
    item_name = models.CharField(max_length=50)
    bound = models.CharField(null=True, blank=True, default=None, max_length=4, verbose_name='Bound')
    price = models.FloatField(default=0)
    maximum_use = models.FloatField(default=0, verbose_name='Maximum use (%)’)
    matterial = models.FloatField(null=True, blank=True, default=None, verbose_name='matterial (%)')
    energy = models.FloatField(null=True, blank=True, default=None, verbose_name='energy (kcal/k)')

    definer = models.ForeignKey(User, on_delete=models.CASCADE)

    def __str__(self):
        return "{}, name: {}, definer: {}".format(self.item_type, self.item_name, self.definer,)

    def get_absolute_url(self):
        return reverse('profile')

    class Meta:
        unique_together = ("definer", "item_name")
````


```` views.py after @Pedro suggestion to edit
from django.db import IntegrityError
from django.http import HttpResponse, HttpResponseRedirect
from django.urls import reverse
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.contrib.auth.models import User
from django.contrib.auth.mixins import LoginRequiredMixin

class RecordCreateView(LoginRequiredMixin, CreateView):
    model = UserItem
    template_name = 'item_new.html'
    fields = ['item_name', 'matterial', 'energy',]

    def get_success_url(self):
        return reverse('profile')

    def form_valid(self, form):
        user_item = form.save(commit=False)
        user_item.definer = self.request.user
        user_item.item_type = 'required'
        user_item.bound = 'min'
        try:
            user_item.save()
        except IntegrityError:
            form.add_error('item_name', 'Item name is repeated')
            return self.form_invalid(form)
        return HttpResponseRedirect(self.get_success_url())
````
python django django-models django-orm unique-constraint
2个回答
0
投票

问题是您在验证表单后添加definer。您可以将request.user作为初始数据传递,如下所示:

class RecordCreateView(LoginRequiredMixin, CreateView):
    model = UserItem
    template_name = 'item_new.html'
    #excluding "definer" field and inserting its value by form_valid
    fields = ['item_name', 'definer', ...]

    def get_initial(self):
        initial = super().get_initial()
        initial['definer'] = self.request.user
        return initial

现在你不需要覆盖form_valid

编辑:如果你不想在表单字段中使用definer,你可以这样做:

class RecordCreateView(LoginRequiredMixin, CreateView):
    model = UserItem
    template_name = 'item_new.html'
    fields = ['item_name', ...]

    def form_valid(self, form):
        user_item = form.save(commit=False)
        user_item.definer = self.request.user
        try:
            user_item.save()  # should raise an exception if unique_together constrain fails
        except ValidationError:
            form.add_error('item_name', 'Item name is repeated')  # add custom error to form
            return self.form_invalid(form)  # return the invalid form
        return HttpResponseRedirect(self.get_success_url())

1
投票

感谢@ Pedro非常有用的提示;最后,我可以通过代码中的一些更改来解决我的问题。

我还在model.py中删除了这个部分:“class meta:unique_together =(”definer“,”item_name“)”

````views.py
class RecordCreateView(LoginRequiredMixin, CreateView):
    model = UserItem
    template_name = 'item_new.html'
    fields = ['item_name', 'matterial', 'energy',]

    def form_valid(self, form):
        user_items = form.save(commit=False)
        item_name = user_items.item_name
        qs = UserItemComposition.objects.filter(definer=self.request.user, item_name=item_name)
        if qs.exists():
            form.add_error('item_name', 'Item name is repeated')
            return self.form_invalid(form)
        form.instance.definer = self.request.user
        return super().form_valid(form)
````
© www.soinside.com 2019 - 2024. All rights reserved.