правильный способ проверки django unique_together [duplicate]

flavour является закрытым. Хотя вы читаете его из общедоступного метода, вы назначаете его частному полю и, скорее всего, не объявляете его в этом классе.

Вы можете настроить вкус protected в родительском классе или определить для него сеттер

. В конечном итоге ваш код на самом деле не имеет смысла. Даже если бы он скомпилировался, это было бы более или менее: flavour = flavour. Возможно, вам стоит пересмотреть то, что вы пытаетесь сделать немного

. Мне кажется, вам может понадобиться более пристальное понимание Java и объектно-ориентированного программирования.

http: // docs.oracle.com/javase/tutorial/java/concepts/

Вы должны начать здесь.

49
задан sttwister 26 January 2010 в 18:01
поделиться

7 ответов

Мне удалось исправить это, не изменяя представление, добавив в мою форму чистый метод:

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.

14
ответ дан sttwister 25 August 2018 в 22:56
поделиться
  • 1
    Не используйте опцию bare except. Это будет проходить, даже если исключение связано с тем, что сервер базы данных попадает в метеор. Вместо этого используйте «except Solution.DoesNotExist:». – GDorn 15 October 2013 в 22:38

решение от @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

В качестве бонуса вы не возвращаете объект в случае дублирования, а только проверяете, существует ли он в базе данных, экономя немного бит исполнений.

6
ответ дан boblefrag 25 August 2018 в 22:56
поделиться

Как говорит Феликс, ModelForms должны проверять ограничение unique_together в их проверке.

Однако в вашем случае вы фактически исключаете один элемент этого ограничения из вашей формы. Я предполагаю, что это ваша проблема - как форма будет проверять ограничение, если половина его даже не на форме?

21
ответ дан Daniel Roseman 25 August 2018 в 22:56
поделиться
  • 1
    В самом деле, это была проблема. Поэтому я предполагаю, что я не могу получить ошибку в форме, не включая также поле проблем, и что мне придется вручную проверить этот случай. – sttwister 27 January 2010 в 16:16

Вам нужно будет сделать что-то вроде этого:

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
0
ответ дан douglaz 25 August 2018 в 22:56
поделиться
  • 1
    Форма по-прежнему не проверяет ограничение unique_together, возможно, потому, что проблема упоминается в свойстве exclude, хотя у нее есть действительный экземпляр – sttwister 28 January 2010 в 17:06

Я решил эту же проблему, переопределив метод 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) в инициализаторе.

34
ответ дан Jarmo Jaakkola 25 August 2018 в 22:56
поделиться
  • 1
    Обратите внимание, что это только подтверждает любые формы для этой модели, а unique_together используется в базовой базе данных. Это означает, что все, что использует объекты модели напрямую, не связано этой проверкой. – Herge 9 August 2012 в 17:16
  • 2
    Хорошо ли использовать Защищенные методы ..! – Satyajeet 31 March 2017 в 07:07

Если вы хотите, чтобы сообщение об ошибке было связано с полем 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
0
ответ дан Risadinha 25 August 2018 в 22:56
поделиться

С помощью ответа Ярмо следующее выглядит хорошо для меня (в 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 для меня ... но мне пришлось бы оглянуться на ранее сообщенные проблемы.


Изменить : Я говорил слишком рано. Возможно, то, что я написал выше, будет работать в некоторых ситуациях, но не в моем; Я в конечном итоге использовал ответ Джармо.

1
ответ дан Sam Hartsfield 25 August 2018 в 22:56
поделиться
Другие вопросы по тегам:

Похожие вопросы: