Skip to content

Commit

Permalink
Merge pull request #764 from awesto/drafts/refactor-perform-model-checks
Browse files Browse the repository at this point in the history
Drafts/refactor perform model checks
  • Loading branch information
jrief committed May 17, 2019
2 parents 11d4555 + 3e396b2 commit 5257e98
Show file tree
Hide file tree
Showing 8 changed files with 41 additions and 42 deletions.
1 change: 0 additions & 1 deletion shop/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,5 @@ def ready(self):

# perform some sanity checks
ForeignKeyBuilder.check_for_pending_mappings()
ForeignKeyBuilder.perform_model_checks()

cms_tags.register.tags['page_attribute'] = PageAttribute
11 changes: 0 additions & 11 deletions shop/deferred.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,24 +194,13 @@ def perform_meta_model_check(cls, Model):
implementation of the just created type.
"""

@classmethod
def perform_model_check(cls):
"""
Hook for each materialized class inheriting from ForeignKeyBuilder, to perform model checks.
"""

@classmethod
def check_for_pending_mappings(cls):
if cls._pending_mappings:
msg = "Deferred foreign key '{0}.{1}' has not been mapped"
pm = cls._pending_mappings
raise ImproperlyConfigured(msg.format(pm[0][0].__name__, pm[0][1]))

@classmethod
def perform_model_checks(cls):
for model in cls._materialized_models.values():
model.perform_model_check()


class PolymorphicForeignKeyBuilder(ForeignKeyBuilder, PolymorphicModelBase):
"""
Expand Down
18 changes: 10 additions & 8 deletions shop/models/cart.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@
from six import with_metaclass
import warnings
from collections import OrderedDict

from django.core import checks
from django.db import models
from django.core.exceptions import ImproperlyConfigured
from django.utils.translation import ugettext_lazy as _

from shop import deferred
Expand Down Expand Up @@ -101,17 +100,20 @@ class Meta:
verbose_name_plural = _("Cart items")

@classmethod
def perform_model_check(cls):
allowed_types = ['IntegerField', 'DecimalField', 'FloatField']
def check(cls, **kwargs):
errors = super(BaseCartItem, cls).check(**kwargs)
allowed_types = ['IntegerField', 'SmallIntegerField', 'PositiveIntegerField',
'PositiveSmallIntegerField', 'DecimalField', 'FloatField']
for field in cls._meta.fields:
if field.attname == 'quantity':
if not field.get_internal_type() in allowed_types:
msg = "Field `{}.quantity` must be of one of the types: {}."
raise ImproperlyConfigured(msg.format(cls.__name__, allowed_types))
if field.get_internal_type() not in allowed_types:
msg = "Class `{}.quantity` must be of one of the types: {}."
errors.append(checks.Error(msg.format(cls.__name__, allowed_types)))
break
else:
msg = "Class `{}` must implement a field named `quantity`."
raise ImproperlyConfigured(msg.format(cls.__name__))
errors.append(checks.Error(msg.format(cls.__name__)))
return errors

def __init__(self, *args, **kwargs):
# reduce the given fields to what the model actually can consume
Expand Down
5 changes: 2 additions & 3 deletions shop/models/defaults/cart_item.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.core.validators import MinValueValidator
from django.db.models import IntegerField
from django.db.models import PositiveIntegerField
from shop.models import cart


class CartItem(cart.BaseCartItem):
"""Default materialized model for CartItem"""
quantity = IntegerField(validators=[MinValueValidator(0)])
quantity = PositiveIntegerField()
4 changes: 2 additions & 2 deletions shop/models/defaults/order_item.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models
from django.db.models import PositiveIntegerField
from django.utils.translation import ugettext_lazy as _, pgettext_lazy
from shop.models import order


class OrderItem(order.BaseOrderItem):
"""Default materialized model for OrderItem"""
quantity = models.IntegerField(_("Ordered quantity"))
quantity = PositiveIntegerField(_("Ordered quantity"))

class Meta:
verbose_name = pgettext_lazy('order_models', "Ordered Item")
Expand Down
18 changes: 11 additions & 7 deletions shop/models/delivery.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
from __future__ import unicode_literals

from six import with_metaclass
from django.core import checks
from django.db import models
from django.core.exceptions import ImproperlyConfigured
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _
from shop import deferred
Expand Down Expand Up @@ -55,13 +55,15 @@ def __str__(self):
return _("Delivery ID: {}").format(self.id)

@classmethod
def perform_model_check(cls):
def check(cls, **kwargs):
errors = super(BaseDelivery, cls).check(**kwargs)
for field in OrderItemModel._meta.fields:
if field.attname == 'canceled' and field.get_internal_type() == 'BooleanField':
break
else:
msg = "Class `{}` must implement a `BooleanField` named `canceled`, if used in combination with a Delivery model."
raise ImproperlyConfigured(msg.format(OrderItemModel.__name__))
errors.append(checks.Error(msg.format(OrderItemModel.__name__)))
return errors

def clean(self):
if self.order._fsm_requested_transition == ('status', 'ship_goods') and not self.shipped_at:
Expand Down Expand Up @@ -106,21 +108,23 @@ class Meta:
verbose_name_plural = _("Deliver items")

@classmethod
def perform_model_check(cls):
def check(cls, **kwargs):
errors = super(BaseDeliveryItem, cls).check(**kwargs)
for order_field in OrderItemModel._meta.fields:
if order_field.attname == 'quantity':
break
else:
msg = "Class `{}` must implement a field named `quantity`."
raise ImproperlyConfigured(msg.format(OrderItemModel.__name__))
errors.append(checks.Error(msg.format(OrderItemModel.__name__)))
for deliver_field in OrderItemModel._meta.fields:
if deliver_field.attname == 'quantity':
break
else:
msg = "Class `{}` must implement a field named `quantity`."
raise ImproperlyConfigured(msg.format(cls.__name__))
errors.append(checks.Error(msg.format(cls.__name__)))
if order_field.get_internal_type() != deliver_field.get_internal_type():
msg = "Field `{}.quantity` must be of one same type `{}.quantity`."
raise ImproperlyConfigured(msg.format(cls.__name__, OrderItemModel.__name__))
errors.append(checks.Error(msg.format(cls.__name__, OrderItemModel.__name__)))
return errors

DeliveryItemModel = deferred.MaterializedModel(BaseDeliveryItem)
19 changes: 11 additions & 8 deletions shop/models/order.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from decimal import Decimal
import logging
from six import with_metaclass
from django.core import checks
from django.core.exceptions import ImproperlyConfigured
from django.db import models, transaction
from django.db.models.aggregates import Sum
Expand Down Expand Up @@ -516,22 +517,24 @@ def __str__(self):
return self.product_name

@classmethod
def perform_model_check(cls):
def check(cls, **kwargs):
errors = super(BaseOrderItem, cls).check(**kwargs)
for cart_field in CartItemModel._meta.fields:
if cart_field.attname == 'quantity':
break
else:
msg = "Class `{}` must implement a field named `quantity`."
raise ImproperlyConfigured(msg.format(CartItemModel.__name__))
for order_field in OrderItemModel._meta.fields:
if order_field.attname == 'quantity':
errors.append(checks.Error(msg.format(CartItemModel.__name__)))
for field in cls._meta.fields:
if field.attname == 'quantity':
if field.get_internal_type() != cart_field.get_internal_type():
msg = "Field `{}.quantity` must be of same type as `{}.quantity`."
errors.append(checks.Error(msg.format(cls.__name__, CartItemModel.__name__)))
break
else:
msg = "Class `{}` must implement a field named `quantity`."
raise ImproperlyConfigured(msg.format(OrderItemModel.__name__))
if order_field.get_internal_type() != cart_field.get_internal_type():
msg = "Field `{}.quantity` must be of one same type `{}.quantity`."
raise ImproperlyConfigured(msg.format(CartItemModel.__name__, OrderItemModel.__name__))
errors.append(checks.Error(msg.format(cls.__name__)))
return errors

@property
def unit_price(self):
Expand Down
7 changes: 5 additions & 2 deletions shop/models/product.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from functools import reduce
import operator
from cms import __version__ as CMS_VERSION
from django.core import checks
from django.db import models
from django.utils import six
from django.utils.encoding import force_text
Expand Down Expand Up @@ -177,12 +178,14 @@ def get_weight(self):
return 0

@classmethod
def perform_model_check(cls):
def check(cls, **kwargs):
errors = super(BaseProduct, cls).check(**kwargs)
try:
cls.product_name
except AttributeError:
msg = "Class `{}` must provide a model field implementing `product_name`"
raise NotImplementedError(msg.format(cls.__name__))
errors.append(checks.Error(msg.format(cls.__name__)))
return errors

ProductModel = deferred.MaterializedModel(BaseProduct)

Expand Down

0 comments on commit 5257e98

Please sign in to comment.