def get_object_list(self, request, *args, **kwargs): return RestPeriod.objects.filter( Q(recipe__publish_date__lte=now()) | Q(recipe__publish_date__isnull=True), Q(recipe__expiry_date__gte=now()) | Q(recipe__expiry_date__isnull=True), Q(recipe__status=CONTENT_STATUS_PUBLISHED))
def get_object_list(self, request, *args, **kwargs): return BlogCategory.objects.filter( Q(blogposts__publish_date__lte=now()) | Q(blogposts__publish_date__isnull=True), Q(blogposts__expiry_date__gte=now()) | Q(blogposts__expiry_date__isnull=True), Q(blogposts__status=CONTENT_STATUS_PUBLISHED)).distinct()
def render(self, context): featured = FeaturedProject.objects.filter( featured_start_date__lte=now(), project__publish_date__lte=now(), project__status=CONTENT_STATUS_PUBLISHED) context['featured_projects'] = featured[:self.num] return ''
def render(self, context): featured = FeaturedProject.objects.filter( featured_start_date__lte=now(), project__publish_date__lte=now(), project__status=CONTENT_STATUS_PUBLISHED ) context['featured_projects'] = featured[:self.num] return ''
def save(self, *args, **kwargs): # Set project as draft by default if not self.id: self.status = CONTENT_STATUS_DRAFT # Set created and modified datetimes if not provided. if not self.id: self.created_datetime = now() self.modified_datetime = now() super(Project, self).save(*args, **kwargs)
def published(self, for_user=None): """ For non-staff users, return items with a published status and whose publish and expiry dates fall before and after the current date when specified. """ from mezzanine.core.models import CONTENT_STATUS_PUBLISHED if for_user is not None and for_user.is_staff: return self.all() return self.filter( Q(publish_date__lte=now()) | Q(publish_date__isnull=True), Q(expiry_date__gte=now()) | Q(expiry_date__isnull=True), Q(status=CONTENT_STATUS_PUBLISHED))
def get_active_users(days=7, number=4): """ Return a queryset of the most active users for the given `days` and limited to `number` users. Defaults to 7 days and 4 users. """ yester_date = now() - timedelta(days=days) actions = Action.objects.model_actions(User) \ .filter(timestamp__gte=yester_date) \ .values_list('actor_object_id', flat=True) # Create a counter for user pks with the most associated actions action_counter = Counter(actions).most_common(number) # Sort the most active users on the number of actions action_counter.sort(key=itemgetter(1), reverse=True) # Use the user pk's to query for the user data most_active_user_pks = map( lambda user_action: int(user_action[0]), action_counter ) users = User.objects.filter( pk__in=most_active_user_pks, is_active=True, profile__isnull=False ) # Return a list of users sorted on the number of actions (desc.) pk_user_mapping = dict((user.pk, user) for user in users) return [ pk_user_mapping[pk] for pk in most_active_user_pks if pk in pk_user_mapping ]
def save(self, *args, **kwargs): self.modified_date = now() if not self.content_type: ct = ContentType.objects ct = ct.get_for_model(self.__class__) self.content_type = ct super(BlogProxy, self).save(*args, **kwargs)
def get_active_users(days=7, number=4): """ Return a queryset of the most active users for the given `days` and limited to `number` users. Defaults to 7 days and 4 users. """ yester_date = now() - timedelta(days=days) actions = Action.objects.model_actions(User) \ .filter(timestamp__gte=yester_date) \ .values_list('actor_object_id', flat=True) # Create a counter for user pks with the most associated actions action_counter = Counter(actions).most_common(number) # Sort the most active users on the number of actions action_counter.sort(key=itemgetter(1), reverse=True) # Use the user pk's to query for the user data most_active_user_pks = map(lambda user_action: int(user_action[0]), action_counter) users = User.objects.filter(pk__in=most_active_user_pks, is_active=True, profile__isnull=False) # Return a list of users sorted on the number of actions (desc.) pk_user_mapping = dict((user.pk, user) for user in users) return [ pk_user_mapping[pk] for pk in most_active_user_pks if pk in pk_user_mapping ]
def from_request(self, request): """ Return a cart by ID stored in the session, creating it if not found as well as removing old carts prior to creating a new cart. """ n = now() expiry_minutes = timedelta(minutes=settings.SHOP_CART_EXPIRY_MINUTES) expiry_time = n - expiry_minutes cart_id = request.session.get("cart", None) cart = None if cart_id: try: cart = self.get(last_updated__gte=expiry_time, id=cart_id) except self.model.DoesNotExist: request.session["cart"] = None else: # Update timestamp and clear out old carts. cart.last_updated = n cart.save() self.filter(last_updated__lt=expiry_time).delete() if not cart: from cartridge.shop.utils import EmptyCart cart = EmptyCart(request) return cart
def save(self, **kwargs): """ Create a ``FormEntry`` instance and related ``FieldEntry`` instances for each form field. """ entry = super(FormForForm, self).save(commit=False) entry.form = self.form entry.entry_time = now() entry.save() entry_fields = entry.fields.values_list("field_id", flat=True) new_entry_fields = [] for field in self.form_fields: field_key = "field_%s" % field.id value = self.cleaned_data[field_key] if value and self.fields[field_key].widget.needs_multipart_form: value = fs.save(join("forms", str(uuid4()), value.name), value) if isinstance(value, list): value = ", ".join([v.strip() for v in value]) if field.id in entry_fields: field_entry = entry.fields.get(field_id=field.id) field_entry.value = value field_entry.save() else: new = {"entry": entry, "field_id": field.id, "value": value} new_entry_fields.append(FieldEntry(**new)) if new_entry_fields: if django.VERSION >= (1, 4, 0): FieldEntry.objects.bulk_create(new_entry_fields) else: for field_entry in new_entry_fields: field_entry.save() return entry
def test_is_published_false(self): self.project.publish_date = now() + timedelta(minutes=1) self.project.save() self.assertFalse(self.project.is_published(), 'Should return False if publish_date is in the future' ) self.project.publish_date = now() - timedelta(minutes=1) self.project.status = CONTENT_STATUS_DRAFT self.project.save() self.assertFalse(self.project.is_published(), 'Should return False if status is "Draft"' ) self.project_publish_date = now() + timedelta(minutes=1) self.project.save() self.assertFalse(self.project.is_published(), 'Should return False if status is "Draft" and publish_date is in the future' )
def on_sale(self): """ Returns True if the sale price is applicable. """ n = now() valid_from = self.sale_from is None or self.sale_from < n valid_to = self.sale_to is None or self.sale_to > n return self.sale_price is not None and valid_from and valid_to
def active(self, *args, **kwargs): """ Items flagged as active and in valid date range if date(s) are specified. """ n = now() valid_from = Q(valid_from__isnull=True) | Q(valid_from__lte=n) valid_to = Q(valid_to__isnull=True) | Q(valid_to__gte=n) return self.filter(valid_from, valid_to, active=True)
def published(self, for_user=None): """ For non-staff/permissionless users, return items with a published status and whose publish and expiry dates fall before and after the current date when specified. :param for_user: """ from mezzanine.core.models import CONTENT_STATUS_PUBLISHED from widget.utilities import widget_extra_permission #This allows a callback for extra user validation, eg. check if a user passes a test (has a subscription) if for_user is not None and bool(for_user.is_staff or bool(for_user.has_perm("widget.change_widget") and widget_extra_permission(for_user))): return self.all() return self.filter( Q(publish_date__lte=now()) | Q(publish_date__isnull=True), Q(expiry_date__gte=now()) | Q(expiry_date__isnull=True), Q(status=CONTENT_STATUS_PUBLISHED))
def save(self, *args, **kwargs): """ Set default for ``publish_date``. We can't use ``auto_now_add`` on the field as it will be blank when a blog post is created from the quick blog form in the admin dashboard. """ if self.publish_date is None: self.publish_date = now() super(Displayable, self).save(*args, **kwargs)
def save(self, *args, **kwargs): """ Set default for ``publish_date``. We can't use ``auto_add`` on the field as it will be blank when a blog post is created from the quick blog form in the admin dashboard. """ if self.publish_date is None: self.publish_date = now() super(Displayable, self).save(*args, **kwargs)
def add_item(self, *args, **kwargs): """ Create a real cart object, add the items to it and store the cart ID in the session. """ from cartridge.shop.models import Cart cart = Cart.objects.create(last_updated=now()) cart.add_item(*args, **kwargs) self._request.session["cart"] = cart.id
def active(self, *args, **kwargs): """ Items flagged as active and in valid date range if date(s) are specified. """ n = now() valid_from = Q(valid_from__isnull=True) | Q(valid_from__lte=n) valid_to = Q(valid_to__isnull=True) | Q(valid_to__gte=n) valid = self.filter(valid_from, valid_to, active=True) return valid.exclude(uses_remaining=0)
def test_draft_visible_projectuser(self): # Project status is draft self.project.status = CONTENT_STATUS_DRAFT self.project.save() self.client.login(username=self.user.username, password='******') response = self.client.get(self.url) self.assertEqual(response.status_code, 200) # Project status is published, but publish_date is in the future self.project.status = CONTENT_STATUS_PUBLISHED self.project.publish_date = now() + timedelta(minutes=1) self.project.save() response = self.client.get(self.url) self.assertEqual(response.status_code, 200)
def is_published(self, request=None): """ Returns True/False if the Project is published for the user in the given request. Staff users can see any projects while regular users can see any of their own projects If no request is given, or the user is not staff and viewing another user's project, returns True if publish_date <= now() and status == CONTENT_STATUS_PUBLISHED otherwise False. """ if request is not None: if request.user.is_staff or request.user == self.user: return True return self.publish_date <= now() and self.status == CONTENT_STATUS_PUBLISHED
def clean_card_expiry_year(self): """ Ensure the card expiry doesn't occur in the past. """ try: month = int(self.cleaned_data["card_expiry_month"]) year = int(self.cleaned_data["card_expiry_year"]) except ValueError: # Haven't reached payment step yet. return n = now() if year == n.year and month < n.month: raise forms.ValidationError(_("A valid expiry date is required.")) return str(year)
def test_draft_hidden_other_user(self): other_user = self.create_user(data={'password': '******'}) # Project status is draft self.project.status = CONTENT_STATUS_DRAFT self.project.save() self.client.login(username=other_user.username, password='******') response = self.client.get(self.url) self.assertEqual(response.status_code, 404) # Project status is published, but publish_date is in the future self.project.status = CONTENT_STATUS_PUBLISHED self.project.publish_date = now() + timedelta(minutes=1) self.project.save() response = self.client.get(self.url) self.assertEqual(response.status_code, 404)
def is_published(self, request=None): """ Returns True/False if the Project is published for the user in the given request. Staff users can see any projects while regular users can see any of their own projects If no request is given, or the user is not staff and viewing another user's project, returns True if publish_date <= now() and status == CONTENT_STATUS_PUBLISHED otherwise False. """ if request is not None: if request.user.is_staff or request.user == self.user: return True return (self.publish_date <= now() and self.status == CONTENT_STATUS_PUBLISHED)
class FeaturedProject(models.Model): "A Project annotated for featuring on the Home Page" project = models.OneToOneField("project.Project") byline = models.CharField( max_length=50, help_text='A terse description to be used on the home page.') photo = models.ImageField(upload_to='images/project_featured_photos', help_text='Upload an image for the home page. Suggested ' \ 'dimensions are 1252x626px and max 5MB filesize.') featured_start_date = models.DateTimeField(default=now(), help_text='Date the Project will start being featured on the' \ 'homepage.') class Meta: ordering = ['-featured_start_date']
def filters(self): """ Returns product filters as a Q object for the category. """ # Build a list of Q objects to filter variations by. filters = [] # Build a lookup dict of selected options for variations. options = self.options.as_fields() if options: lookup = dict([("%s__in" % k, v) for k, v in options.items()]) filters.append(Q(**lookup)) # Q objects used against variations to ensure sale date is # valid when filtering by sale, or sale price. n = now() valid_sale_from = Q(sale_from__isnull=True) | Q(sale_from__lte=n) valid_sale_to = Q(sale_to__isnull=True) | Q(sale_to__gte=n) valid_sale_date = valid_sale_from & valid_sale_to # Filter by variations with the selected sale if the sale date # is valid. if self.sale_id: filters.append(Q(sale_id=self.sale_id) & valid_sale_date) # If a price range is specified, use either the unit price or # a sale price if the sale date is valid. if self.price_min or self.price_max: prices = [] if self.price_min: sale = Q(sale_price__gte=self.price_min) & valid_sale_date prices.append(Q(unit_price__gte=self.price_min) | sale) if self.price_max: sale = Q(sale_price__lte=self.price_max) & valid_sale_date prices.append(Q(unit_price__lte=self.price_max) | sale) filters.append(reduce(iand, prices)) # Turn the variation filters into a product filter. operator = iand if self.combined else ior products = Q(id__in=self.products.only("id")) if filters: filters = reduce(operator, filters) variations = ProductVariation.objects.filter(filters) filters = [Q(variations__in=variations)] # If filters exist, checking that products have been # selected is neccessary as combining the variations # with an empty ID list lookup and ``AND`` will always # result in an empty result. if self.products.count() > 0: filters.append(products) return reduce(operator, filters) return products
def from_request(self, request): """ Return a cart by ID stored in the session, creating it if not found as well as removing old carts prior to creating a new cart. """ n = now() expiry_minutes = timedelta(minutes=settings.SHOP_CART_EXPIRY_MINUTES) expiry_time = n - expiry_minutes try: cart_id = request.session.get("cart", None) cart = self.get(last_updated__gte=expiry_time, id=cart_id) except self.model.DoesNotExist: self.filter(last_updated__lt=expiry_time).delete() cart = self.create(last_updated=n) request.session["cart"] = cart.id else: cart.save() # Update timestamp. return cart
def save(self, **kwargs): """ Create a ``FormEntry`` instance and related ``FieldEntry`` instances for each form field. """ entry = super(FormForForm, self).save(commit=False) entry.form = self.form entry.entry_time = now() entry.save() for field in self.form_fields: field_key = "field_%s" % field.id value = self.cleaned_data[field_key] if value and self.fields[field_key].widget.needs_multipart_form: value = fs.save(join("forms", str(uuid4()), value.name), value) if isinstance(value, list): value = ", ".join([v.strip() for v in value]) field_entry, _ = entry.fields.get_or_create(field_id=field.id) field_entry.value = value field_entry.save() return entry
def __init__(self, request, step, data=None, initial=None, errors=None): """ Handle setting shipping field values to the same as billing field values in case JavaScript is disabled, hiding fields for the current step. """ # Copy billing fields to shipping fields if "same" checked. first = step == checkout.CHECKOUT_STEP_FIRST last = step == checkout.CHECKOUT_STEP_LAST if (first and data is not None and "same_billing_shipping" in data): data = copy(data) # Prevent second copy occuring for forcing step below when # moving backwards in steps. data["step"] = step for field in data: billing = field.replace("shipping_detail", "billing_detail") if "shipping_detail" in field and billing in data: data[field] = data[billing] if initial is not None: initial["step"] = step # Force the specified step in the posted data - this is # required to allow moving backwards in steps. if data is not None and int(data["step"]) != step: data = copy(data) data["step"] = step super(OrderForm, self).__init__(request, data=data, initial=initial) self._checkout_errors = errors settings.use_editable() # Hide Discount Code field if no codes are active. if (DiscountCode.objects.active().count() == 0 or not settings.SHOP_DISCOUNT_FIELD_IN_CHECKOUT): self.fields["discount_code"].widget = forms.HiddenInput() # Determine which sets of fields to hide for each checkout step. hidden = None if settings.SHOP_CHECKOUT_STEPS_SPLIT: if first: # Hide the cc fields for billing/shipping if steps are split. hidden = lambda f: f.startswith("card_") elif step == checkout.CHECKOUT_STEP_PAYMENT: # Hide the non-cc fields for payment if steps are split. hidden = lambda f: not f.startswith("card_") elif not settings.SHOP_PAYMENT_STEP_ENABLED: # Hide all the cc fields if payment step is not enabled. hidden = lambda f: f.startswith("card_") if settings.SHOP_CHECKOUT_STEPS_CONFIRMATION and last: # Hide all fields for the confirmation step. hidden = lambda f: True if hidden is not None: for field in self.fields: if hidden(field): self.fields[field].widget = forms.HiddenInput() self.fields[field].required = False # Set the choices for the cc expiry year relative to the current year. year = now().year choices = make_choices(range(year, year + 21)) self.fields["card_expiry_year"].choices = choices
def save(self, *args, **kwargs): # Set created and modified datetimes if not provided. if not self.id: self.created_datetime = now() self.modified_datetime = now() super(Answer, self).save(*args, **kwargs)
def get_object_list(self, request, *args, **kwargs): return BlogCategory.objects.filter(Q(blogposts__publish_date__lte=now()) | Q(blogposts__publish_date__isnull=True), Q(blogposts__expiry_date__gte=now()) | Q(blogposts__expiry_date__isnull=True), Q(blogposts__status=CONTENT_STATUS_PUBLISHED)).distinct()
def get_object_list(self, request, *args, **kwargs): return RestPeriod.objects.filter(Q(recipe__publish_date__lte=now()) | Q(recipe__publish_date__isnull=True), Q(recipe__expiry_date__gte=now()) | Q(recipe__expiry_date__isnull=True), Q(recipe__status=CONTENT_STATUS_PUBLISHED))
def __init__(self, request, step, data=None, initial=None, errors=None): """ Handle setting shipping field values to the same as billing field values in case JavaScript is disabled, hiding fields for the current step. """ get_saved_card = True # Copy billing fields to shipping fields if "same" checked. first = step == checkout.CHECKOUT_STEP_FIRST last = step == checkout.CHECKOUT_STEP_LAST if (first and data is not None and "same_billing_shipping" in data): data = copy(data) # Prevent second copy occuring for forcing step below when # moving backwards in steps. data["step"] = step for field in data: billing = field.replace("shipping_detail", "billing_detail") if "shipping_detail" in field and billing in data: data[field] = data[billing] if initial is not None: initial["step"] = step # Force the specified step in the posted data - this is # required to allow moving backwards in steps. if data is not None and int(data["step"]) != step: data = copy(data) data["step"] = step super(OrderForm, self).__init__(request, data=data, initial=initial) self._checkout_errors = errors settings.use_editable() # Hide Discount Code field if no codes are active. if (DiscountCode.objects.active().count() == 0 or not settings.SHOP_DISCOUNT_FIELD_IN_CHECKOUT): self.fields["discount_code"].widget = forms.HiddenInput() # Determine which sets of fields to hide for each checkout step. hidden = None if settings.SHOP_CHECKOUT_STEPS_SPLIT: if first: # Hide the cc fields for billing/shipping if steps are split. hidden = lambda f: (f.startswith("card_") or f == "stripe_token" or f == "last_4_digits" or f == "use_saved_card") get_saved_card = False elif step == checkout.CHECKOUT_STEP_PAYMENT: # TODO: If this user has a stripe customer object, get it and the saved card # Allow user to use saved card. # Hide the non-cc fields for payment if steps are split. hidden = lambda f: not (f.startswith("card_") or f == "stripe_token" or f == "last_4_digits") elif not settings.SHOP_PAYMENT_STEP_ENABLED: # Hide all the cc fields if payment step is not enabled. hidden = lambda f: (f.startswith("card_") or f == "stripe_token" or f == "last_4_digits" or f == "use_saved_card") get_saved_card = False if settings.SHOP_CHECKOUT_STEPS_CONFIRMATION and last: # Hide all fields for the confirmation step. hidden = lambda f: True if hidden is not None: for field in self.fields: if hidden(field): self.fields[field].widget = forms.HiddenInput() self.fields[field].required = False hide_saved_card = True hide_card_save_options = True if not settings.ALLOW_SAVED_CREDIT_CARDS: get_saved_card = False if get_saved_card: #Get stripe customer and their saved card if request.user.is_authenticated(): User = request.user customer = getStripeCustomerFromUser(User) hide_card_save_options = False if customer.cards.count > 0: brand,last4 = getBrandAndLast4OfDefaultCard(customer) if brand is not None and last4 is not None: self.fields['use_saved_card'].label = "Use {} ending in {}".format(brand, last4) hide_saved_card = False if hide_saved_card: self.fields['use_saved_card'].widget = forms.HiddenInput() if hide_card_save_options: self.fields['card_save_card'].widget = forms.HiddenInput() # Set the choices for the cc expiry year relative to the current year. year = now().year choices = make_choices(range(year, year + 21)) self.fields["card_expiry_year"].choices = choices
def test_category_filters(self): """ Test the category filters returns expected results. """ self._product.variations.all().delete() self.assertCategoryFilteredProducts(0) # Test option filters - add a variation with one option, and # assign another option as a category filter. Check that no # products match the filters, then add the first option as a # category filter and check that the product is matched. option_field, options = self._options.items()[0] option1, option2 = options[:2] # Variation with the first option. self._product.variations.create_from_options({option_field: [option1]}) # Filter with the second option option = ProductOption.objects.get(type=option_field[-1], name=option2) self.assertCategoryFilteredProducts(0) # First option as a filter. option = ProductOption.objects.get(type=option_field[-1], name=option1) self._category.options.add(option) self.assertCategoryFilteredProducts(1) # Test price filters - add a price filter that when combined # with previously created filters, should match no products. # Update the variations to match the filter for a unit price, # then with sale prices, checking correct matches based on sale # dates. self._category.combined = True self._category.price_min = TEST_PRICE self.assertCategoryFilteredProducts(0) self._product.variations.all().update(unit_price=TEST_PRICE) self.assertCategoryFilteredProducts(1) n, d = now(), timedelta(days=1) tomorrow, yesterday = n + d, n - d self._product.variations.all().update(unit_price=0, sale_price=TEST_PRICE, sale_from=tomorrow) self.assertCategoryFilteredProducts(0) self._product.variations.all().update(sale_from=yesterday) self.assertCategoryFilteredProducts(1) # Clean up previously added filters and check that explicitly # assigned products match. for option in self._category.options.all(): self._category.options.remove(option) self._category.price_min = None self.assertCategoryFilteredProducts(0) self._category.products.add(self._product) self.assertCategoryFilteredProducts(1) # Test the ``combined`` field - create a variation which # matches a price filter, and a separate variation which # matches an option filter, and check that the filters # have no results when ``combined`` is set, and that the # product matches when ``combined`` is disabled. self._product.variations.all().delete() self._product.variations.create_from_options({option_field: [option1, option2]}) # Price variation and filter. variation = self._product.variations.get(**{option_field: option1}) variation.unit_price = TEST_PRICE variation.save() self._category.price_min = TEST_PRICE # Option variation and filter. option = ProductOption.objects.get(type=option_field[-1], name=option2) self._category.options.add(option) # Check ``combined``. self._category.combined = True self.assertCategoryFilteredProducts(0) self._category.combined = False self.assertCategoryFilteredProducts(1)
def __init__(self, request, step, data=None, initial=None, errors=None): """ Setup for each order form step which does a few things: - Calls OrderForm.preprocess on posted data - Sets up any custom checkout errors - Hides the discount code field if applicable - Hides sets of fields based on the checkout step - Sets year choices for cc expiry field based on current date """ # ``data`` is usually the POST attribute of a Request object, # which is an immutable QueryDict. We want to modify it, so we # need to make a copy. data = copy(data) # Force the specified step in the posted data, which is # required to allow moving backwards in steps. Also handle any # data pre-processing, which subclasses may override. if data is not None: data["step"] = step data = self.preprocess(data) if initial is not None: initial["step"] = step super(OrderForm, self).__init__(request, data=data, initial=initial) self._checkout_errors = errors # Hide Discount Code field if no codes are active. settings.use_editable() no_discounts = DiscountCode.objects.active().count() == 0 if no_discounts or not settings.SHOP_DISCOUNT_FIELD_IN_CHECKOUT: self.fields["discount_code"].widget = forms.HiddenInput() # Determine which sets of fields to hide for each checkout step. # A ``hidden_filter`` function is defined that's used for # filtering out the fields to hide. is_first_step = step == checkout.CHECKOUT_STEP_FIRST is_last_step = step == checkout.CHECKOUT_STEP_LAST is_payment_step = step == checkout.CHECKOUT_STEP_PAYMENT hidden_filter = lambda f: False if settings.SHOP_CHECKOUT_STEPS_SPLIT: if is_first_step: # Hide cc fields for billing/shipping if steps are split. hidden_filter = lambda f: f.startswith("card_") elif is_payment_step: # Hide non-cc fields for payment if steps are split. hidden_filter = lambda f: not f.startswith("card_") elif not settings.SHOP_PAYMENT_STEP_ENABLED: # Hide all cc fields if payment step is not enabled. hidden_filter = lambda f: f.startswith("card_") if settings.SHOP_CHECKOUT_STEPS_CONFIRMATION and is_last_step: # Hide all fields for the confirmation step. hidden_filter = lambda f: True for field in filter(hidden_filter, self.fields): self.fields[field].widget = forms.HiddenInput() self.fields[field].required = False # Set year choices for cc expiry, relative to the current year. year = now().year choices = make_choices(range(year, year + 21)) self.fields["card_expiry_year"].choices = choices