Чистый метод модели Django и проверка внешнего ключа в FormView - PullRequest
0 голосов
/ 01 декабря 2019

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

class Category(BaseModel):
    title = models.CharField(_('Category title'), max_length=256)
    available = models.BooleanField(_('Is available'), default=True)
    slug = models.SlugField(max_length=256, null=True, blank=True, unique=True, verbose_name=_(Slug'))

    requires_item_price = models.BooleanField(default=False, verbose_name=_('Requires item price to be provided'))


class Offer(BaseModel):
    category = models.ForeignKey(Category, on_delete=models.CASCADE, null=True, blank=True, verbose_name=_('Category'))

    item_price = models.DecimalField(max_digits=8, decimal_places=2, null=True, verbose_name=_('Item price'),
                                     blank=True)

    def clean(self):
        if self.category.requires_item_price and not self.item_price:
            raise ValidationError({'item_price': _('If category requires item price - you have to provide it')})

Мой класс формы:

class NewPaginatedOfferForm(forms.ModelForm):
    class Meta:
        model = Offer
        fields = ('item_price',)

    def __init__(self, category, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.category = category
        self.helper = FormHelper()
        self.helper.form_id = self.__class__.__name__.lower()
        self.initial['category'] = category

        self.helper.layout = Layout(
            Field('item_price'),
            Div(
                Submit('submit', _(Save →'),
                       css_class="btn btn-lg bold btn-block btn-success", ),
            )
        )

и мой класс представления на основе универсального класса CreateView:

class NewOfferForCategoryView(CreateView):
    model = Offer
    category = None
    template_name = 'web/new_offer_for_category.html'

    def get_form_class(self):
        print('get_form_class')
        if self.category.requires_item_price:
            return NewPaginatedOfferForm

    def get_form_kwargs(self):
        print('get_form_kwargs')
        kwargs = super().get_form_kwargs()
        kwargs['category'] = self.category
        print('kwargs:', kwargs)
        return kwargs

    def dispatch(self, request, *args, **kwargs):
        print('dispatch, ', request.method)
        try:
            self.category = Category.objects.get(slug=self.kwargs.get('cat_slug'), available=True)
        except:
            print('wrong category')
            return redirect(reverse('web:new_offer'))
        print('self category is', self.category)
        return super().dispatch(request, *args, **kwargs)

    def form_valid(self, form):
        print('form_valid')
        form.instance.category = self.category
        return super().form_valid(form)

    def form_invalid(self, form):
        print('form_invalid')
        form.instance.category = self.category
        return super().form_invalid(form)

    def get_context_data(self, **kwargs):
        print('get_context_data')
        ctx = super().get_context_data(**kwargs)
        ctx['categories'] = Category.objects.filter(available=True)
        ctx['category'] = self.category
        return ctx

GET-запросы работают нормально. Проблема в том, когда я пытаюсь отправить такую ​​форму. Я всегда получаю сообщение об ошибке:

AttributeError at /new-offer/my-category-slug
'NoneType' object has no attribute 'requires_item_price'

Request Method: POST
Request URL:    http://127.0.0.1:8000/new-offer/my-category-slug
Django Version: 2.2.6
Exception Type: AttributeError
Exception Value:    
'NoneType' object has no attribute 'requires_item_price'
Exception Location: /Users/User/project/core/models.py in clean, line 272

Похоже, свойство категории имеет значение Нет в методе очистки модели предложения, но я не уверен, почему и как я могу передать его там. Я хочу использовать метод очистки модели, поскольку он также охватывает проверку админ-панели django при создании нового объекта. Есть идеи?

1 Ответ

1 голос
/ 01 декабря 2019

Ваша модель допускает пустое значение category (null=True), поэтому ваш метод clean() должен не предполагать, что есть категория. Добавить if self.category and self.category.requires_item_price....

По вашему мнению, вы назначаете категорию после проверки формы (т. Е. После вызова метода clean () модели). Вместо этого следует назначить его в инициализаторе вашей формы (поскольку вы уже передаете его в __init__()), выполнив self.instance.category = category.

Вы можете удалить self.initial['category'] = category в своей форме, который ничего не делаетпоскольку форма не имеет поля category. Также вы можете удалить self.category = category, вы его нигде не используете. И вы можете удалить form.instance.category = category в вашем представлении.

Также в вашем методе dispatch() есть универсальное предложение except. Никогда не делайте этого, только поймайте исключения, которые вы хотите поймать, а не просто исключение. В вашем случае замените except: на except Category.DoesNotExist:.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...