我的代码中存在两个字段条目唯一性检查的问题。
我用unique_together
定义了一个模型来检查每个用户的字段记录的唯一性,但是它接受该用户添加的重复条目。
model.py
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.py
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())
````
答案 0 :(得分:1)
感谢@Pedro的非常有用的提示;最后,我可以通过对他的代码进行一些更改来解决我的问题。
我也删除了model.py中的这一部分: “类元: 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)
````
答案 1 :(得分: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())