Reputation: 21
I'm fairly new to Django, and coding in general so this could be a conceptual oversight, but I'm running out of ideas so any help is appreciated.
I'm trying to add logic to my form's clean() method which has nested try blocks. I'm trying to get object instances from different ForeignKey related models in each try block. The first two levels seem to work fine, but the third level throws the error below. I've printed the value and type for wine_get.wine_id and I get back 6 and 'int' respectively, so I'm not sure why this isn't considered a number.
Environment:
Request Method: POST
Request URL: http://127.0.0.1:8000/post/new/
Django Version: 2.1
Python Version: 3.6.5
Installed Applications:
['django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'debug_toolbar',
'bootstrap4',
'accounts',
'groups',
'posts']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'debug_toolbar.middleware.DebugToolbarMiddleware']
Traceback:
File "/anaconda3/lib/python3.6/site-packages/django/core/handlers/exception.py" in inner
34. response = get_response(request)
File "/anaconda3/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
126. response = self.process_exception_by_middleware(e, request)
File "/anaconda3/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
124. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/anaconda3/lib/python3.6/site-packages/django/views/generic/base.py" in view
68. return self.dispatch(request, *args, **kwargs)
File "/anaconda3/lib/python3.6/site-packages/django/contrib/auth/mixins.py" in dispatch
52. return super().dispatch(request, *args, **kwargs)
File "/anaconda3/lib/python3.6/site-packages/django/views/generic/base.py" in dispatch
88. return handler(request, *args, **kwargs)
File "/anaconda3/lib/python3.6/site-packages/django/views/generic/edit.py" in post
141. if form.is_valid():
File "/anaconda3/lib/python3.6/site-packages/django/forms/forms.py" in is_valid
185. return self.is_bound and not self.errors
File "/anaconda3/lib/python3.6/site-packages/django/forms/forms.py" in errors
180. self.full_clean()
File "/anaconda3/lib/python3.6/site-packages/django/forms/forms.py" in full_clean
382. self._clean_form()
File "/anaconda3/lib/python3.6/site-packages/django/forms/forms.py" in _clean_form
409. cleaned_data = self.clean()
File "/Users/evan/code/wine/wineProject/wineProject/posts/forms.py" in clean
78. wine = wine_get,
File "/anaconda3/lib/python3.6/site-packages/django/db/models/manager.py" in manager_method
82. return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/anaconda3/lib/python3.6/site-packages/django/db/models/query.py" in get
390. clone = self.filter(*args, **kwargs)
File "/anaconda3/lib/python3.6/site-packages/django/db/models/query.py" in filter
841. return self._filter_or_exclude(False, *args, **kwargs)
File "/anaconda3/lib/python3.6/site-packages/django/db/models/query.py" in _filter_or_exclude
859. clone.query.add_q(Q(*args, **kwargs))
File "/anaconda3/lib/python3.6/site-packages/django/db/models/sql/query.py" in add_q
1263. clause, _ = self._add_q(q_object, self.used_aliases)
File "/anaconda3/lib/python3.6/site-packages/django/db/models/sql/query.py" in _add_q
1287. split_subq=split_subq,
File "/anaconda3/lib/python3.6/site-packages/django/db/models/sql/query.py" in build_filter
1225. condition = self.build_lookup(lookups, col, value)
File "/anaconda3/lib/python3.6/site-packages/django/db/models/sql/query.py" in build_lookup
1096. lookup = lookup_class(lhs, rhs)
File "/anaconda3/lib/python3.6/site-packages/django/db/models/lookups.py" in __init__
20. self.rhs = self.get_prep_lookup()
File "/anaconda3/lib/python3.6/site-packages/django/db/models/fields/related_lookups.py" in get_prep_lookup
115. self.rhs = target_field.get_prep_value(self.rhs)
File "/anaconda3/lib/python3.6/site-packages/django/db/models/fields/__init__.py" in get_prep_value
965. return int(value)
Exception Type: TypeError at /post/new/
Exception Value: int() argument must be a string, a bytes-like object or a number, not 'ModelBase'
Local vars from error:
Variable Value
__class__ <class 'posts.forms.WineForm'>
post_type 'opened'
quantity 2
self <WineForm bound=True, valid=True, fields=(winemaker;wine;vintage;post_type;quantity;rating;location;tasting_notes)>
vintage '1950'
wine 'Cellar 2'
wine_get <Wine: Cellar 2>
winemaker 'Cellar 2'
winemaker_get <WineMaker: Cellar 2>
Session data:
Variable Value
'_auth_user_backend' 'django.contrib.auth.backends.ModelBackend'
'_auth_user_hash' '2c72b4192e2d568f616919e66da6b281d3764e4f'
'_auth_user_id' '2'
models.py
class WineMaker(models.Model):
winemaker_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=255, unique=True)
region = models.ForeignKey(
WineRegion,
db_column = 'region_id',
related_name = 'winemaker_region',
on_delete = models.CASCADE,
null = True
)
def __str__(self):
return self.name
class Meta:
db_table = 'winemakers'
class Wine(models.Model):
wine_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=510)
winemaker = models.ForeignKey(
WineMaker,
db_column = 'winemaker_id',
related_name = 'wine_winemakers',
on_delete = models.CASCADE
)
vintage = models.CharField(
max_length = 10,
choices = VINTAGES,
default = 'none'
)
description = models.TextField(max_length=3000, null=True)
style = models.ForeignKey(
Style,
db_column = 'style_id',
related_name = 'wine_styles',
on_delete = models.CASCADE,
null = True
)
varietal = models.ForeignKey(
Varietal,
db_column = 'varietal_id',
related_name = 'wine_varietals',
on_delete = models.CASCADE,
null = True
)
blend = models.ForeignKey(
Blend,
db_column = 'blend_id',
related_name = 'wine_blends',
on_delete = models.CASCADE,
null = True
)
def __str__(self):
return self.name
class Meta:
db_table = 'wines'
unique_together = ('winemaker', 'name', 'vintage')
class UserCellar(models.Model):
id = models.AutoField(primary_key=True)
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
related_name = 'userCellar_users',
on_delete = models.CASCADE
)
wine = models.ForeignKey(
Wine,
db_column = 'wine_id',
related_name = 'userCellar_wines',
on_delete = models.CASCADE
)
quantity = models.SmallIntegerField(default=0)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __int__(self):
return self.wine_id
def __str__(self):
return self.wine.name
class Meta:
db_table = 'user_cellars'
unique_together = ('user', 'wine')
...
forms.py
from django import forms
from .models import *
from django.contrib.auth import get_user_model
from .choices import VINTAGES, POST_TYPE_CHOICES
user = get_user_model()
class WineForm(forms.Form):
winemaker = forms.CharField(max_length=255)
wine = forms.CharField(max_length=510)
vintage = forms.ChoiceField(
choices = VINTAGES
)
post_type = forms.ChoiceField(
choices = POST_TYPE_CHOICES
)
quantity = forms.IntegerField(
required = False
)
rating = forms.IntegerField(
required = False
)
location = forms.CharField(
max_length = 255,
required = False
)
tasting_notes = forms.CharField(
max_length = 2000,
required = False,
widget = forms.Textarea
)
class Meta:
labels = {
'winemaker' : 'Winemaker',
'wine' : 'Wine',
'vintage' : 'Vintage',
'post_type' : 'Activity Type',
'rating' : 'Rating',
'location' : 'Location',
'tasting_notes' : 'Tasting Notes',
}
def __init__(self, *args, **kwargs):
super(WineForm, self).__init__(*args, **kwargs)
self.fields['quantity'].widget.attrs={
'id': 'quantity'
}
def clean(self):
super().clean()
winemaker = self.cleaned_data.get('winemaker')
wine = self.cleaned_data.get('wine')
vintage = self.cleaned_data.get('vintage')
post_type = self.cleaned_data.get('post_type')
quantity = self.cleaned_data.get('quantity')
if post_type and quantity:
# If both fields are valid
if post_type == 'opened':
try:
# Try to get the WineMaker instance
winemaker_get = WineMaker.objects.get(
name = winemaker,
)
try:
#Try to get the Wine instance
wine_get = Wine.objects.get(
name = wine,
winemaker = winemaker_get,
vintage = vintage,
)
try:
#Try to get the UserCellar instance
cellar_get = UserCellar.objects.get(
user = user,
wine = wine_get,
)
...
Upvotes: 1
Views: 826
Reputation: 5730
I'm afraid my original answer below is rubbish. When filtering on a foreign key, Django doesn't care if you pass an object or just a primary key:
# wm is a WineMaker object; the next 2 lines are both valid
wines1 = Wine.objects.filter(winemaker=wm)
wines2 = Wine.objects.filter(winemaker=wm.id)
===================
The stack trace is clear that the issue is with this line (though the error message is arguably less than helpful):
wine_id = wine_get.wine_id
Since wine_id
is a foreign key, you need to pass a Wine
instance:
wine_id = wine_get
Upvotes: 1