Problems after Version update

Hi folks,

I’ve been not around here for a while. My project is resting sincoe October 2023. It was considered completed so far. Now I made the “mistake” to run an update with all outdated modules in requirements.txt including the Django Version itself.

Before that, everything was working as intended, since the update i get this error message when trying to start the testserver in PyCharm:

ERRORS:
<class ‘employees.admin.KeysAdmin’>: (admin.E013) The value of ‘filter_horizontal[0]’ cannot include the ManyToManyField ‘room’, because that field manually specifies a relationship model.

The error refers to this code fragment:

@admin.register(Keys)
class KeysAdmin(admin.ModelAdmin):

    list_display = ['key']
    list_display_links = ['key']
    search_fields = ['key']
    ordering = ['key']
    filter_horizontal = ['room']

and this is corresponding to these models:

class Rooms(models.Model):

    room = models.CharField(max_length=25, unique=True)
    cylinder = models.CharField(max_length=25, null=True, blank=True)
    description = models.CharField(max_length=100, null=True, blank=True)
    restricted_access = models.BooleanField(default='0')

    def __str__(self):
        return self.room

    class Meta:
        verbose_name = 'Raum'
        verbose_name_plural = 'Räume'
        ordering = ['room']


class Keys(models.Model):

    key = models.CharField(max_length=25, unique=True)
    comment = models.CharField(max_length=100, null=True, blank=True)
    room = models.ManyToManyField(Rooms, through='LockingAuthorisations')

    def __str__(self):
        return self.key

    class Meta:
        verbose_name = 'Schlüssel'
        verbose_name_plural = 'Schlüssel'
        ordering = ['key']


class LockingAuthorisations(models.Model):

    key = models.ForeignKey(Keys, null=True, blank=True, on_delete=models.CASCADE)
    room = models.ForeignKey(Rooms, null=True, blank=True, on_delete=models.CASCADE)

    class Meta:
        verbose_name = 'Schliessberechtigung'
        verbose_name_plural = 'Schliessberechtigungen'
        ordering = ['key']

Due to several other tasks I have to complete at the moment, I didn’t had time to read any changelogs concerning the updated modules. Will do so as soon as I can manage it but maybe someone around here has a simple hint, what changes have to be made to get it working again? The installed DjangoVersion is now 5.0.1.

Thx for any efforts to help me out :slight_smile:

See the docs at Working with many-to-many intermediary models,
along with:

Hi again Ken,

thx for hint. It seems, that filter_horizontal was never meant to be used this way but was not throwing an error until Django Version 5…

If I out-comment the last line here:

class KeysAdmin(admin.ModelAdmin):

    list_display = ['key']
    list_display_links = ['key']
    search_fields = ['key']
    ordering = ['key']
    # filter_horizontal = ['room']

The error is gone and i can start the test-server. However, now i get an error when using a specific function, triggered by this first line of template code:

{% for room in form.room %} <===============
        {% if forloop.counter0|divisibleby:10 %} <div class="row g-2 mb-1"> {%  endif %}
            <div class="col-auto">
                <button type="button"
                        class="btn btn-transparent p-0">
                    {{ room }}
                </button>
            </div>
        {%  if forloop.counter|divisibleby:10 or forloop.last %}</div><!-- row closing -->{%  endif %}
{% endfor %}

It says:

ValueError at /employees/alter.html

Cannot assign “<QuerySet [<Rooms: E027>, <Rooms: E033>, <Rooms: E061>, <Rooms: E075>, <Rooms: E081>, <Rooms: E085>, <Rooms: E095>, <Rooms: E112>, <Rooms: E123>, <Rooms: E159>, <Rooms: E161>, <Rooms: E169>, <Rooms: E171>, <Rooms: E176>, <Rooms: E201>, <Rooms: E317>, <Rooms: E339>, <Rooms: E347>, <Rooms: E362>, <Rooms: E371>, ‘…(remaining elements truncated)…’]>”: “LockingAuthorisations.room” must be a “Rooms” instance.

Request Method: POST
Request URL: http://127.0.0.1:8000/employees/alter.html
Django Version: 5.0.2
Exception Type: ValueError
Exception Value: Cannot assign “<QuerySet [<Rooms: E027>, <Rooms: E033>, <Rooms: E061>, <Rooms: E075>, <Rooms: E081>, <Rooms: E085>, <Rooms: E095>, <Rooms: E112>, <Rooms: E123>, <Rooms: E159>, <Rooms: E161>, <Rooms: E169>, <Rooms: E171>, <Rooms: E176>, <Rooms: E201>, <Rooms: E317>, <Rooms: E339>, <Rooms: E347>, <Rooms: E362>, <Rooms: E371>, ‘…(remaining elements truncated)…’]>”: “LockingAuthorisations.room” must be a “Rooms” instance.
Exception Location: C:\Users\User\PycharmProjects\klixdat\venv\Lib\site-packages\django\db\models\fields\related_descriptors.py, line 284, in set
Raised during: employees.views.alter
Python Executable: C:\Users\User\PycharmProjects\klixdat\venv\Scripts\python.exe
Python Version: 3.11.2

corresponding lines in views.py are:

        elif 'alter_authorisation' in request.POST:
            key_alter = request.POST['alter_authorisation']
            context['key_number'] = Keys.objects.get(id=key_alter)
            context['switch'] = 'alter_authorisation'
            form = ManageAuthorisationsForm({'key': key_alter,
                                             'room': Rooms.objects.filter(keys=key_alter),
                                             })

and the lines in forms.py:

class ManageAuthorisationsForm(ModelForm):

    class Meta:
        model = LockingAuthorisations
        fields = '__all__'

    key = forms.ModelChoiceField(queryset=Keys.objects.all(), widget=forms.HiddenInput)

    room = forms.ModelMultipleChoiceField(queryset=Rooms.objects.all(), label='',
                                          required=False,
                                          widget=forms.CheckboxSelectMultiple(attrs={
                                              'class': "fw-bold",
                                          }))

and the corresponding lines in models.py:

class Rooms(models.Model):

    room = models.CharField(max_length=25, unique=True)
    cylinder = models.CharField(max_length=25, null=True, blank=True)
    description = models.CharField(max_length=100, null=True, blank=True)
    restricted_access = models.BooleanField(default='0')

class Keys(models.Model):

    key = models.CharField(max_length=25, unique=True)
    comment = models.CharField(max_length=100, null=True, blank=True)
    room = models.ManyToManyField(Rooms, through='LockingAuthorisations')

class LockingAuthorisations(models.Model):

    key = models.ForeignKey(Keys, null=True, blank=True, on_delete=models.CASCADE)
    room = models.ForeignKey(Rooms, null=True, blank=True, on_delete=models.CASCADE)

However until Django Version 5 this code was working properly and i don’t get my mistake…
I assume the solution hides somewhere in here but I don’t get it where exactly:
Changlog/Release Notes Django V5.0

The issue here is that you’re trying to assign multiple values to a singular foreign key.

You’re creating a form for LockingAuthorisations which is defined as:

However, the room field on the form is defined as:

which is not proper.

This is not a Django 5.0 issue - this would have never worked.

I know you as a person who usually knows, what he’s talking about. So i can accept your statement on the one side, on the other side, somebody then has to explain to me, that the very given code above works as intended when used with Django < Version 5 :stuck_out_tongue:

Maybe I should explain, what the form is MEANT to do:
It’s about keys, that are saved with their key numbers in database. Each key can be coded to unlock 1…2…many rooms. In this function, the user gets displayed a form, where all rooms are shown as checkboxes with the ones checked, that are already unlockable by the corresponding selected key.

And besides the fact, that this would “never have worked”, the same code delivers the following form without error message, if i use my pythonanywhere.com installation i installed for test purposes on dealing with deployment issues a few months ago - which is running with Django Version lower than 5.0…:

Screenshot 2024-02-07 095132

…and any changes made in the form also are saved flawlessly to database…

But if you say this is not proper, what would be a proper way ?

I could be wrong - it certainly wouldn’t be the first time here. I would need to see the complete project to even attempt to find an explanation. Until then, I remain skeptical.

The issue is that you want to assign multiple rooms on the Keys model and not the LockingAuthorisations model.

Each instance of LockingAuthorizations establish a relationship between one Room and one Key. This allows each Key to have relationships with _multiple Room - each instance of that relationship being defined by a separate instance of LockingAuthorisations.

The model structure does not allow you to create multiple relationships between one LockingAuthorisations and a Room.

Will try to check this this weekend and give feedback…thx for the moment for the explanation :slight_smile:

@KenWhitesell so as intermediate Information:

Had no time this weekend to investigate this more deeply, but after deleting Django Version 5 and manually installing Django 4.2.1 into my project…everything is again working as intended…