1

I was going through "Django for Beginners", there is a project that make posts with title, author and body fields, u can add posts via admin where in author field u choose either -- or the admin itself, what I'd like to do is if this field is not edited then then its value would be a string that i can pass (i. e. in that case 'anon') . I've found a way to make a default for ForeignKey but without models.User so how to do it in that case?

from django.db import models
from django.urls import reverse

def anon():
    return 'User.username="Anon"'    

class Post(models.Model):
    title = models.CharField(max_length=200)
    author = models.ForeignKey(
        "auth.User", 
        on_delete=models.CASCADE, default=anon
    )
    
    body = models.TextField()
    
    def __str__(self):
        return self.title
    
    def get_absolute_url(self):
        return reverse("post_detail", kwargs={"pk": self.pk})

Firstly I've tried to plainly type in author = models.ForeignKey("auth.User", on_delete=models.CASCADE, default='anon').

Then to make a function that would return the desired string, then looked up models.User fields and found username field, tried to return it in anon() but only got SyntaxError: expression cannot contain assignment, perhaps you meant "=="? when entered makemigrations command

KA RL
  • 13
  • 2
  • I'm seeing your question in a peer review. If the provided answer helped you, please consider upvoting it and/or marking it as accepted. – Moritz Ringler Mar 16 '23 at 18:44

1 Answers1

0

You can make a callable that gets or creates the User with username Anon this:

from django.conf import settings
from django.contrib.auth import get_user_model


def anon():
    User = get_user_model()
    usr, __ = User.objects.get_or_create(
        username='Anon', defaults={'password': ''}
    )
    return usr


class Post(models.Model):
    title = models.CharField(max_length=200)
    author = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.CASCADE, default=anon
    )

    body = models.TextField()

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse('post_detail', kwargs={'pk': self.pk})

That being said, it is probably not a good idea to make an extra user: you can work with None/NULL to specify that there is no author. This is more efficient and will not impose any security risks if people for example manage to login with that anonymous user, so:

class Post(models.Model):
    title = models.CharField(max_length=200)
    author = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        null=True,
        default=None,
    )

    body = models.TextField()

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse('post_detail', kwargs={'pk': self.pk})

Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • ok, gotcha ya. Then is it possible when choosing null=True instead of '--' display 'anon'? – KA RL Mar 16 '23 at 16:43
  • @KARL: you can specify this in the `ModelAdmin` https://stackoverflow.com/a/35003020/67579 as well as in (model)forms, and in templates with the [`|default_if_none`](https://docs.djangoproject.com/en/dev/ref/templates/builtins/#default-if-none) template filter. – Willem Van Onsem Mar 16 '23 at 16:54
  • thank u, although even going through ur link and some others I couldn't change the '--' to 'anon' in admin panel, |default_if_none is what i really needed although couldn't formulate it from the 1st time – KA RL Mar 16 '23 at 18:59