Hi, I have a MarketCrop model and a Contract model, defined in the same module, where a MarketCrop has many Contracts. I’m able to create new Contracts for a MarketCrop in the shell like this:
from main.models.market_crop import MarketCrop, Contract
mc = MarketCrop.objects.get(pk=53)
c = Contract(market_crop_id=53, is_basis=True, contract_date=datetime.now(), bushels=1000, price=3.75)
c.save()
where the parent key is specified by ‘market_crop_id’.
I’m trying to implement a form that will allow Contracts to be added for an existing MarketCrop without the user having to redundantly specify the MarketCrop. For now, I’d like to do this using a hidden field ‘market_crop_id’ on the form (I’ll deal with security concerns later). But I’m stuck getting a FieldError when I try to run the local server. There’s probably a dumb mistake somewhere, but I’m not seeing it. I appreciate any help with this!
The url pattern is:
path('contract/create/<int:market_crop>/<int:is_basis>',
login_required(ContractCreateView.as_view()), name='contract_create'),
and a typical url path looks like this: /contract/create/53/1/
The view is like this:
class ContractCreateView(CreateView):
model = Contract
form_class = ContractCreateForm
template_name = 'main/contract_form.html'
def dispatch(self, request, *args, **kwargs):
""" get the info from the request path into extra_context """
self.extra_context = {'market_crop': kwargs['market_crop'],
'is_basis': kwargs['is_basis']}
return super().get(request, *args, **kwargs)
def get_initial(self):
""" convert extra_context data into initial data for the form """
print(f'in get_initial: {self.extra_context=}')
return {'market_crop_id': self.extra_context['market_crop'],
'is_basis': 'on' if self.extra_context['is_basis'] == 1 else ''}
def get_success_url(self):
mc_id = self.kwargs.get('market_crop', None)
return reverse('marketcrop_update', args=[mc_id])
The (crispy) form looks like this:
class ContractCreateForm(ModelForm):
def __init__(self, *args, **kwargs):
print(f'in form: {kwargs=}')
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.add_input(Submit('submit', 'Create'))
self.helper.form_id = 'contractform'
self.helper.layout = Layout(
Fieldset('Contract Information',
'contract_date', 'bushels', 'price', 'terminal',
'contract_number', 'delivery_start_date',
'delivery_end_date',
Field('is_basis', type='hidden'),
Field('market_crop_id', type='hidden'),
)
)
class Meta:
model = Contract
fields = '''contract_date bushels price terminal
contract_number delivery_start_date
delivery_end_date is_basis market_crop_id'''.split()
The essential parts of the models are like this:
class MarketCrop(models.Model):
"""
A crop which can be marketed and which has a unique set of futures prices
for a given county.
"""
assumed_basis_for_new = models.FloatField(
default=0, validators=[MinVal(-2), MaxVal(2)],
help_text="Assumed basis for non-contracted bushels.")
farm_year = models.ForeignKey(FarmYear, on_delete=models.CASCADE,
related_name='market_crops')
market_crop_type = models.ForeignKey(MarketCropType, on_delete=models.CASCADE)
fsa_crop = models.ForeignKey(FsaCrop, on_delete=models.CASCADE,
related_name='market_crops')
class Contract(models.Model):
"""
Represents a futures or basis contract
"""
is_basis = models.BooleanField(
default=False,
help_text='Specifies a basis contract instead of a futures contract.')
contract_date = models.DateField(
default=datetime.today)
bushels = models.IntegerField(default=0)
price = models.FloatField(
default=0, verbose_name="price per bushel")
terminal = models.CharField(max_length=60, blank=True)
contract_number = models.CharField(max_length=25, blank=True)
delivery_start_date = models.DateField(
null=True, blank=True)
delivery_end_date = models.DateField(
null=True, blank=True)
market_crop = models.ForeignKey(
MarketCrop, on_delete=models.CASCADE, related_name='contracts')
But the model form code is raising a FieldError, complaining that ‘maket_crop_id’ is an unknown field. I don’t understand this.
$ mpy check
Traceback (most recent call last):
File “/home/dow/python/ifbtdir/manage.py”, line 22, in
main()
File “/home/dow/python/ifbtdir/manage.py”, line 18, in main
execute_from_command_line(sys.argv)
File “/home/dow/python/ifbtdir/env/lib/python3.10/site-packages/django/core/management/init.py”, line 442, in execute_from_command_line
utility.execute()
File “/home/dow/python/ifbtdir/env/lib/python3.10/site-packages/django/core/management/init.py”, line 436, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File “/home/dow/python/ifbtdir/env/lib/python3.10/site-packages/django/core/management/base.py”, line 412, in run_from_argv
self.execute(*args, **cmd_options)
File “/home/dow/python/ifbtdir/env/lib/python3.10/site-packages/django/core/management/base.py”, line 458, in execute
output = self.handle(*args, **options)
File “/home/dow/python/ifbtdir/env/lib/python3.10/site-packages/django/core/management/commands/check.py”, line 76, in handle
self.check(
File “/home/dow/python/ifbtdir/env/lib/python3.10/site-packages/django/core/management/base.py”, line 485, in check
all_issues = checks.run_checks(
File “/home/dow/python/ifbtdir/env/lib/python3.10/site-packages/django/core/checks/registry.py”, line 88, in run_checks
new_errors = check(app_configs=app_configs, databases=databases)
File “/home/dow/python/ifbtdir/env/lib/python3.10/site-packages/django/core/checks/urls.py”, line 14, in check_url_config
return check_resolver(resolver)
File “/home/dow/python/ifbtdir/env/lib/python3.10/site-packages/django/core/checks/urls.py”, line 24, in check_resolver
return check_method()
File “/home/dow/python/ifbtdir/env/lib/python3.10/site-packages/django/urls/resolvers.py”, line 494, in check
for pattern in self.url_patterns:
File “/home/dow/python/ifbtdir/env/lib/python3.10/site-packages/django/utils/functional.py”, line 57, in get
res = instance.dict[self.name] = self.func(instance)
File “/home/dow/python/ifbtdir/env/lib/python3.10/site-packages/django/urls/resolvers.py”, line 715, in url_patterns
patterns = getattr(self.urlconf_module, “urlpatterns”, self.urlconf_module)
File “/home/dow/python/ifbtdir/env/lib/python3.10/site-packages/django/utils/functional.py”, line 57, in get
res = instance.dict[self.name] = self.func(instance)
File “/home/dow/python/ifbtdir/env/lib/python3.10/site-packages/django/urls/resolvers.py”, line 708, in urlconf_module
return import_module(self.urlconf_name)
File “/usr/lib/python3.10/importlib/init.py”, line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File “”, line 1050, in _gcd_import
File “”, line 1027, in _find_and_load
File “”, line 1006, in _find_and_load_unlocked
File “”, line 688, in _load_unlocked
File “”, line 883, in exec_module
File “”, line 241, in _call_with_frames_removed
File “/home/dow/python/ifbtdir/ifbt/urls.py”, line 21, in
path(‘’, include(‘main.urls’)),
File “/home/dow/python/ifbtdir/env/lib/python3.10/site-packages/django/urls/conf.py”, line 38, in include
urlconf_module = import_module(urlconf_module)
File “/usr/lib/python3.10/importlib/init.py”, line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File “”, line 1050, in _gcd_import
File “”, line 1027, in _find_and_load
File “”, line 1006, in _find_and_load_unlocked
File “”, line 688, in _load_unlocked
File “”, line 883, in exec_module
File “”, line 241, in _call_with_frames_removed
File “/home/dow/python/ifbtdir/main/urls.py”, line 4, in
from .views import (
File “/home/dow/python/ifbtdir/main/views.py”, line 24, in
from .forms import (FarmYearCreateForm, FarmYearUpdateForm, FarmCropUpdateForm,
File “/home/dow/python/ifbtdir/main/forms.py”, line 171, in
class ContractCreateForm(ModelForm):
File “/home/dow/python/ifbtdir/env/lib/python3.10/site-packages/django/forms/models.py”, line 320, in new
raise FieldError(message)
django.core.exceptions.FieldError: Unknown field(s) (market_crop_id) specified for Contract
If I change the name of the hidden field from ‘market_crop_id’ to ‘market_crop’, for example, I can see that the values in the url path are populated in the form hidden fields, but of course, then the form won’t validate.
I really appreciate any suggestions on this!