django-cms / django-cms

The easy-to-use and developer-friendly enterprise CMS powered by Django
http://www.django-cms.org
BSD 3-Clause "New" or "Revised" License
10.02k stars 3.06k forks source link

[BUG] Model PageUrl should add constraint unique_together #7838

Open jrief opened 3 months ago

jrief commented 3 months ago

Description

Each CMS Page can have one PageUrl object per language. If there are more than that, a MultipleObjectsReturned-exception may be raised.

Steps to reproduce

The PageUrl-object for the home page now has two entries in the database. Reason is this https://github.com/django-cms/django-cms/blob/21d6a6defc5a6321bd691e43eb57c112508b952f/cms/models/pagemodel.py#L292-L296 code snippet. Here new_path is a functional expression containing Concat(ConcatPair(Value('parent_slug'), ConcatPair(Value('/'), F(slug)))). Since the resulting path field of the home page must be an empty string the above query can't work.

Alternative reproduction

Now we get two objects of PageUrl with the same language and the same path entry for different pages. This in my opinion is inconsistent.

I therefore strongly recommend to add unique_together = [['path', 'language'], ['page', 'language']] to the Meta-class of the PageUrl-class.

In my setup I already did this. This is how I found out about the two errors reported before. Otherwise I rarely ran into the problem of hitting a MultipleObjectsReturned-exception, whose real cause then of course is much harder to detect.

Do you want to help fix this issue?

I already patched this locally and would like to know if that proposed model change makes sense.

fsbraun commented 3 months ago

@jrief Great work finding this!!!!

jrief commented 1 month ago

Another note on this:

Slugs currently are not validated against having uppercase letters. This is a problem, because validate_url_uniqueness then validates URLs which only differ in the case.

I would suggest to add an explicit method clean_slug which enforces lowercased slugs.

Shall I create a pull request for this?