BO 1.23 controlling, cron: sync customers
This commit is contained in:
parent
ffbfe4c877
commit
3c02685ed6
@ -12,3 +12,4 @@ from .training_plan import TrainingPlanAdmin, TrainingPlanDetailAdmin
|
||||
from .faq import FaqAdmin
|
||||
from .split_tests import SplitTestAdmin
|
||||
from .training_plan_day import TrainingPlanDayAdmin
|
||||
from .controlling import ControllingAdmin
|
||||
|
@ -1,6 +1,9 @@
|
||||
{% extends "admin/base_site.html" %}
|
||||
|
||||
{% block extrahead %}
|
||||
<script>window.CKEDITOR_BASEPATH = '/static/ckeditor/ckeditor/';</script>
|
||||
{{ block.super }}
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<p>Controlling</p>
|
||||
{% endblock %}
|
||||
|
@ -0,0 +1,29 @@
|
||||
from django.contrib import admin
|
||||
from django.db import models
|
||||
from django.urls import path
|
||||
from django.http import HttpResponse
|
||||
|
||||
|
||||
class Controlling(models.Model):
|
||||
class Meta:
|
||||
verbose_name_plural = 'Controlling'
|
||||
app_label = 'aitrainer_backoffice'
|
||||
|
||||
|
||||
def my_custom_view(request):
|
||||
return HttpResponse('Admin Custom View')
|
||||
|
||||
|
||||
class ControllingAdmin(admin.ModelAdmin):
|
||||
model = Controlling
|
||||
|
||||
def get_urls(self):
|
||||
view_name = '{}_{}_changelist'.format(
|
||||
self.model._meta.app_label, self.model._meta.model_name)
|
||||
return [
|
||||
path('my_admin_path/', my_custom_view, name=view_name),
|
||||
]
|
||||
|
||||
|
||||
admin.site.register(Controlling, ControllingAdmin)
|
||||
admin.autodiscover()
|
22
aitrainer_backoffice/aitrainer_backoffice/db_router.py
Normal file
22
aitrainer_backoffice/aitrainer_backoffice/db_router.py
Normal file
@ -0,0 +1,22 @@
|
||||
class TestRouter:
|
||||
"""
|
||||
A router to control all database operations on models
|
||||
"""
|
||||
live_app_labels = {'controlling'}
|
||||
|
||||
def db_for_read(self, model, **hints):
|
||||
if model._meta.app_label == 'controlling':
|
||||
return 'live'
|
||||
else:
|
||||
return 'default'
|
||||
|
||||
def db_for_write(self, model, **hints):
|
||||
if model._meta.app_label == 'controlling':
|
||||
raise Exception("This table cannot be changed!")
|
||||
return 'default'
|
||||
|
||||
def allow_relation(self, obj1, obj2, **hints):
|
||||
return True
|
||||
|
||||
def allow_migrate(self, db, app_label, model_name=None, **hints):
|
||||
return False
|
@ -15,3 +15,4 @@ from .training_plan import TrainingPlan, TrainingPlanDetail
|
||||
from .faq import Faq, FaqTranslation
|
||||
from .split_tests import SplitTests
|
||||
from .training_plan_day import TrainingPlanDay, TrainingPlanDayTranslation
|
||||
from .controlling import Controlling
|
@ -0,0 +1,9 @@
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Controlling(models.Model):
|
||||
sort = models.IntegerField(blank=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name_plural = 'Controlling'
|
||||
app_label = 'controlling'
|
28
aitrainer_backoffice/aitrainer_backoffice/models/multi_db.py
Normal file
28
aitrainer_backoffice/aitrainer_backoffice/models/multi_db.py
Normal file
@ -0,0 +1,28 @@
|
||||
from django.contrib import admin
|
||||
|
||||
|
||||
class MultiDBModelAdmin(admin.ModelAdmin):
|
||||
# A handy constant for the name of the alternate database.
|
||||
using = 'default'
|
||||
|
||||
def save_model(self, request, obj, form, change):
|
||||
# Tell Django to save objects to the 'other' database.
|
||||
obj.save(using=self.using)
|
||||
|
||||
def delete_model(self, request, obj):
|
||||
# Tell Django to delete objects from the 'other' database
|
||||
obj.delete(using=self.using)
|
||||
|
||||
def get_queryset(self, request):
|
||||
# Tell Django to look for objects on the 'other' database.
|
||||
return super().get_queryset(request).using(self.using)
|
||||
|
||||
def formfield_for_foreignkey(self, db_field, request, **kwargs):
|
||||
# Tell Django to populate ForeignKey widgets using a query
|
||||
# on the 'other' database.
|
||||
return super().formfield_for_foreignkey(db_field, request, using=self.using, **kwargs)
|
||||
|
||||
def formfield_for_manytomany(self, db_field, request, **kwargs):
|
||||
# Tell Django to populate ManyToMany widgets using a query
|
||||
# on the 'other' database.
|
||||
return super().formfield_for_manytomany(db_field, request, using=self.using, **kwargs)
|
@ -12,7 +12,7 @@ https://docs.djangoproject.com/en/3.0/ref/settings/
|
||||
|
||||
import os
|
||||
|
||||
BACKOFFICE_VERSION = 1.22
|
||||
BACKOFFICE_VERSION = 1.23
|
||||
|
||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
@ -38,6 +38,7 @@ ALLOWED_HOSTS = ['localhost']
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'aitrainer_backoffice',
|
||||
'controlling.apps.ControllingConfig',
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
@ -47,6 +48,8 @@ INSTALLED_APPS = [
|
||||
'ckeditor',
|
||||
'ckeditor_uploader',
|
||||
'django_admin_json_editor',
|
||||
'rangefilter',
|
||||
'django_crontab'
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
@ -93,7 +96,7 @@ DATABASES = {
|
||||
},
|
||||
'live': {
|
||||
'ENGINE': 'django.db.backends.mysql',
|
||||
'NAME': 'aitrainer2',
|
||||
'NAME': 'aitrainer',
|
||||
'USER': 'aitrainer',
|
||||
'PASSWORD': 'andio2009',
|
||||
'HOST': '127.0.0.1',
|
||||
@ -101,6 +104,8 @@ DATABASES = {
|
||||
}
|
||||
}
|
||||
|
||||
DATABASE_ROUTERS = ['aitrainer_backoffice.db_router.TestRouter']
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators
|
||||
|
||||
@ -166,3 +171,7 @@ LOGGING = {
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
CRONJOBS = [
|
||||
('4 */1 * * *', 'controlling.cron.sync_customers')
|
||||
]
|
||||
|
@ -12,7 +12,7 @@ https://docs.djangoproject.com/en/3.0/ref/settings/
|
||||
|
||||
import os
|
||||
|
||||
BACKOFFICE_VERSION = 1.22
|
||||
BACKOFFICE_VERSION = 1.23
|
||||
|
||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
@ -34,6 +34,7 @@ ALLOWED_HOSTS = ['62.171.188.119', 'localhost', 'andio.eu', 'aitrainer.info','ai
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'aitrainer_backoffice.aitrainer_backoffice',
|
||||
'controlling.apps.ControllingConfig',
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
@ -43,6 +44,8 @@ INSTALLED_APPS = [
|
||||
'ckeditor',
|
||||
'ckeditor_uploader',
|
||||
'django_admin_json_editor',
|
||||
'rangefilter',
|
||||
'django_crontab'
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
@ -89,6 +92,8 @@ DATABASES = {
|
||||
}
|
||||
}
|
||||
|
||||
DATABASE_ROUTERS = ['aitrainer_backoffice.db_router.TestRouter']
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators
|
||||
|
||||
@ -170,3 +175,7 @@ CACHES = {
|
||||
}
|
||||
}
|
||||
|
||||
CRONJOBS = [
|
||||
('4 */1 * * *', 'controlling.cron.sync_customers')
|
||||
]
|
||||
|
||||
|
@ -0,0 +1,12 @@
|
||||
{% extends 'admin/change_list.html' %}
|
||||
|
||||
{% block object-tools %}
|
||||
<div>
|
||||
<form action="mautic/" method="POST">
|
||||
{% csrf_token %}
|
||||
<button type="submit">Mautic Sync</button>
|
||||
</form>
|
||||
</div>
|
||||
<br />
|
||||
{{ block.super }}
|
||||
{% endblock %}
|
0
aitrainer_backoffice/controlling/__init__.py
Normal file
0
aitrainer_backoffice/controlling/__init__.py
Normal file
3
aitrainer_backoffice/controlling/admin/__init__.py
Normal file
3
aitrainer_backoffice/controlling/admin/__init__.py
Normal file
@ -0,0 +1,3 @@
|
||||
from .customer import CustomerAdmin
|
||||
from .frequent_customers import FrequentCustomersAdmin
|
||||
from .frequent_exercises import FrequentExerciseTypeAdmin
|
83
aitrainer_backoffice/controlling/admin/customer.py
Normal file
83
aitrainer_backoffice/controlling/admin/customer.py
Normal file
@ -0,0 +1,83 @@
|
||||
from abc import ABC
|
||||
from datetime import datetime
|
||||
|
||||
from django.contrib.admin import SimpleListFilter
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.contrib import admin
|
||||
from rangefilter.filters import DateRangeFilter, DateTimeRangeFilter
|
||||
from django.urls import path
|
||||
|
||||
from ..models.customer import Customer
|
||||
from ..models.customer import Sport
|
||||
from ..mautic import MauticHelper
|
||||
from ..cron import cron
|
||||
|
||||
|
||||
class SportFilter(SimpleListFilter, ABC):
|
||||
title = "Sport"
|
||||
parameter_name = 'sport_id'
|
||||
|
||||
def lookups(self, request, model_admin):
|
||||
data = []
|
||||
for s in Sport.objects.filter():
|
||||
data.append([s.sport_id, s.sport_name])
|
||||
return data
|
||||
|
||||
def queryset(self, request, queryset):
|
||||
if self.value():
|
||||
return Customer.objects.filter(sport__sport_id=self.value())
|
||||
else:
|
||||
return queryset
|
||||
|
||||
|
||||
class CustomerAdmin(admin.ModelAdmin):
|
||||
change_list_template = "controlling/mautic.html"
|
||||
list_display = ('customer_id', 'name','firstname', 'email', 'date_add', 'get_sport')
|
||||
list_filter = (
|
||||
('date_add', DateRangeFilter),
|
||||
SportFilter
|
||||
)
|
||||
|
||||
def get_sport(self, obj):
|
||||
return obj.sport.sport_name
|
||||
|
||||
get_sport.short_description = 'Sport'
|
||||
get_sport.admin_order_field = 'sport__sport_name'
|
||||
|
||||
|
||||
# If you would like to add a default range filter
|
||||
# method pattern "get_rangefilter_{field_name}_default"
|
||||
def get_rangefilter_date_add_default(self, request):
|
||||
return (datetime.today(), datetime.today())
|
||||
|
||||
# If you would like to change a title range filter
|
||||
# method pattern "get_rangefilter_{field_name}_title"
|
||||
def get_rangefilter_date_add_title(self, request, field_path):
|
||||
return _('Registered')
|
||||
|
||||
def changelist_view(self, request, extra_context=None):
|
||||
if not request.GET.__contains__('date_add__range__gte'):
|
||||
q = request.GET.copy()
|
||||
q['date_add__range__gte'] = datetime.today()
|
||||
q['date_add__range__lte'] = datetime.today()
|
||||
request.GET = q
|
||||
request.META['QUERY_STRING'] = request.GET.urlencode()
|
||||
return super(CustomerAdmin, self).changelist_view(
|
||||
request, extra_context=extra_context)
|
||||
|
||||
def get_urls(self):
|
||||
urls = super().get_urls()
|
||||
my_urls = [
|
||||
path('mautic/', self.set_mautic),
|
||||
]
|
||||
return my_urls + urls
|
||||
|
||||
def set_mautic(self, request):
|
||||
cron.sync_customers()
|
||||
self.message_user(request, "All heroes are now synced")
|
||||
return HttpResponseRedirect("../")
|
||||
|
||||
|
||||
admin.site.register(Customer, CustomerAdmin)
|
||||
admin.autodiscover()
|
24
aitrainer_backoffice/controlling/admin/frequent_customers.py
Normal file
24
aitrainer_backoffice/controlling/admin/frequent_customers.py
Normal file
@ -0,0 +1,24 @@
|
||||
from django.contrib import admin
|
||||
|
||||
from ..models.frequent_customers import FrequentCustomers
|
||||
|
||||
|
||||
|
||||
class FrequentCustomersAdmin(admin.ModelAdmin):
|
||||
list_display = ('customer_id', 'name', 'firstname', 'email', 'exercise_count')
|
||||
|
||||
#def get_queryset(self, request):
|
||||
# qs = super(FrequentCustomersAdmin, self).get_queryset(request)
|
||||
# return FrequentCustomers.objects.extra(
|
||||
# select=["customer_id, name, firstname, email, ( select count(exercise_id) from exercises where exercises.customer_id = customer_customer.id) as exercise_count "],
|
||||
#group_by=["customer_id"],
|
||||
#having=["exercise_count > 10"],
|
||||
# order_by=["-exercise_count"]
|
||||
#)
|
||||
#return qs.values("exercises").annotate(exercise_count=Count('exercises')).order_by('-exercise_count')
|
||||
#return Exercises.objects.annotate(count=Count("customer__customer_id"))
|
||||
#return qs.values('user').annotate(visit_sum=Count('visit_count')).order_by('-visit_sum')
|
||||
|
||||
|
||||
admin.site.register(FrequentCustomers, FrequentCustomersAdmin)
|
||||
admin.autodiscover()
|
15
aitrainer_backoffice/controlling/admin/frequent_exercises.py
Normal file
15
aitrainer_backoffice/controlling/admin/frequent_exercises.py
Normal file
@ -0,0 +1,15 @@
|
||||
from django.contrib import admin
|
||||
|
||||
from ..models import ExerciseType
|
||||
|
||||
|
||||
class FrequentExerciseTypeAdmin(admin.ModelAdmin):
|
||||
list_display = ('exercise_type_id', 'name', 'exercise_count')
|
||||
|
||||
def get_queryset(self, request):
|
||||
qs = super(FrequentExerciseTypeAdmin, self).get_queryset(request)
|
||||
return qs.filter(active=True)
|
||||
|
||||
|
||||
admin.site.register(ExerciseType, FrequentExerciseTypeAdmin)
|
||||
admin.autodiscover()
|
6
aitrainer_backoffice/controlling/apps.py
Normal file
6
aitrainer_backoffice/controlling/apps.py
Normal file
@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class ControllingConfig(AppConfig):
|
||||
app_label = 'controlling'
|
||||
name = 'controlling'
|
0
aitrainer_backoffice/controlling/cron/__init__.py
Normal file
0
aitrainer_backoffice/controlling/cron/__init__.py
Normal file
6
aitrainer_backoffice/controlling/cron/cron.py
Normal file
6
aitrainer_backoffice/controlling/cron/cron.py
Normal file
@ -0,0 +1,6 @@
|
||||
from ..mautic import MauticHelper
|
||||
|
||||
|
||||
def sync_customers():
|
||||
helper = MauticHelper()
|
||||
helper.sync()
|
1
aitrainer_backoffice/controlling/mautic/__init__.py
Normal file
1
aitrainer_backoffice/controlling/mautic/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
from .helper import MauticHelper
|
71
aitrainer_backoffice/controlling/mautic/helper.py
Normal file
71
aitrainer_backoffice/controlling/mautic/helper.py
Normal file
@ -0,0 +1,71 @@
|
||||
import requests
|
||||
import logging
|
||||
from django.db import connections
|
||||
|
||||
from ..models.customer import Customer
|
||||
|
||||
|
||||
class MauticHelper:
|
||||
|
||||
|
||||
def sync(self):
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.info("Syncronising...")
|
||||
|
||||
last_synced_date = self.get_last_synced_date()
|
||||
|
||||
if len(last_synced_date) != 0:
|
||||
qs = Customer.objects.raw(
|
||||
'SELECT * from customer WHERE date_add > "' + last_synced_date + '" and synced_date is null')
|
||||
else:
|
||||
qs = Customer.objects.raw(
|
||||
'SELECT * from customer WHERE synced_date is null')
|
||||
|
||||
headers = {
|
||||
'content-type': "application/x-www-form-urlencoded",
|
||||
'cache-control': "no-cache"
|
||||
}
|
||||
index = 0
|
||||
for customer in qs:
|
||||
goal = customer.goal if customer.goal is not None else ""
|
||||
fitness_level = customer.fitness_level if customer.fitness_level is not None else ""
|
||||
data = "mauticform[email]=" + customer.email + \
|
||||
"&mauticform[f_name]=" + customer.name + \
|
||||
"&mauticform[firstname]=" + customer.firstname + \
|
||||
"&mauticform[goal]=" + goal + \
|
||||
"&mauticform[fitness_level]=" + fitness_level + \
|
||||
"&mauticform[subscribed]=" + str(customer.date_add) + \
|
||||
"&mauticform[database_id]=" + str(customer.customer_id) + \
|
||||
"&mauticform[formId]=1" + \
|
||||
"&mauticform[formName]=appsync"
|
||||
|
||||
print(data)
|
||||
|
||||
form_url = 'https://mautic.aitrainer.app/form/submit?formId=1'
|
||||
response = requests.post(form_url, data=data.encode('utf-8'), headers=headers)
|
||||
print(str(response.status_code))
|
||||
|
||||
if response.status_code == 200:
|
||||
with connections["live"].cursor() as cursor:
|
||||
cursor.execute("UPDATE customer SET synced_date = NOW() WHERE customer_id="
|
||||
+ str(customer.customer_id))
|
||||
#if index == 0:
|
||||
# break
|
||||
index = index + 1
|
||||
|
||||
logger.info("Syncronised customer count: " + str(index))
|
||||
|
||||
return True
|
||||
|
||||
def get_last_synced_date(self):
|
||||
qs = Customer.objects.raw('SELECT customer_id, max(synced_date) as synced_date from customer')
|
||||
for c in qs:
|
||||
if c.synced_date is None:
|
||||
return ""
|
||||
synced_date = c.synced_date.strftime('%Y-%m-%d')
|
||||
print(synced_date)
|
||||
return synced_date
|
||||
|
||||
def sync_frequent_users(self):
|
||||
print("SYNC FREQ USERS")
|
||||
return True
|
4
aitrainer_backoffice/controlling/models/__init__.py
Normal file
4
aitrainer_backoffice/controlling/models/__init__.py
Normal file
@ -0,0 +1,4 @@
|
||||
from .customer import Customer
|
||||
from .exercises import Exercises
|
||||
from .exercise_type import ExerciseType
|
||||
from .frequent_customers import FrequentCustomers
|
38
aitrainer_backoffice/controlling/models/customer.py
Normal file
38
aitrainer_backoffice/controlling/models/customer.py
Normal file
@ -0,0 +1,38 @@
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
||||
class Sport(models.Model):
|
||||
sport_id = models.AutoField(primary_key = True)
|
||||
language_code = models.CharField(max_length=2,default="hu")
|
||||
sport_name = models.CharField(max_length=100)
|
||||
|
||||
class Meta:
|
||||
db_table = 'sport_translation'
|
||||
|
||||
|
||||
class Customer(models.Model):
|
||||
customer_id = models.BigAutoField(primary_key=True)
|
||||
name = models.CharField(max_length=100, help_text='Last name', verbose_name=_("name"))
|
||||
firstname = models.CharField(max_length=100, help_text='First name', verbose_name=_("firstname"))
|
||||
email = models.CharField(max_length=100)
|
||||
sport = models.ForeignKey(Sport, on_delete=models.CASCADE)
|
||||
goal = models.CharField(max_length=20)
|
||||
fitness_level = models.CharField(max_length=20)
|
||||
date_add = models.DateField()
|
||||
synced_date = models.DateTimeField(blank=True,null=True)
|
||||
|
||||
def has_add_permission(self, request):
|
||||
return False
|
||||
|
||||
def has_delete_permission(self, request, obj=None):
|
||||
return False
|
||||
|
||||
class Meta:
|
||||
db_table = 'customer'
|
||||
verbose_name = _("Customer")
|
||||
verbose_name_plural = _("Customers")
|
||||
app_label = 'controlling'
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
28
aitrainer_backoffice/controlling/models/exercise_type.py
Normal file
28
aitrainer_backoffice/controlling/models/exercise_type.py
Normal file
@ -0,0 +1,28 @@
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from ..models.exercises import Exercises
|
||||
|
||||
|
||||
class ExerciseType(models.Model):
|
||||
exercise_type_id = models.AutoField(primary_key=True)
|
||||
name = models.CharField(max_length=50)
|
||||
active = models.BooleanField()
|
||||
|
||||
|
||||
def has_add_permission(self, request):
|
||||
return False
|
||||
|
||||
def has_delete_permission(self, request, obj=None):
|
||||
return False
|
||||
|
||||
@property
|
||||
def exercise_count(self):
|
||||
count = Exercises.objects.filter(exercise_type_id=self.exercise_type_id).count()
|
||||
return count
|
||||
|
||||
class Meta:
|
||||
db_table = 'exercise_type'
|
||||
verbose_name = _("Frequent Exercise")
|
||||
verbose_name_plural = _("Frequent Exercises")
|
||||
|
25
aitrainer_backoffice/controlling/models/exercises.py
Normal file
25
aitrainer_backoffice/controlling/models/exercises.py
Normal file
@ -0,0 +1,25 @@
|
||||
from django.db import models
|
||||
|
||||
#from ..models.exercise_type import ExerciseType
|
||||
from ..models.customer import Customer
|
||||
|
||||
|
||||
class Exercises(models.Model):
|
||||
exercise_id = models.BigAutoField(primary_key=True)
|
||||
customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
|
||||
exercise_type_id = models.IntegerField()
|
||||
#exercise_type = models.ForeignKey(ExerciseType, on_delete=models.CASCADE)
|
||||
date_add = models.DateField()
|
||||
quantity = models.DecimalField(decimal_places=0, max_digits=6)
|
||||
unit = models.CharField(max_length=20)
|
||||
unit_quantity = models.DecimalField(decimal_places=0, max_digits=6,blank=True, null=True)
|
||||
|
||||
|
||||
def has_add_permission(self, request):
|
||||
return False
|
||||
|
||||
def has_delete_permission(self, request, obj=None):
|
||||
return False
|
||||
|
||||
class Meta:
|
||||
db_table = 'exercises'
|
@ -0,0 +1,32 @@
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from .exercises import Exercises
|
||||
|
||||
|
||||
class FrequentCustomers(models.Model):
|
||||
customer_id = models.BigAutoField(primary_key=True)
|
||||
name = models.CharField(max_length=100, help_text='Last name', verbose_name=_("name"))
|
||||
firstname = models.CharField(max_length=100, help_text='First name', verbose_name=_("firstname"))
|
||||
email = models.CharField(max_length=100)
|
||||
date_add = models.DateField()
|
||||
#exercises = models.ManyToManyField(Exercises)
|
||||
|
||||
#def exercises(self):
|
||||
# exercises = Exercises.objects.filter(customer__customer_id=self.customer_id)
|
||||
# return exercises
|
||||
|
||||
@property
|
||||
def exercise_count(self):
|
||||
count = Exercises.objects.filter(customer__customer_id=self.customer_id).count()
|
||||
return count
|
||||
|
||||
class Meta:
|
||||
db_table = 'customer'
|
||||
verbose_name = _("Frequent Customer")
|
||||
verbose_name_plural = _("Frequent Customers")
|
||||
#ordering = ['exercise_count']
|
||||
#filter(exercise_count__gt=10)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
0
aitrainer_backoffice/controlling/views.py
Normal file
0
aitrainer_backoffice/controlling/views.py
Normal file
Loading…
Reference in New Issue
Block a user