Introduction
Another article for discussing on how to handle an error appear. Actually, the error appear upon submitting a form for adding an object. In this case, the object is ‘staff’ which is using the model ‘Staff’. Actually this article is using another article as a reference. That article is an article of ‘How to Use ModelForm to Create a Form for submitting User Input in Django Application‘. So, the error itself exist as in the following appearance :
ValueError at /save_staff/
Field ‘id’ expected a number but got ”.
Request Method: | POST |
---|---|
Request URL: | http://localhost:8000/save_staff/ |
Django Version: | 4.1.1 |
Exception Type: | ValueError |
Exception Value: |
Field ‘id’ expected a number but got ”. |
Exception Location: | C:\python\model\env\lib\site-packages\django\db\models\fields\__init__.py, line 2020, in get_prep_value |
Raised during: | apps.views.save_staff |
Python Executable: | C:\python\model\env\Scripts\python.exe |
Python Version: | 3.10.5 |
Python Path: | [‘C:\\python\\model\\model’, ‘C:\\python\\python310\\python310.zip’, ‘C:\\python\\python310\\DLLs’, ‘C:\\python\\python310\\lib’, ‘C:\\python\\python310’, ‘C:\\python\\model\\env’, ‘C:\\python\\model\\env\\lib\\site-packages’] |
In order to have an information about the Django project especially the Django application triggering the error message, below is the structure of the Django project :
C:\project>dir Volume in drive C is Windows-SSD Volume Serial Number is CA30-19A4 Directory of C:\project 09/06/2022 07:13 AM <DIR> . 09/06/2022 10:42 AM <DIR> .. 09/06/2022 08:19 PM <DIR> apps 08/24/2022 09:30 AM 159,744 db.sqlite3 08/20/2022 05:17 PM 683 manage.py 08/20/2022 05:18 PM <DIR> project 09/06/2022 07:14 AM 126 requirements.txt 3 File(s) 160,553 bytes 4 Dir(s) 65,556,508,672 bytes free C:\project>
Furthermore, below is the structure of the Django application where it exist in a folder inside the Django project. It is a folder with the name of ‘apps’ :
(env) C:\project\apps>dir Volume in drive C is Windows-SSD Volume Serial Number is CA30-19A4 Directory of C:\project\apps 09/06/2022 08:19 PM <DIR> . 09/06/2022 07:13 AM <DIR> .. 08/24/2022 10:02 AM 215 admin.py 08/24/2022 08:43 AM 146 apps.py 09/17/2022 02:18 PM 454 forms.py 08/26/2022 02:19 PM <DIR> migrations 08/26/2022 02:05 PM 1,548 models.py 09/06/2022 07:01 PM <DIR> templates 08/24/2022 08:43 AM 63 tests.py 09/06/2022 08:03 AM 118 urls.py 09/08/2022 06:43 AM 871 views.py 08/24/2022 08:43 AM 0 __init__.py 09/08/2022 06:43 AM <DIR> __pycache__ 7 File(s) 2,961 bytes 6 Dir(s) 66,276,225,024 bytes free (env) C:\project\apps>
So, what is actually the one triggering the error message ?. Well, actually it is exist in the error message in the detail which is the long format from the above error message. In general, there is an information that the error message was raised in ‘apps.views.save_staff’. But in the long format of the error message, the one triggering it exist as follows :
user = User.objects.get(id=request.POST.get('user'))
Actually,the above line exist in the file with the name of ‘views.py’ which is for defining function to process the request. Below is the function ‘save_staff’ for processing submit form request to save a new object ‘staff’ from the ‘Staff’ model as follows :
def save_staff(request): if request.POST: staff = Staff() staff.name = request.POST.get('name') if(request.POST.get('user')!= ''): user = User.objects.get(id=request.POST.get('user')) print(user.username) staff.user = user if(request.POST.get('unit')!= ''): unit = Unit.objects.get(pk=request.POST.get('unit')) staff.unit = unit print("Staff Name : ",staff.name) staff.save() return redirect("list_staff")
How to Solve Error Message ValueError at /save_staff/ Field ‘id’ expected a number but got ”
In this context, the error message actually hinting that the ‘id’ exist in the line triggering that error message is expecting a number. Instead, it is receiving an empty string. That line triggering the error message exist below :
user = User.objects.get(id=request.POST.get('user'))
So, the part of ‘id=request.POST.get(‘user’)’ did not received any number. It is receiving empty string where it will generate error. Because it will be passed to ‘User.objects.get’ where it cannot get any User object with id with an empty string. Actually, below is the image of the form for adding the staff :
Using the form above for adding a new object of ‘staff’ using ‘Staff’ model, without selecting the user dropdown list, clicking the ‘Submit’ button, unfortunately generated the error message. In this case, there is a clear correlation where the ‘request.POST.get(‘user’)’ for passing the value to the id of ‘Users.objects.get(id=request.POST.get(‘user’)). Since no ‘User’ object selected, the value of ‘request.POST.get(‘user’) will be empty. So, below is the solution for solving the problem occurred :
-
First solution, it is to just select the ‘User’ object in the above dropdown list. Since there is a selected ‘User’ object, it will have an ‘id’ value. In the end, the id value will not be an empty string. On the other hand, it will be a number which is the id of the User object.
-
Second solution, it is to modify the Staff model. It is to make sure that the ‘Staff’ model does not strictly have a User object attached to it. Below is the current format of the ‘Staff’ model exist in the ‘models.py’ file :
class Staff(models.Model): id_unique = models.AutoField(primary_key=True) user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True, default=None) name = models.CharField(max_length=255, default="") unit = models.OneToOneField(Unit, on_delete=models.CASCADE, null=True, blank=True, default=None) def __str__(self): return '%s' %(self.name)
The problem lies to the type of the user definition as an attribute of the Staff model. It is a OneToOneField relationship with the ‘User’ object. In that case, it is a mandatory attribute. It need exactly one User object as the value of the ‘user’ variable. In order to avoid this, just change the type of the attribute ‘user’ as the second solution. It also applied to the ‘unit’ attribute. Below is the revision of the model :
class Staff(models.Model): id_unique = models.AutoField(primary_key=True) user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True, default=None) name = models.CharField(max_length=255, default="") unit = models.ForeignKey(Unit, on_delete=models.CASCADE, null=True, blank=True, default=None) def __str__(self): return '%s' %(self.name)
Just change it as in the above revision so that the attribute will contain foreign key value which is the id of the object. The definition of the above attribute is definitely safe and will not trigger and error if the ‘User’ dropdown in the form is not selected. The reason is that the foreign key type is allowing null, blank and it doesn’t need to have default value.
-
Finally, just execute the Django application once more. If there are no more error message appear, the submit process after the entry of a new input Staff will be a success.