Django의 ModelForm unique_together 유효성 검사
다음과 같은 Django 모델이 있습니다.
class Solution(models.Model):
'''
Represents a solution to a specific problem.
'''
name = models.CharField(max_length=50)
problem = models.ForeignKey(Problem)
description = models.TextField(blank=True)
date = models.DateTimeField(auto_now_add=True)
class Meta:
unique_together = ("name", "problem")
다음과 같은 모델을 추가하기 위해 양식을 사용합니다.
class SolutionForm(forms.ModelForm):
class Meta:
model = Solution
exclude = ['problem']
내 문제는 의 제약 조건을 SolutionForm
확인하지 않으므로 양식을 저장하려고 할 때을 반환한다는 것입니다. 나는 이것을 수동으로 확인 하는 데 사용할 수 있다는 것을 알고 있지만 양식 유효성 검사에서 이것을 포착하고 양식 오류를 자동으로 반환하는 방법이 있는지 궁금합니다.Solution
unique_together
IntegrityError
validate_unique
감사.
validate_unique()
ModelForm 의 메서드를 재정 의하여 동일한 문제를 해결했습니다 .
def validate_unique(self):
exclude = self._get_validation_exclusions()
exclude.remove('problem') # allow checking against the missing attribute
try:
self.instance.validate_unique(exclude=exclude)
except ValidationError, e:
self._update_errors(e.message_dict)
이제는 양식에 제공되지 않은 속성이 여전히 사용 가능한지 확인합니다 (예 : instance=Solution(problem=some_problem)
이니셜 라이저).
Felix가 말했듯이 ModelForms는 unique_together
유효성 검사에서 제약 조건 을 확인 해야합니다.
그러나 귀하의 경우 실제로 해당 제약 조건의 한 요소를 양식에서 제외합니다. 나는 이것이 당신의 문제라고 생각합니다-양식의 절반이 양식에 똑같지 않은 경우 양식이 제약 조건을 어떻게 확인합니까?
내 양식에 깨끗한 메서드를 추가하여보기를 수정하지 않고이 문제를 해결할 수있었습니다.
class SolutionForm(forms.ModelForm):
class Meta:
model = Solution
exclude = ['problem']
def clean(self):
cleaned_data = self.cleaned_data
try:
Solution.objects.get(name=cleaned_data['name'], problem=self.problem)
except Solution.DoesNotExist:
pass
else:
raise ValidationError('Solution with this Name already exists for this problem')
# Always return cleaned_data
return cleaned_data
보기에서 지금해야 할 유일한 일은 실행하기 전에 폼에 문제 속성을 추가하는 것 is_valid
입니다.
@sttwister의 솔루션은 맞지만 단순화 할 수 있습니다.
class SolutionForm(forms.ModelForm):
class Meta:
model = Solution
exclude = ['problem']
def clean(self):
cleaned_data = self.cleaned_data
if Solution.objects.filter(name=cleaned_data['name'],
problem=self.problem).exists():
raise ValidationError(
'Solution with this Name already exists for this problem')
# Always return cleaned_data
return cleaned_data
보너스로 복제의 경우 개체를 검색하지 않고 데이터베이스에 존재하는지 확인하여 약간의 성능을 절약합니다.
Jarmo의 답변의 도움으로 다음은 나에게 잘 작동하는 것 같습니다 (Django 1.3에서).하지만 일부 코너 케이스를 깨 뜨렸을 가능성이 있습니다 (많은 티켓이 있습니다 _get_validation_exclusions
).
class SolutionForm(forms.ModelForm):
class Meta:
model = Solution
exclude = ['problem']
def _get_validation_exclusions(self):
exclude = super(SolutionForm, self)._get_validation_exclusions()
exclude.remove('problem')
return exclude
잘 모르겠지만 이것은 나에게 Django 버그처럼 보이지만 이전에보고 된 문제를 살펴 봐야합니다.
편집 : 너무 빨리 말 했어요. 위에서 쓴 내용이 어떤 상황에서는 작동하지만 내 상황에서는 작동하지 않을 수 있습니다. 나는 Jarmo의 대답을 직접 사용했습니다.
다음과 같이해야합니다.
def your_view(request):
if request.method == 'GET':
form = SolutionForm()
elif request.method == 'POST':
problem = ... # logic to find the problem instance
solution = Solution(problem=problem) # or solution.problem = problem
form = SolutionForm(request.POST, instance=solution)
# the form will validate because the problem has been provided on solution instance
if form.is_valid():
solution = form.save()
# redirect or return other response
# show the form
오류 메시지를 name
필드 와 연결하고 그 옆에 표시하려는 경우 :
def clean(self):
cleaned_data = super().clean()
name_field = 'name'
name = cleaned_data.get(name_field)
if name:
if Solution.objects.filter(name=name, problem=self.problem).exists():
cleaned_data.pop(name_field) # is also done by add_error
self.add_error(name_field, _('There is already a solution with this name.'))
return cleaned_data
내 솔루션은 Django 2.1을 기반으로합니다.
SolutionForm은 그대로두고 Solution에 save () 메서드가 있습니다.
class Solution(models.Model):
...
def save(self, *args, **kwargs):
self.clean()
return super(Solution, self).save(*args, **kwargs)
def clean():
# have your custom model field checks here
# They can raise Validation Error
# Now this is the key to enforcing unique constraint
self.validate_unique()
ValidationError가 처리되지 않으므로 save ()에서 full_clean () 호출이 작동하지 않습니다.
필자의 company
경우 필드 를 제외 하고 뷰의 form_valid
기능 에 추가해야했습니다 . 나는 결국 다음을 수행했습니다 (다른 답변에서 영감을 얻음). 내CreateView
def form_valid(self, form):
cleaned_data = form.cleaned_data
user_company = self.request.user.profile.company
if UnitCategory.objects.filter(code=cleaned_data['code'],
company=user_company).exists():
form.add_error('code', _(
'A UnitCategory with this Code already exists for this company.'))
return super(UnitCategoryCreateView, self).form_invalid(form)
if UnitCategory.objects.filter(color=cleaned_data['color'],
company=user_company).exists():
form.add_error('color', _(
'A UnitCategory with this Color already exists for this company.'))
return super(UnitCategoryCreateView, self).form_invalid(form)
form.instance.company = user_company
return super(UnitCategoryCreateView, self).form_valid(form)
In my UpdateView
I had to exclude the current instance of the object in checking if the query exist using exclude(pk=self.kwargs['pk'])
def form_valid(self, form):
cleaned_data = form.cleaned_data
user_company = self.request.user.profile.company
if UnitCategory.objects.filter(code=cleaned_data['code'],
company=user_company).exclude(pk=self.kwargs['pk']).exists():
form.add_error(
'code', _('A UnitCategory with this Code already exists for this company.'))
return super(UnitCategoryUpdateView, self).form_invalid(form)
if UnitCategory.objects.filter(color=cleaned_data['color'],
company=user_company).exclude(pk=self.kwargs['pk']).exists():
form.add_error('color', _(
'A UnitCategory with this Color already exists for this company.'))
return super(UnitCategoryUpdateView, self).form_invalid(form)
# Return form_valid if no errors raised
# Add logged-in user's company as form's company field
form.instance.company = user_company
return super(UnitCategoryUpdateView, self).form_valid(form)
Not the cleanest solution I was hoping for, but thought it might benefit someone.
ReferenceURL : https://stackoverflow.com/questions/2141030/djangos-modelform-unique-together-validation
'developer tip' 카테고리의 다른 글
Angular2로드시 너무 많은 파일 요청 (0) | 2020.12.25 |
---|---|
'위치 : 절대'가 flexbox와 충돌합니까? (0) | 2020.12.25 |
Django의 계단식 삭제 동작을 재정의하는 옵션은 무엇입니까? (0) | 2020.12.25 |
캐치 블록으로 돌아 오시겠습니까? (0) | 2020.12.25 |
Java에서 RESTful API를 만드는 방법을 배우는 데 가장 좋은 소스는 무엇입니까? (0) | 2020.12.25 |