Usage of unique_for_date

Viewed 3716

I'm trying to use unique_for_date option to prevent creating multiple posts with the same slug for the same date. But it doesn't seem to work at all: I still can create posts with the same slug from the shell and admin dashboard. The same goes for ModelForm. My models.py:

class Post(models.Model):

    STATUS_CHOICES = (
        ('draft', 'Draft'),
        ('published', 'Published'),
        ('suspended', 'Suspended'),
    )

    title = models.CharField(max_length=200)
    slug = models.SlugField(max_length=200, unique_for_date='created')
    status = models.CharField(max_length=15,
                              choices=STATUS_CHOICES,
                              default='draft')
    content = models.TextField(max_length=200000, blank=True)
    # dates
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)
    publish = models.DateTimeField(default=timezone.now)

I've found some kind of a workaround for problem by changing auto_now_add=True to default=timezone.now but it only shows error while creating object via django admin - still no errors while creating objects from shell or form.

Update: I know that using auto_now_add sets editable=False causing django to skip field validation, but it doesn't explain why it skips validation even with default=timezone.now

Update 2: For some reason unique_for_date works only for django-admin dashboard forms (in my case at least). To get the same effect for other forms I've overridden the clean_fields method of the model (forces django to validate unique fields):

def clean_fields(self, exclude=None):
    super().clean_fields(exclude=exclude)
    self.validate_unique()
4 Answers

Thanks for posting that question, I ran into exactly the same problem (curiously, on more or less the same code – are we following the same book? :) ). It's been three years and some change that this questions was opened, but were you using WSL for your developments by any chance?

I set unique_for_date as parameter for the slug as well and the admin interface of the local version is behaving as intended, i. e. it doesn't allow two identical slugs on the same date. Interestingly enough, in the version in WSL, it is possible to create several identical slugs for any given date, even though the code is identical to the Windows version.

I've encountered another inexplicable error in the same code in my WSL version (tl;dr: the local version is, again, working as intended): I'm displaying a list of blog posts in abridged form using django's bread-and-butter HTML templates. Clicking on a list entry's title (a canonical url using the urlpattern path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail) described in the Django documentation) should open its unabridged detail view, but, although the list is displayed correctly, the detail view's entry cannot be displayed because the system cannot find the entry and throws a 404 error. I'm passing the 'published' date to construct the canonical url; while the post that contains the slug can be retrieved using 'published__year', neither 'published__month' nor 'published__day' returns anything (the dates are well-formed when I save my test entries). Again, the very same code is working flawlessly in the local version (i. e., outside of WSL). Feel free to pester me about the details if that was too compact.

My observations point to either WSL itself (there are a few memory issues) or to the database I'm running in there. It's rather hard to say, but could it be possible that your problem is caused by similar reasons?

I have two different versions of my code, one on my local file system (Windows) and the other in WSL 2 (Windows Subsystem for Linux, obviously; Debian), and was thus able to compare the behaviour of the two systems: I'm using the same code (transferred through github) and requirements both locally and in WSL with e. g. Django 3.1.6, as well as the same DBMS (MySQL; whether it's MySQL or MariaDB in my WSL/Debian is not 100% clear, but the latter is meant to be a drop-in replacement for the former, so I'd be surprised if this would cause the errors I'm describing here). I'm also using Visual Studio code in both environments.

From official doc: https://docs.djangoproject.com/en/2.2/ref/models/fields/#unique-for-date

If any unique_for_date constraint involves fields that are not part of a ModelForm (for example, if one of the fields is listed in exclude or has editable=False), Model.validate_unique() will skip validation for that particular constraint.

Maybe the problem is on "fields that are not part of a ModelForm will skip validation for that particular constraint".

Related