Tuesday, July 17, 2018

Re: trying to learn custom validators

Oh, this is perfect! Works exactly the way I need it. Thank you so much for your help!

On Monday, July 16, 2018 at 5:12:40 PM UTC-4, Matthew Pava wrote:

What I would do in that situation is add a custom field to the model form that holds the item number.  Then, in the save method, convert that to the Item object.

 

class AddItem(forms.ModelForm):

 

    item_number = IntegerField()

 

    class Meta:

        model = ItemsTestCollection

        fields = ['qty', 'case']

 

    def save(self, *args, **kwargs):

              instance = super().save(commit=False)

        instance.item = Item.objects.get(number=self.cleaned_data.get('item_number'))

        instance.save()

        return instance

 

 

 

From: django...@googlegroups.com [mailto:django...@googlegroups.com] On Behalf Of clavie...@gmail.com
Sent: Monday, July 16, 2018 3:02 PM
To: Django users
Subject: trying to learn custom validators

 

I have a legacy database that we want to replace, and Django is still new to us. There are some 40,000 items in the old db, and each item has an item_number that is not necessarily the primary key; that way, the users can maintain their own sku number system and we can maintain data integrity without either of us getting in the other's way. And it also helps guarantee data integrity as we migrate the data from the old db to our new db, since Django will assign PK's and manage FKs as it goes, and leave the item_numbers intact. 

 

I'm running into trouble though, because Django Views and Forms all assume that, when performing a lookup, the input is going to be a primary key. For example, I have an item where item.item_number = '515874'. So when I put that item_number in, Django looks for an item where item.pk = 515874 and raises a ValidationError--because there is no such item. The actual PK for item '515874' is 41293. So I need to take the user's input, use it to get the right item based on its item_number, and give it back to Django to use instead. 

 

CreateView and {{ form.as_table }} default to populating a dropdown, which would mean that the whole item_num/pk problem would go away... but with Django querying *all* 40,000 items, the page literally took 20 seconds to load. So the users are going to need to type in item_numbers which I'll have to convert to PKs. 

 

Overriding form_valid() and clean() weren't working, because the no-such-item ValidationError had already been raised before either method could be called. Defining a custom field and overriding that field's validate method seems to be the right way to go, but I'm still running into issues. The validate method is being called and is returning the correct value, but Django seems to be throwing it away. When I step through it with the debugger, I see the item where (item.id = 41293 and item.item_number = '515874') is correctly being returned. But when Django calls clean() next, that item is nowhere to be found and it's busy cleaning '515874', which was the original input. And then it breaks.

 

This particular view/ModelForm is a simple tool for non-programmers to be able to evaluate a small part of a background process.

 

class ItemsTestCollection(models.Model):
   
"""An item to be tested in Box Opt."""
   
item = models.ForeignKey('item.Item', on_delete=models.CASCADE)
    qty
= models.IntegerField()
    case
= models.ForeignKey('EvaluateTestCase', on_delete=models.CASCADE)
    box
= models.ForeignKey('BoxResults', on_delete=models.CASCADE, null=True)

 

class ItemNumField(forms.CharField):

    
def validate(self, value):
       
# item = Item.objects.get(item_number=value)
        # value = item.id
        # return value
       
return Item.objects.get(item_number=value)

class AddItem(forms.ModelForm):

   
item = ItemNumField()

   
class Meta:
       
model = ItemsTestCollection
        fields
= ['item', 'qty', 'case']

 

class AddItemsToEvaluateCreateView(CreateView):
   
model = ItemsTestCollection
    form_class
= AddItem
    template_name
= 'utils\evaluate.html'

   
def get_queryset(self):
       
return ItemsTestCollection.objects.filter(case_id=self.kwargs['pk'])

   
def get_object(self, queryset=None):
       
return EvaluateTestCase.objects.get(pk=self.kwargs['pk'])

   
def get_success_url(self):
       
if 'add_more' in self.request.POST:
           
return reverse('utils:evaluate', kwargs={'pk': self.kwargs['pk']})
       
elif 'optimize' in self.request.POST:
           
return reverse('utils:results', kwargs={'pk': self.kwargs['pk']})
       
else:
           
return '/'

   
def get_context_data(self, **kwargs):
       
context = super().get_context_data()
        context[
'case_id'] = self.kwargs['pk']
        context[
'items_in_order'] = ItemsTestCollection.objects.filter(case_id=self.kwargs['pk'])
       
return context

 

ValueError at /utils/box-optimization/add-items/118

Cannot assign "'515874'": "ItemsTestCollection.item" must be a "Item" instance.

Request Method:

POST

Request URL:

http://localhost:8000/utils/box-optimization/add-items/118

Django Version:

2.0.5

Exception Type:

ValueError

Exception Value:

Cannot assign "'515874'": "ItemsTestCollection.item" must be a "Item" instance.

Exception Location:

C:\miniconda3\envs\django\lib\site-packages\django\db\models\fields\related_descriptors.py in __set__, line 197

Python Executable:

C:\miniconda3\envs\django\python.exe

Python Version:

3.6.5

Python Path:

['C:\\WMS Repository\\Warehouse Management System',
 'C:\\Program Files\\JetBrains\\PyCharm 2017.3.3\\helpers\\pydev',
 'C:\\WMS Repository\\Warehouse Management System',
 'C:\\Program Files\\JetBrains\\PyCharm 2017.3.3\\helpers\\pydev',
 'C:\\Users\\heast\\.PyCharm2018.1\\system\\cythonExtensions',
 'C:\\miniconda3\\envs\\django\\python36.zip',
 'C:\\miniconda3\\envs\\django\\DLLs',
 'C:\\miniconda3\\envs\\django\\lib',
 'C:\\miniconda3\\envs\\django',
 'C:\\Users\\heast\\AppData\\Roaming\\Python\\Python36\\site-packages',
 'C:\\miniconda3\\envs\\django\\lib\\site-packages',
 'C:\\Program Files\\JetBrains\\PyCharm '
 '2017.3.3\\helpers\\pycharm_matplotlib_backend']

Server time:

Mon, 16 Jul 2018 15:46:11 -0400

Environment:

 

 

Request Method: POST

 

Django Version: 2.0.5

Python Version: 3.6.5

Installed Applications:

['item.apps.ItemConfig',

 'inventory.apps.InventoryConfig',

 'fulfillment.apps.FulfillmentConfig',

 'manifest.apps.ManifestConfig',

 'order.apps.OrderConfig',

 'utils.apps.UtilsConfig',

 'django.contrib.admin',

 'django.contrib.auth',

 'django.contrib.contenttypes',

 'django.contrib.sessions',

 'django.contrib.messages',

 'django.contrib.staticfiles']

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']

 

 

 

Traceback:

 

File "C:\miniconda3\envs\django\lib\site-packages\django\core\handlers\exception.py" in inner

  35.             response = get_response(request)

 

File "C:\miniconda3\envs\django\lib\site-packages\django\core\handlers\base.py" in _get_response

  128.                 response = self.process_exception_by_middleware(e, request)

 

File "C:\miniconda3\envs\django\lib\site-packages\django\core\handlers\base.py" in _get_response

  126.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

 

File "C:\miniconda3\envs\django\lib\site-packages\django\views\generic\base.py" in view

  69.             return self.dispatch(request, *args, **kwargs)

 

File "C:\miniconda3\envs\django\lib\site-packages\django\views\generic\base.py" in dispatch

  89.         return handler(request, *args, **kwargs)

 

File "C:\miniconda3\envs\django\lib\site-packages\django\views\generic\edit.py" in post

  172.         return super().post(request, *args, **kwargs)

 

File "C:\miniconda3\envs\django\lib\site-packages\django\views\generic\edit.py" in post

  141.         if form.is_valid():

 

File "C:\miniconda3\envs\django\lib\site-packages\django\forms\forms.py" in is_valid

  179.         return self.is_bound and not self.errors

 

File "C:\miniconda3\envs\django\lib\site-packages\django\forms\forms.py" in errors

  174.             self.full_clean()

 

File "C:\miniconda3\envs\django\lib\site-packages\django\forms\forms.py" in full_clean

  378.         self._post_clean()

 

File "C:\miniconda3\envs\django\lib\site-packages\django\forms\models.py" in _post_clean

  396.             self.instance = construct_instance(self, self.instance, opts.fields, opts.exclude)

 

File "C:\miniconda3\envs\django\lib\site-packages\django\forms\models.py" in construct_instance

  60.             f.save_form_data(instance, cleaned_data[f.name])

 

File "C:\miniconda3\envs\django\lib\site-packages\django\db\models\fields\__init__.py" in save_form_data

  838.         setattr(instance, self.name, data)

 

File "C:\miniconda3\envs\django\lib\site-packages\django\db\models\fields\related_descriptors.py" in __set__

  197.                     self.field.remote_field.model._meta.object_name,

 

Exception Type: ValueError at /utils/box-optimization/add-items/118

Exception Value: Cannot assign "'515874'": "ItemsTestCollection.item" must be a "Item" instance.

 

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users...@googlegroups.com.
To post to this group, send email to djang...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/16a9d28f-a23a-4112-acc5-f7be9bef4d12%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/89eb1869-6b94-4d41-9023-31573a10de97%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

No comments:

Post a Comment