1

I want to add both choices of days and hours in my assigned_time field, along with adding how many days or how many hours. Here is what I tried that doesn't work. Here is my model.py

class Timesheet(models.Model):
    DAYS= 'D'
    HOURS = 'H'
    STATUS= [
        ('D', 'Days'),
        ('H', 'Hours')
    ]
    employee= models.ForeignKey(Employee, on_delete=models.CASCADE)
    date= models.DateField(verbose_name='Date')
    designation=models.ForeignKey(Designation, on_delete=models.CASCADE)
    projects= models.CharField(max_length=256, verbose_name='Project Name')
    assigned_time= models.IntegerField(verbose_name='Assigned Hours/days', choices=STATUS, default=DAYS)
    time_spent=models.IntegerField(verbose_name='Spent Hours/Days', choices=STATUS, default=DAYS)
    description=models.TextField(max_length=1000, verbose_name='Description')

    def __str__(self):
        return f'{self.employee.user.first_name} {self.employee.user.last_name} {self.project}' 

Check for assigned_time or time_spent field. I want to do the same thing on both as I explained above.

Here is my admin.py

@admin.register(Timesheet)
class TimesheetAdmin(admin.ModelAdmin):
    list_display=('first_name', 'last_name', 'date', 'assigned_time', 'projects', 'time_spent', 'description', 'designation_name')

    def first_name(self, obj):
        return obj.employee.user.first_name

    def last_name(self, obj):
        return obj.employee.user.last_name

    def designation_name(self, obj):
        return obj.designation.designation_name

Here is the image of what I am getting

enter image description here

What should I do to add both things in a single field?

1 Answer 1

1

I think you should create another field for type of time. You cannot have both in the same field. Even if it would be not readable for some reasons. I suggest such solution:

Add another field of type and use CHOICES there:

class Timesheet(models.Model):
    STATUS = [
        ('D', 'Days'),
        ('H', 'Hours')
    ]

    ...
    time_type = models.CharField(verbose_name='Type of time', choices=STATUS, default=STATUS[0], max_length=10)
    assigned_time = models.IntegerField(verbose_name='Assigned time', default=0)
    time_spent = models.IntegerField(verbose_name='Spent time', default=0)
    ...

I also corrected your attempt for choices. It was not working, cause IntegerField cannot accept string values.

UPDATE: If you really need have it in one field, you can use IntegerField choices like that:

STATUS = [
    (1, '1 Hour'),
    (2, '2 Hours'),
    (3, '3 Hours'),
    ...
    (1, '1 Day'),
    (2, '2 Days'),
    (3, '3 Days'),
    ...
]

# or comprehensions will give us same result with less code

STATUS = [
(i, f'{i} Days') for i in range(1, 31)
]

[STATUS.append((i, f'{i} Hours')) for i in range(1, 25)]

But remember, that first value of the tuple has to fit Field type.

Sign up to request clarification or add additional context in comments.

3 Comments

Comprehension is giving me this error ERRORS: core.Timesheet.assigned_time: (fields.E005) 'choices' must be an iterable containing (actual value, human readable name) tuples. core.Timesheet.time_spent: (fields.E005) 'choices' must be an iterable containing (actual value, human readable name) tuples. I think its because of what you said in the last the first value of the tuple has to fit field type What does it mean?
Sorry, missed one closing bracket inside the second one. It actually might not need double brackets in append method. But for now I leave that.
First value of tuple is the value that actually goes to database. It means it has to be the same type as the Field is expecting. So for IntegerField first value in tuple has to be Integer. Second value is for human readable reasons.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.