使用 unique_together 和保存经过身份验证的用户时出现问题
Problem using unique_together and saving authenticated user
我的两个字段条目唯一性检查代码存在问题。
我用 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" 时,它工作正常并警告重复记录。此外,当管理员添加记录时,它会起作用,并且会有预期的警告。
我想,这个问题是因为 "def form_valid" 在“unique_together = ("definer", "item_name")”已经发挥了作用。另一方面,当 "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())
````
问题是您在验证表单后添加 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())
感谢@Pedro 非常有用的提示;最后我可以通过修改他的代码来解决我的问题。
我还在 model.py 中删除了这部分:
“class 元:
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)
````
我的两个字段条目唯一性检查代码存在问题。
我用 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" 时,它工作正常并警告重复记录。此外,当管理员添加记录时,它会起作用,并且会有预期的警告。
我想,这个问题是因为 "def form_valid" 在“unique_together = ("definer", "item_name")”已经发挥了作用。另一方面,当 "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())
````
问题是您在验证表单后添加 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())
感谢@Pedro 非常有用的提示;最后我可以通过修改他的代码来解决我的问题。
我还在 model.py 中删除了这部分: “class 元: 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)
````