'Django model's clean method and foreign key validation in FormView
In my django app I have simple Category and Offer models:
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')})
My form class:
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", ),)
)
and my view class, based on generic CreateView class:
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 requests are working fine. Problem is when I try to submit such form. I am always getting an error:
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
Looks like category property is None in Offer model clean method - but I am not sure why and how can I pass it there. I want to use model clean method as it covers also django's admin panel validation when new object is created there. Any ideas?
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
