Model name visible in Admin section - python

I am using Python 3.10.0 and Django 3.2.9
I created a new app in my django project, and then created a model called Posts. Everything works as intended except for how it's name is being displayed in the admin section of the website. It says "Postss" (double s in the end).
If I change the model name to "Post" or just one letter "P" for instance, django automatically adds "s" to the end of it's name, so it is being displayed as "Posts" or "Ps" then.
Other words, whatever the model name is, django automatically adds "s" in the end of it's name in the admin pannel of the website.
Is it possible to tell django I don't want that "s" to be added? How?
Thanks a mil, guys.

Normally models have singular names, so Post, not Posts. You thus might want to consider renaming your model.
If you still want to use Posts as model name, you can specify the verbose name of the model, and the plural verbose name with the verbose_name [Django-doc] and the verbose_name_plural model options [Django-doc] respectively:
class Posts(models.Model):
# …
class Meta:
verbose_name = 'post'
verbose_name_plural = 'posts'
But as said before, if you rename your model Post, Django will convert the PerlCase to a name with spaces and as plural append the name with an s.

Related

Django model string representation [duplicate]

Django's internationalization is very nice (gettext based, LocaleMiddleware), but what is the proper way to translate the model name and the attributes for admin pages? I did not find anything about this in the documentation:
http://docs.djangoproject.com/en/dev/topics/i18n/internationalization/
http://www.djangobook.com/en/2.0/chapter19/
I would like to have "Выберите заказ для изменения" instead of "Выберите order для изменения". Note, the 'order' is not translated.
First, I defined a model, activated USE_I18N = True in settings.py, run django-admin makemessages -l ru. No entries are created by default for model names and attributes.
Grepping in the Django source code I found:
$ ack "Select %s to change"
contrib/admin/views/main.py
70: self.title = (self.is_popup and ugettext('Select %s') % force_unicode(self.opts.verbose_name) or ugettext('Select %s to change') % force_unicode(self.opts.verbose_name))
So the verbose_name meta property seems to play some role here. Tried to use it:
class Order(models.Model):
subject = models.CharField(max_length=150)
description = models.TextField()
class Meta:
verbose_name = _('order')
Now the updated po file contains msgid 'order' that can be translated. So I put the translation in. Unfortunately running the admin pages show the same mix of "Выберите order для изменения".
I'm currently using Django 1.1.1.
Could somebody point me to the relevant documentation? Because google can not. ;-) In the mean time I'll dig deeper into the django source code...
Important things not mentioned in the Django documentation:
run django-admin compilemessages, e.g. as a part of your build
process. Thanks stevejalim!
apply django's ugettext_lazy() to model names ( Meta class and verbose_name )
attribute (model field verbose_name) names can also be translated with ugettext_lazy()
use lazy translation in your model metadata, otherwise the translation
happens while loading the model classes and the settings of your users,
especially the browser settings, will not be taken into account
I use some scoping for attribute names, e.g. separating the model name
and attribute names with a pipe. The same convention is used in
ruby-gettext. Background: attribute names like 'title' or 'name' translated
differently in the most languages depending on context. Example
'Book|title' -> 'Titel' or 'Buchtitel' in German. But
'Chapter|title' would be translated as 'Überschrift'.
Example using above principles:
from django.utils.translation import ugettext_lazy as _
class Order(models.Model):
subject = models.CharField(max_length=150, verbose_name = _('Order|subject'))
description = models.TextField( verbose_name = _('Order|description'))
class Meta:
verbose_name = _('order')
verbose_name_plural = _('orders')
Or is there a better way to translate the model and admin pages?
Either way we should enhance the Django documentation and fill the gap!
See https://automationpanda.com/2018/04/21/django-admin-translations/
It's author made an excellent work in showing how to master all django translation features step by step. It's much better than oficial documentation to me.
I use both ugettext with _ and ugettext_lazy with a double __. Consequently, the makemessages management command was only collecting the first ones.
To collect both _ and __ we can ask the gettext tool to collect more than the default strings enclosed in _( ). To do this, we override the makemessages command: https://docs.djangoproject.com/en/dev/topics/i18n/translation/#customizing-the-makemessages-command
# myapp/management/commands/makemessages.py
from django.core.management.commands import makemessages
class Command(makemessages.Command):
self.stdout.write("----> Using our custom makemessages command to collect both _ and double __")
xgettext_options = makemessages.Command.xgettext_options + ['--keyword=__'] # <-- added __
My models in Admin are now finally fully translated.

Custom Django Adminsite Doesn't show link to read_only ForeignKey field

In the default Django Admin Site, if a model is registered with ForegingKey fields and those are included in readonly_fields (using the model property or the get_readonly_fields method) the value of the field is rendered with a link to the Change View, but this Doesn't work on a custom Django Admin Site.
E.g.: I have this two models:
class ModelA(models.Model):
field_a = models.CharField(max_length=50)
class ModelB(models.Model):
model_a = models.ForeignKey(ModelA, on_delete=models.PROTECT)
I registered in the default Django Admin Site:
admin.register(ModelA)
#register(ModelB)
class ModelBAdmin(admin.ModelAdmin):
model = ModelB
readonly_fields = ["model_a"]
So I get in the Change View of ModelB in the Admin the value of the field (str of the model) with a link to the Change View of the related model:
Link pointing to Chang View
But if I register the models in a Custom Admin Site, the link is not generated.
How can I extends my Custom Admin Site in order to generate those links?
PD1: I know I can code custom methods to build the links, but this is not a DRY way of do it and doesn't work well with get_readonly_fields method
PD2: If I register the related model (ModelA in the example) in the default Admin Site the link is genereted, but point to the default Admin Site, brokening the purpose of the Custom Admin Site.
I posted the same question in the official Django forum:
forum.djangoproject.com/t/9472/5
It has generated a ticket because is a missing line in the method get_admin_url in the helper class AdminReadOnlyField, The temporal solution is in the ticket: code.djangoproject.com/ticket/33077
PD: Why someone marks this post like a bad question? It has generates a ticket for a patch so it was a fair problem, this is my first question in StackOverflow and this is discouraging.

Django - Access changed InlineAdmin fields within parent Admin's save_model()

Apologize if this question has already been addressed before. Since I was not able to find a proper solution for this, had to ask.
I need to perform an action(an API call telling my clients to update models from their end) when there is a change in a model's Inline Admin fields from within the save_model() of the parent admin.
models.py
class Student(models.Model)
name = CharField()
age = DateField()
class Marks(models.Model)
student = ForeignKey(Student)
subject = CharField()
marks = IntegerField()
admin.py
class MarksInline(admin.TabularInline):
model = Marks
form = MarksForm
formset = MarksInlineFormSet
class StudentAdmin(admin.ModelAdmin):
form = StudentForm
inlines = [MarksInline, ]
I am able to achieve this by checking the form.changed_data from within the StudentAdmin save_model() and for the MarksInline models MarksInlineFormSet clean() method. The issue is my action will be called separately from each of these methods resulting in two calls, even though all I need is a single call to update the Student and Marks model in the clients end.
My problem would be solved if the save_model() of StudentAdmin could return the fields that has been changed via form.changed_data in MarksInline as well.
Tried to use post_save signals as well by implementing Field Tracker. But this too sent out separate post_save signal calls to the receiver function.
Does anyone know a work around using which I can figure out the changed fields of the InlineAdmin fields from within the parent Admins save_model() method.

I have a django model but i only want to put some of my models as forms.

For example, lets say this is my model:
class Author(models.Model):
author = models.CharField()
friends = models.CharField()
and I only want to have the friends as a form field
Are you using a ModelForm? If so, you set the fields you want using the fields variable in the Meta class:
from django import forms
from yourapp.models import Author
class AuthorForm(forms.ModelForm):
class Meta:
model = Author
fields = [ "friends", ]
Note: The fields variable is a list, so make sure you include the trailing comma if you're only passing a single field.
Suggest that you have a read of the Django ModelForm Docs as well, as that way you'll get a bit ahead on all the other questions you're probably about to come up with :)

Delete m2m through field from admin panel

I searched and could not find a way to do this. Here's my situation:
I have 3 classes:
Publication
Person
AuthorOrder
The last is a through class that allows me to specify the author order for a publication, as this does not normally seem possible to do.
Initially, I made Author a mandatory field (blank=False) for Publication and added a placeholder Person object to add Publications to that don't have a proper author. However, a better solution seems to be to just handle missing authors in Views appropriately. Now, I've changed the field to be optional, but I cannot seem to set the authors to empty via the admin panel. It gives me a "This field is required." error. My guess is that this is because the Person is required of the through class, but setting the Person to null/empty in the admin panel does not set the through object to null/empty.
I found a workaround. One can delete the placeholder Person object. This unsets the through class from the Publications without deleting them via cascade as they are no longer mandatory. However, this is not always a good workaround, so I hope there's a better method.
models.py
There is a lot of code, I reproduce only the minimal necessary:
#Publication
class Publication(models.Model):
authors = models.ManyToManyField(Person, blank=True, related_name="author_of", through='AuthorOrder')
#Person
class Person(models.Model):
# mandatory
firstname = models.CharField(max_length=200)
# AuthorOrder
class AuthorOrder(models.Model):
publication = models.ForeignKey(Publication)
author = models.ForeignKey(Person)
admin.py
# AuthorInline
class AuthorInline(admin.StackedInline):
model = AuthorOrder
extra = 3
# Publication
class PublicationAdmin(admin.ModelAdmin):
list_display = ("title", 'issue', "keywords")
search_fields = ['title', "keywords"]
list_filter = ['issue']
# author list via Inline
inlines = [AuthorInline]
admin.site.register(Publication, PublicationAdmin)
It's simple. To the very right of the "Author order: AuthorOrder object" line, there is a small "Delete" box. Check it and save. It's small and somewhat oddly placed, so easily gets missed.

Categories