Monday, July 29, 2019

Using multiple models in for loop on template

I'm trying to create a detail view for the model PROJECT. In the detail view, I want to also include a model TASK and all the related objects in ATTACHMENTS to each task.
I'd like to do something like this -
{for task in task list}
{task}
{for attachments in task}
{attachment}
{end for}
{end for}


Here are snippets of the working files. Thanks in advance for any help!!

Models.py - Project
class Project(NamedModel):
    """An Asana project in a workspace having a collection of tasks."""
    layout_choices = (
        ('board', _('board')),
        ('list', _('list')),
    )

    archived = models.BooleanField(default=False)
    color = models.CharField(choices=COLOR_CHOICES, max_length=16, null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    current_status = models.ForeignKey(
        'ProjectStatus', null=True, on_delete=models.SET_NULL, related_name='current_status')
    custom_field_settings = models.ManyToManyField(
        'CustomField', through='CustomFieldSetting', related_name='custom_field_settings')
    due_date = models.DateField(null=True, blank=True)
    due_on = models.DateField(null=True, blank=True)
    followers = models.ManyToManyField('User', related_name='projects_following', blank=True)
    html_notes = models.TextField(null=True, blank=True)
    layout = models.CharField(choices=layout_choices, max_length=16)
    members = models.ManyToManyField('User', blank=True)
    modified_at = models.DateTimeField(auto_now=True)
    notes = models.TextField(null=True, blank=True)
    owner = models.ForeignKey(
        'User', to_field='remote_id', related_name='projects_owned',
        null=True, on_delete=models.SET_NULL)
    public = models.BooleanField(default=False)
    resource_type = models.CharField(max_length=24, null=True, blank=True, default='project')
    start_on = models.DateField(null=True, blank=True)
    team = models.ForeignKey('Team', to_field='remote_id', null=True, on_delete=models.SET_NULL)
    workspace = models.ForeignKey('Workspace', to_field='remote_id', on_delete=models.CASCADE)

    def asana_url(self, **kwargs):
        """Returns the absolute url for this project at Asana."""
        return '{}{}/list'.format(ASANA_BASE_URL, self.remote_id)


Models.py - Task
class Task(Hearted, NamedModel):
    """An Asana task; something that needs doing."""
    status_choices = (
        ('inbox', _('inbox')),
        ('upcoming', _('upcoming')),
        ('later', _('later')),
    )
    subtype_choices = (
        ('default_task', _('default task')),
        ('section', _('section')),
    )

    assignee = models.ForeignKey(
        'User', to_field='remote_id', related_name='assigned_tasks', null=True, blank=True,
        on_delete=models.SET_NULL)
    assignee_status = models.CharField(choices=status_choices, max_length=16)
    completed = models.BooleanField(default=False)
    completed_at = models.DateTimeField(null=True, blank=True)
    custom_fields = models.TextField(null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    dependencies = models.ManyToManyField('self', symmetrical=False, related_name='dependents')
    due_at = models.DateTimeField(null=True, blank=True)
    due_on = models.DateField(null=True, blank=True)
    followers = models.ManyToManyField('User', related_name='tasks_following')
    html_notes = models.TextField(null=True, blank=True)
    modified_at = models.DateTimeField(auto_now=True)
    notes = models.TextField(null=True, blank=True)
    parent = models.ForeignKey(
        'self', to_field='remote_id', null=True, blank=True, on_delete=models.SET_NULL)
    projects = models.ManyToManyField('Project')
    resource_subtype = models.CharField(
        choices=subtype_choices, max_length=24, default='default_task')
    resource_type = models.CharField(max_length=24, null=True, blank=True, default='task')
    start_on = models.DateField(null=True, blank=True)
    tags = models.ManyToManyField('Tag')

    def _asana_project_url(self, project):
        return '{}{}/{}/list'.format(ASANA_BASE_URL, project.workspace.remote_id, self.remote_id)

    def asana_url(self, **kwargs):
        """Returns the absolute url for this task at Asana."""
        if 'project' in kwargs:
            return self._asana_project_url(kwargs['project'])
        projects = self.projects.all()
        if len(projects) == 1:
            project = projects[0]
            return self._asana_project_url(project)
        return super(Task, self).asana_url()

    def delete_from_asana(self, *args, **kwargs):
        """Deletes this task from Asana and then deletes this model instance."""
        client = client_connect()
        client.tasks.delete(self.remote_id)
        logger.debug('Deleted asana task %s', self.name)
        return self.delete(*args, **kwargs)

    def due(self):
        return self.due_at or self.due_on
    due.admin_order_field = 'due_on'

    def refresh_from_asana(self):
        """Updates this task from Asana."""
        client = client_connect()
        task_dict = client.tasks.find_by_id(self.remote_id)
        if task_dict['assignee']:
            user = User.objects.get_or_create(
                remote_id=task_dict['assignee']['id'],
                defaults={'name': task_dict['assignee']['name']})[0]
            task_dict['assignee'] = user
        task_dict.pop('id')
        task_dict.pop('dependents', None)
        dependencies = task_dict.pop('dependencies', None)
        task_dict.pop('hearts', None)
        task_dict.pop('memberships')
        task_dict.pop('num_hearts', None)
        task_dict.pop('projects')
        task_dict.pop('workspace')
        followers_dict = task_dict.pop('followers')
        tags_dict = task_dict.pop('tags')
        for field, value in task_dict.items():
            setattr(self, field, value)
        self.save()
        follower_ids = [follower['id'] for follower in followers_dict]
        followers = User.objects.filter(id__in=follower_ids)
        self.followers.set(followers)
        for tag_ in tags_dict:
            tag = Tag.objects.get_or_create(
                remote_id=tag_['id'],
                defaults={'name': tag_['name']})[0]
            self.tags.add(tag)
        if dependencies:
            self.dependencies.set([dep['id'] for dep in dependencies])

    def sync_to_asana(self, fields=None):
        """Updates Asana to match values from this task."""
        fields = fields or ['completed']
        data = {}
        for field in fields:
            data[field] = getattr(self, field)
        client = client_connect()
        client.tasks.update(self.remote_id, data)
        logger.debug('Updated asana for task %s', self.name)

    def add_comment(self, text):
        """Adds a comment in Asana for this task."""
        client = client_connect()
        response = client.tasks.add_comment(self.remote_id, {'text': text})
        logger.debug('Added comment for task %s: %s', self.name, text)
        return response

    def get_custom_fields(self):
        """Returns custom_fields as a dict"""
        response = json.loads(self.custom_fields)
        custom_field_values = {}
        for custom_field in response:
            if custom_field['resource_subtype'] == 'enum':
                custom_field_values[custom_field['name']] = custom_field['enum_value']['name']
            elif custom_field['resource_subtype'] == 'number':
                if custom_field.get('precision', 0):
                    custom_field_values[custom_field['name']] = float(custom_field['number_value'])
                else:
                    custom_field_values[custom_field['name']] = int(custom_field['number_value'])
            else:
                custom_field_values[custom_field['name']] = custom_field['text_value']
        return custom_field_values



Models.py - Attachment
class Attachment(NamedModel):
    """A remote file."""
    host_choices = (
        ('asana', 'asana'),
    )
    type_choices = (
        ('image', 'image'),
        ('other', 'other'),
    )
    created_at = models.DateTimeField(auto_now_add=True)
    download_url = models.URLField(max_length=1024)
    host = models.CharField(choices=host_choices, max_length=24)
    parent = models.ForeignKey('Task', to_field='remote_id', on_delete=models.CASCADE)
    permanent_url = models.URLField(max_length=1024)
    resource_type = models.CharField(max_length=24, null=True, blank=True, default='attachment')
    type = models.CharField(choices=type_choices, max_length=24, null=True, blank=True)
    view_url = models.URLField(max_length=1024)

    def asana_url(self, **kwargs):
        return self.permanent_url


Views.py - Project Detail
class ProjectDetail(SingleObjectMixin, ListView):
    queryset = Project.objects.all()
    template_name = 'dash1/project_detail.html'

    def get(self, request, *args, **kwargs):
        self.object = self.get_object(queryset=Project.objects.all())
        return super().get(request, *args, **kwargs)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['Project'] = self.object
        context['task_list'] = Task.objects.filter(projects=8).order_by('-completed_at', 'name')[:5]
        context['attachment_list'] = Attachment.objects.all()[:5]
        return context

Template - 
{% block main %}
<h1>{{ object }}</h1>
{% for object in task_list.all %}
<div class="row">
    <div class="col-xl-4">
        <div class="card-box project-box">
            <div class="dropdown float-right">
                <a href="#" class="dropdown-toggle card-drop arrow-none" data-toggle="dropdown" aria-expanded="false">
                    <h3 class="m-0 text-muted"><i class="mdi mdi-dots-horizontal"></i></h3>
                </a>
                <div class="dropdown-menu dropdown-menu-right" aria-labelledby="btnGroupDrop1">
                    <a class="dropdown-item" href="#">Edit</a>
                    <a class="dropdown-item" href="#">Delete</a>
                    <a class="dropdown-item" href="#">Add Members</a>
                    <a class="dropdown-item" href="#">Add Due Date</a>
                </div>
            </div>
            <p class="text-muted text-uppercase mb-0 font-13">DUE: {{ object.due_on }}</p>
            <h4 class="mt-0 mb-3"><a href="" class="text-dark">{{ object.name }}</a></h4>
            <p class="text-muted font-13">{{ object.notes }}<a href="#" class="font-600 text-muted">view more</a>
            </p>

            <ul class="list-inline">
                {% for object in attachment_list.all %}
                <li class="list-inline-item">
                    <img src="{{ object.permanent_url }}" height="30px">
                </li>
                {% endfor %}
            </ul>

            
            <label class="">Task completed: <span class="text-custom">{{ object.completed_at }}</span></label>
            
            </div><!-- /.progress .no-rounded -->
        </div>
    </div>
</div>
        {% empty %}
            <p class="lead">
                No Tasks Loaded
            </p>
        {% endfor %}


{% endblock %}




--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/9f7d091c-a40e-4c8a-b290-ef77fe6b9482%40googlegroups.com.

No comments:

Post a Comment