Skip to content

Commit 6bf20df

Browse files
committed
add smallintegerfield to django examples. fix some details of other examples
1 parent ebd9ad6 commit 6bf20df

File tree

4 files changed

+838
-3
lines changed

4 files changed

+838
-3
lines changed

content/pages/examples/django/django-db-models-positivesmallintegerfield.markdown

Lines changed: 243 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ meta: Python code examples for the PositiveSmallIntegerField class used in the D
88

99

1010
[PositiveSmallIntegerField](https://github.com/django/django/blob/master/django/db/models/fields/__init__.py)
11-
([documentation](https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.PositiveIntegerField))
11+
([documentation](https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.PositiveSmallIntegerField))
1212
is a [Django ORM](/django-orm.html) mapping from your Python code to an
1313
integer-type column in your [relational database](/databases.html)
14-
that is restricted to only positive values from 0 to 2147483647.
14+
that is restricted to only positive values from 0 to 32767.
1515

1616
Note that `PositiveSmallIntegerField` is defined within the
1717
[django.db.models.fields](https://github.com/django/django/blob/master/django/db/models/fields/__init__.py)
@@ -348,3 +348,244 @@ def inlineformset_factory(parent_model, model, form=ModelForm,
348348
```
349349

350350

351+
## Example 4 from django-flexible-subscriptions
352+
[django-flexible-subscriptions](https://github.com/studybuffalo/django-flexible-subscriptions)
353+
([project documentation](https://django-flexible-subscriptions.readthedocs.io/en/latest/)
354+
and
355+
[PyPI package information](https://pypi.org/project/django-flexible-subscriptions/))
356+
provides boilerplate code for adding subscription and recurrent billing
357+
to [Django](/django.html) web applications. Various payment providers
358+
can be added on the back end to run the transactions.
359+
360+
The django-flexible-subscriptions project is open sourced under the
361+
[GNU General Public License v3.0](https://github.com/studybuffalo/django-flexible-subscriptions/blob/master/LICENSE).
362+
363+
[**django-flexible-subscriptions / subscriptions / . / models.py**](https://github.com/studybuffalo/django-flexible-subscriptions/blob/master/subscriptions/./models.py)
364+
365+
```python
366+
"""Models for the Flexible Subscriptions app."""
367+
from datetime import timedelta
368+
from uuid import uuid4
369+
370+
from django.contrib.auth import get_user_model
371+
from django.contrib.auth.models import Group
372+
from django.core.validators import MinValueValidator
373+
~~from django.db import models
374+
from django.utils.translation import ugettext_lazy as _
375+
376+
377+
# Convenience references for units for plan recurrence billing
378+
# ----------------------------------------------------------------------------
379+
ONCE = '0'
380+
SECOND = '1'
381+
MINUTE = '2'
382+
HOUR = '3'
383+
DAY = '4'
384+
WEEK = '5'
385+
MONTH = '6'
386+
YEAR = '7'
387+
RECURRENCE_UNIT_CHOICES = (
388+
(ONCE, 'once'),
389+
(SECOND, 'second'),
390+
(MINUTE, 'minute'),
391+
(HOUR, 'hour'),
392+
(DAY, 'day'),
393+
(WEEK, 'week'),
394+
(MONTH, 'month'),
395+
(YEAR, 'year'),
396+
)
397+
# ----------------------------------------------------------------------------
398+
399+
class PlanTag(models.Model):
400+
"""A tag for a subscription plan."""
401+
tag = models.CharField(
402+
help_text=_('the tag name'),
403+
max_length=64,
404+
unique=True,
405+
)
406+
407+
class Meta:
408+
ordering = ('tag',)
409+
410+
def __str__(self):
411+
return self.tag
412+
413+
class SubscriptionPlan(models.Model):
414+
"""Details for a subscription plan."""
415+
id = models.UUIDField(
416+
default=uuid4,
417+
editable=False,
418+
primary_key=True,
419+
verbose_name='ID',
420+
)
421+
plan_name = models.CharField(
422+
help_text=_('the name of the subscription plan'),
423+
max_length=128,
424+
)
425+
plan_description = models.CharField(
426+
blank=True,
427+
help_text=_('a description of the subscription plan'),
428+
max_length=512,
429+
null=True,
430+
)
431+
group = models.ForeignKey(
432+
Group,
433+
blank=True,
434+
help_text=_('the Django auth group for this plan'),
435+
null=True,
436+
on_delete=models.SET_NULL,
437+
related_name='plans',
438+
)
439+
tags = models.ManyToManyField(
440+
PlanTag,
441+
blank=True,
442+
help_text=_('any tags associated with this plan'),
443+
related_name='plans',
444+
)
445+
grace_period = models.PositiveIntegerField(
446+
default=0,
447+
help_text=_(
448+
'how many days after the subscription ends before the '
449+
'subscription expires'
450+
),
451+
)
452+
453+
class Meta:
454+
ordering = ('plan_name',)
455+
permissions = (
456+
('subscriptions', 'Can interact with subscription details'),
457+
)
458+
459+
def __str__(self):
460+
return self.plan_name
461+
462+
def display_tags(self):
463+
"""Displays tags as a string (truncates if more than 3)."""
464+
if self.tags.count() > 3:
465+
return '{}, ...'.format(
466+
', '.join(tag.tag for tag in self.tags.all()[:3])
467+
)
468+
469+
return ', '.join(tag.tag for tag in self.tags.all()[:3])
470+
471+
class PlanCost(models.Model):
472+
"""Cost and frequency of billing for a plan."""
473+
id = models.UUIDField(
474+
default=uuid4,
475+
editable=False,
476+
primary_key=True,
477+
verbose_name='ID',
478+
)
479+
plan = models.ForeignKey(
480+
SubscriptionPlan,
481+
help_text=_('the subscription plan for these cost details'),
482+
on_delete=models.CASCADE,
483+
related_name='costs',
484+
)
485+
~~ recurrence_period = models.PositiveSmallIntegerField(
486+
~~ default=1,
487+
~~ help_text=_('how often the plan is billed (per recurrence unit)'),
488+
~~ validators=[MinValueValidator(1)],
489+
~~ )
490+
recurrence_unit = models.CharField(
491+
choices=RECURRENCE_UNIT_CHOICES,
492+
default=MONTH,
493+
max_length=1,
494+
)
495+
cost = models.DecimalField(
496+
blank=True,
497+
decimal_places=4,
498+
help_text=_('the cost per recurrence of the plan'),
499+
max_digits=19,
500+
null=True,
501+
)
502+
503+
~~ class Meta:
504+
~~ ordering = ('recurrence_unit', 'recurrence_period', 'cost',)
505+
506+
@property
507+
def display_recurrent_unit_text(self):
508+
"""Converts recurrence_unit integer to text."""
509+
conversion = {
510+
ONCE: 'one-time',
511+
SECOND: 'per second',
512+
MINUTE: 'per minute',
513+
HOUR: 'per hour',
514+
DAY: 'per day',
515+
WEEK: 'per week',
516+
MONTH: 'per month',
517+
YEAR: 'per year',
518+
}
519+
520+
return conversion[self.recurrence_unit]
521+
522+
@property
523+
def display_billing_frequency_text(self):
524+
"""Generates human-readable billing frequency."""
525+
conversion = {
526+
ONCE: 'one-time',
527+
SECOND: {'singular': 'per second', 'plural': 'seconds'},
528+
MINUTE: {'singular': 'per minute', 'plural': 'minutes'},
529+
HOUR: {'singular': 'per hour', 'plural': 'hours'},
530+
DAY: {'singular': 'per day', 'plural': 'days'},
531+
WEEK: {'singular': 'per week', 'plural': 'weeks'},
532+
MONTH: {'singular': 'per month', 'plural': 'months'},
533+
YEAR: {'singular': 'per year', 'plural': 'years'},
534+
}
535+
536+
if self.recurrence_unit == ONCE:
537+
return conversion[ONCE]
538+
539+
~~ if self.recurrence_period == 1:
540+
~~ return conversion[self.recurrence_unit]['singular']
541+
542+
~~ return 'every {} {}'.format(
543+
~~ self.recurrence_period, conversion[self.recurrence_unit]['plural']
544+
~~ )
545+
546+
def next_billing_datetime(self, current):
547+
"""Calculates next billing date for provided datetime.
548+
549+
Parameters:
550+
current (datetime): The current datetime to compare
551+
against.
552+
553+
Returns:
554+
datetime: The next time billing will be due.
555+
"""
556+
~~ if self.recurrence_unit == SECOND:
557+
~~ return current + timedelta(seconds=self.recurrence_period)
558+
559+
~~ if self.recurrence_unit == MINUTE:
560+
~~ return current + timedelta(minutes=self.recurrence_period)
561+
562+
~~ if self.recurrence_unit == HOUR:
563+
~~ return current + timedelta(hours=self.recurrence_period)
564+
565+
~~ if self.recurrence_unit == DAY:
566+
~~ return current + timedelta(days=self.recurrence_period)
567+
568+
~~ if self.recurrence_unit == WEEK:
569+
~~ return current + timedelta(weeks=self.recurrence_period)
570+
571+
~~ if self.recurrence_unit == MONTH:
572+
~~ # Adds the average number of days per month as per:
573+
~~ # http://en.wikipedia.org/wiki/Month#Julian_and_Gregorian_calendars
574+
~~ # This handle any issues with months < 31 days and leap years
575+
~~ return current + timedelta(
576+
~~ days=30.4368 * self.recurrence_period
577+
~~ )
578+
579+
~~ if self.recurrence_unit == YEAR:
580+
~~ # Adds the average number of days per year as per:
581+
~~ # http://en.wikipedia.org/wiki/Year#Calendar_year
582+
~~ # This handle any issues with leap years
583+
~~ return current + timedelta(
584+
~~ days=365.2425 * self.recurrence_period
585+
~~ )
586+
587+
~~ return None
588+
589+
590+
## ... source file continues with no further relevant examples ...
591+
```

0 commit comments

Comments
 (0)