注释Django中的相关和多过滤对象

时间:2022-01-18 15:46:06

I have a queryset of profiles:

我有一组查询档案:

Model:

模型:

class Profile(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, unique=True)
    ...

View:

观点:

Profile.objects.select_related('user')

Profile.objects.select_related(“用户”)

Each user/profile can register for multiple events per day:

每个用户/个人资料每天可以注册多个事件:

Models:

模型:

class Event(models.Model):

    title = models.CharField(max_length=120)
    date = models.DateField(default=default_event_date)
    ...


class Registration(models.Model):

    event = models.ForeignKey(Event)
    student = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    block = models.ForeignKey(Block, on_delete=models.CASCADE)
    ....

Given a Date how can I annotate (?I think that's what I want?) one Registration object per block (filtered on the user/profile and the Event__Date)

给定一个日期,我如何注释(?)我想这就是我想要的)每个块一个注册对象(过滤用户/配置文件和Event__Date)

In the end, what I'm trying to output in my template is something like this:

最后,我想在模板中输出的是这样的:

For Date: 19 Dec 2016

User/Profile    Block A      Block B   ...
user1           None         None
user2           Event1       Event2
user3           Event3       None
...

EDIT

编辑

Attempt 1. Here's my first attempt to accomplish this. I suspect this is horribly inefficient and would be extremely slow in production, but at least it works. If anyone can provide a more efficient and elegant solution, it would be appreciated! (Note that this also includes a filter on the User's Profile model for homeroom_teacher that was not included in the original question, but I've left here because this is the code that's working)

尝试1。这是我的第一次尝试。我怀疑这是非常低效的,在生产过程中会非常缓慢,但至少它是有效的。如果有谁能提供一个更高效、更优雅的解决方案,我将不胜感激!(注意,这也包含了一个过滤器,在用户的概要文件模型中,没有包含在最初的问题中,但我在这里留下了,因为这是工作的代码)

Registration model manager

注册模型管理员

class RegistrationManager(models.Manager):

类RegistrationManager(models.Manager):

def homeroom_registration_check(self, event_date, homeroom_teacher):
    students = User.objects.all().filter(is_staff=False, profile__homeroom_teacher=homeroom_teacher)
    students = students.values('id', 'username', 'first_name', 'last_name')
    # convert to list of dicts so I can add 'annotate' dict elements
    students = list(students) 

    # get queryset with events? optimization for less hits on db
    registrations_qs = self.get_queryset().filter(event__date=event_date, student__profile__homeroom_teacher=homeroom_teacher)

    # append each students' dict with registration data
    for student in students:
        user_regs_qs = registrations_qs.filter(student_id=student['id'])

        for block in Block.objects.all():
            # add a new key:value for each block
            try:
                reg = user_regs_qs.get(block=block)
                student[block.constant_string()] = str(reg.event)
            except ObjectDoesNotExist:
                student[block.constant_string()] = None

    return students

Template Note that block.constant_string() --> "ABLOCK", "BBLOCK", etc, this is hardcoded in the block.constant_string() method and I'm not sure how to get around this either.

注意block.constant_string()——>“ABLOCK”、“BBLOCK”等等,这在block.constant_string()方法中是硬编码的,我也不知道如何解决这个问题。

{% for student in students %}
  <tr >
    <td>{{ student.username }}</td>
    <td>{{ student.first_name }}</td>
    <td>{{ student.last_name }}</td>
    <td>{{ student.ABLOCK|default_if_none:'-' }}</td>
    <td>{{ student.BBLOCK|default_if_none:'-' }}</td>
  </tr>
{% endfor %}

2 个解决方案

#1


1  

To solve the problem of the harcoded names, I'd slightly modify your solution to look like this:

为了解决硬编码名称的问题,我稍微修改一下您的解决方案,如下所示:

def homeroom_registration_check(event_date, homeroom_teacher):
    students = User.objects.filter(
        is_staff=False,
        profile__homeroom_teacher=homeroom_teacher,
    )
    block_ids = Block.objects.values('id')
    for student in students:
        table_row = []
        for block_id in block_ids:
            try:
                reg = Registration.objects.get(
                    student=student,
                    block=block_id,
                    event__date=event_date,
                )
                table_row.append(reg.event)
            except ObjectDoesNotExist:
                table_row.append(None)
        yield (student, table_row)

I'd take it out from the model manager and put it in views.py or a separate file (like table.py). Seems cleaner to me, but that's just an opinion - you could put this code in the model manager and it would run anyway.

我将从模型管理器中取出它并将其放入视图中。py或单独的文件(如表.py)。对我来说似乎更简洁,但这只是一种观点——您可以将此代码放到模型管理器中,它将会运行。

Then in your template:

然后在你的模板:

{% for student, row in homeroom_reg_check %}
    <tr>
        <td>{{ student.username }}</td>
        <td>{{ student.other_data }}</td>
        {% for event in row %}
            <td>{{ event.name|default_if_none:'-' }}</td>
        {% endfor %}
    </tr>
{% endfor %}

#2


0  

Probably you don't need to use annotate but can use regroup tag inside template.

您可能不需要使用annotate,但是可以在模板中使用regroup标记。

Going from the end. All the information which you want to display on the page can be retrieved from Registration model.

从结束。您希望在页面上显示的所有信息都可以从注册模型中检索。

Get all the registrations filtered by date of the event:

按事件日期过滤所有登记事项:

registrations = Registration.objects.filter(event__date = date)

Afterwards you have to regroup by user in template.

之后,您必须在模板中按用户重新分组。

However I see following problems:

然而,我看到以下问题:

  1. I am not sure that regroup tag is working correctly with querysets. So probably you have to convert data into list. However, I have found this answer in which querysets are used.
  2. 我不确定regroup标记是否正确地使用了querysets。所以你可能需要把数据转换成列表。但是,我找到了使用querysets的答案。
  3. Even if you will regroup you need some logic in template to define the block for the event.
  4. 即使您需要重新组合,也需要在模板中使用一些逻辑来定义事件的块。

#1


1  

To solve the problem of the harcoded names, I'd slightly modify your solution to look like this:

为了解决硬编码名称的问题,我稍微修改一下您的解决方案,如下所示:

def homeroom_registration_check(event_date, homeroom_teacher):
    students = User.objects.filter(
        is_staff=False,
        profile__homeroom_teacher=homeroom_teacher,
    )
    block_ids = Block.objects.values('id')
    for student in students:
        table_row = []
        for block_id in block_ids:
            try:
                reg = Registration.objects.get(
                    student=student,
                    block=block_id,
                    event__date=event_date,
                )
                table_row.append(reg.event)
            except ObjectDoesNotExist:
                table_row.append(None)
        yield (student, table_row)

I'd take it out from the model manager and put it in views.py or a separate file (like table.py). Seems cleaner to me, but that's just an opinion - you could put this code in the model manager and it would run anyway.

我将从模型管理器中取出它并将其放入视图中。py或单独的文件(如表.py)。对我来说似乎更简洁,但这只是一种观点——您可以将此代码放到模型管理器中,它将会运行。

Then in your template:

然后在你的模板:

{% for student, row in homeroom_reg_check %}
    <tr>
        <td>{{ student.username }}</td>
        <td>{{ student.other_data }}</td>
        {% for event in row %}
            <td>{{ event.name|default_if_none:'-' }}</td>
        {% endfor %}
    </tr>
{% endfor %}

#2


0  

Probably you don't need to use annotate but can use regroup tag inside template.

您可能不需要使用annotate,但是可以在模板中使用regroup标记。

Going from the end. All the information which you want to display on the page can be retrieved from Registration model.

从结束。您希望在页面上显示的所有信息都可以从注册模型中检索。

Get all the registrations filtered by date of the event:

按事件日期过滤所有登记事项:

registrations = Registration.objects.filter(event__date = date)

Afterwards you have to regroup by user in template.

之后,您必须在模板中按用户重新分组。

However I see following problems:

然而,我看到以下问题:

  1. I am not sure that regroup tag is working correctly with querysets. So probably you have to convert data into list. However, I have found this answer in which querysets are used.
  2. 我不确定regroup标记是否正确地使用了querysets。所以你可能需要把数据转换成列表。但是,我找到了使用querysets的答案。
  3. Even if you will regroup you need some logic in template to define the block for the event.
  4. 即使您需要重新组合,也需要在模板中使用一些逻辑来定义事件的块。