0

I have my django model Customer which consists of these fields;

'Customer_ID', 'Name', 'Gender', 'Age', 'Nationality', 'Address', 'Account_Type', 'Salary', 'Balance', 'Employer_Stability', 'Customer_Loyalty', 'Residential_Status' and 'Service_Level'

where Service_Level = Silver, Gold or Platinum.

I have managed to create a custom-admin-action to just update the Service_Level without any condition as shown below;

def allocate_service(ModelAdmin, request, queryset):
    queryset.update(Service_Level=2)

@admin.register(models.Customer)
class CustomerAdmin(admin.ModelAdmin):
    icon = '<i class="material-icons">account_box</i>'
    list_display = ('Customer_ID', 'Name', 'Gender', 'Nationality', 
                'Account_Type', 'Salary', 'Balance', 'Service_Level')
    list_per_page = 10
    list_filter = ('Nationality', 'Gender')
    actions = [allocate_service ]

I would like to add an action that assigns the Service_Level to a customer/ customers depending on the values of the bold features above (Age, Salary etc.). e.g. when Age > 25 and Salary >= 800 and Account_Type == Savings then Service_Level = Platinum.

my Models are as follows:

class Service(models.Model):
#service_no = models.CharField(primary_key=True, max_length=4)
service_name = models.CharField(primary_key=True, max_length=40)
service_description = models.TextField(default='')

class Meta:
    db_table = 'services'
    ordering = ['service_name']

def __str__(self):
    return self.service_name

# Customer Model: too big so I ommited the other fields here

class Customer(models.Model):
    Service_Level = models.ForeignKey(Service, on_delete=models.CASCADE, 
        db_column='service_name', null=True, blank=True)

I removed the option to use int key on Service_Level

I am not sure how I am supposed to go about it. Help will be appreciated

Terry Mafura
  • 147
  • 2
  • 15
  • Have you tried anything? Have you looked at the official [django admin actions](https://docs.djangoproject.com/en/1.11/ref/contrib/admin/actions/)? – nik_m Apr 17 '17 at 05:28
  • @nik_m I am able to create custom actions, for example; I created an action to export to CSV and another one to update the ***Service_Level*** without a condition. `def allocate_service(ModelAdmin, request, queryset): queryset.update(Service_Level=2)` this updates the Service_Level column to Silver. However, I am failing to implement conditions as mentioned above – Terry Mafura Apr 17 '17 at 06:37
  • 1
    You must update your question with more details. What do you want to happen when you select one or more customers? You have to be more specific! – nik_m Apr 17 '17 at 06:43
  • thanks @nik_m, I have updated the question – Terry Mafura Apr 17 '17 at 06:55

1 Answers1

1

You can iterate over the queryset and perform your conditions on each one seperately, instead of just applying a "global" update to all (queryset.update(Service_Level=2)).

from django.contrib.messages import SUCCESS

def allocate_service(modeladmin, request, queryset):
    platinum_customers = []
    silver_customers = []
    message = ''

    for customer in queryset:
        if customer.Age > 25 and customer.Salary >= 800 and customer.Account_Type == 'Savings':
            customer.Service_Level.service_name = 'Platinum'
            platinum_customers.append(customer.name)
        elif other_condition_here:
            customer.Service_Level.service_name = 'Silver'
            silver_customers.append(customer.name)
        customer.save()

    if platinum_customers:
        message = 'The following customers are now platinum: {}'.format(', '.join(platinum_customers))
    if silver_customers:
        message = 'The following customers are now silver: {}'.format(', '.join(silver_customers))
    if not platinum_customers and not silver_customers:
        message = 'No customer changes!'
    modeladmin.message_user(request, message, level=SUCESS)
nik_m
  • 11,825
  • 4
  • 43
  • 57
  • It is not updating the table field. it is just returning a null – Terry Mafura Apr 17 '17 at 08:32
  • It is now just displaying a message with customer name but not adding the Service_Level. see image http://imgur.com/a/x1LjF – Terry Mafura Apr 17 '17 at 09:10
  • Show your models please. Maybe the lines `customer.Service_Level == 'Platinum'` and `customer.Service_Level == 'Silver'` might become `customer.Service_Level == 1` and `customer.Service_Level == 2`, respectively. – nik_m Apr 17 '17 at 09:13
  • I added the models on the question – Terry Mafura Apr 17 '17 at 09:26
  • I thought I did not have to include the other object since they are related. I am now getting an error `'NoneType' object has no attribute 'service_name'` – Terry Mafura Apr 17 '17 at 09:45
  • That's very weird.... Put a `print(customer.Service_Level)` after the `for` loop and comment out all the rest. Now, select multiple customers and execute this action. Does it print the `Service_Level` names? If yes, then change to `print(customer.Service_Level.service_name)` and perform same steps. – nik_m Apr 17 '17 at 09:51
  • `print(customer.Service_Level` is printing `None` and the other one is returning the `'NoneType' object has no attribute 'service_name'` – Terry Mafura Apr 17 '17 at 10:01
  • I think I had a typo in my code. I had `customer.Service_Level.service_name == 'Platinum'` instead of `customer.Service_Level.service_name = 'Platinum'`. Note the double `=`. – nik_m Apr 17 '17 at 11:23
  • yeah that helped too but it gave a `Cannot assign "'Platinum Package'": "Customer.Service_Level" must be a "Service" instance.` so I ended up editing my assignment to `customer.Service_Level = Service.objects.get(service_name = 'Silver Package')` and it added the Service_Level. – Terry Mafura Apr 17 '17 at 11:44