DateTimeField doesn't show in admin system - python

How come my "date" field doesn't come up in the admin system?
In my admin.py file i have
from django.contrib import admin
from glasses.players.models import *
admin.site.register(Rating)
and the Rating model has a field called "date" which looks like this
date = models.DateTimeField(editable=True, auto_now_add=True)
However within the admin system, the field doesn't show, even though editable is set to True.
Does anyone have any idea?

If you really want to see date in the admin panel, you can add readonly_fields in admin.py:
class RatingAdmin(admin.ModelAdmin):
readonly_fields = ('date',)
admin.site.register(Rating,RatingAdmin)
Any field you specify will be added last after the editable fields. To control the order you can use the fields options.
Additional information is available from the Django docs.

I believe to reason lies with the auto_now_add field.
From this answer:
Any field with the auto_now attribute
set will also inherit editable=False
and therefore will not show up in the
admin panel.
Also mentioned in the docs:
As currently implemented, setting
auto_now or auto_now_add to True will
cause the field to have editable=False
and blank=True set.
This does make sense, since there is no reason to have the field editable if it's going to be overwritten with the current datetime when the object is saved.

Major Hack:
If you really need to do this (as I do) you can always hack around it by immediatley setting the field to be "editable" defining the field as follows:
class Point(models.Model):
mystamp=models.DateTimeField("When Created",auto_now_add=True)
mystamp.editable=True
This will make the field editable, so you can actually alter it. It seems to work fine, at least with the mysql backing engine. I cannot say for certian if other backing stores would make this data immutable in the database and thus cause a problem when editing is attempted, so use with caution.

Depending on your specific needs, and any nuances in difference in behavior, you could do the following:
from django.utils.timezone import now
class MyModel(models.Model):
date = models.DateTimeField(default=now)
The default field can be used this way: https://docs.djangoproject.com/en/dev/ref/models/fields/#default
The default value for the field. This can be a value or a callable object. If callable it will be called every time a new object is created.
This does not set editable to False

It might have to do with the auto_now_add being true. Perhaps instead of that parameter to capture the date on add, you could override the model save method to insert the datetime when the id is null.
class Rating(models.Model):
....
def save(self, *args, **kwargs)
if not self.id:
self.date = datetime.datetime.now()

If you want any field to be visible in the list of all your entries (when you click on a model in the admin people) and not when you open that particular entry then -
class RatingAdmin(admin.ModelAdmin):
list_display = ('name', 'date')
admin.site.register(Rating, RatingAdmin)
'name' being your main field or any other field you want to display in the admin panel.
This way you can specify all the columns you want to see.

Can be displayed in Django admin simply by below code in admin.py
#admin.register(model_name)
class model_nameAdmin(admin.ModelAdmin):
list_display = ['date']
Above code will display all fields in django admin that are mentioned in list_display, no matter the model field is set to True for auto_now attribute

You can not do that, check the documentation
auto_now and auto_now_add are all non-editable fields and you can not override them...

I wanted to create an editable time field that defaults to the current time.
I actually found that the best option was to avoid the auto_now or auto_add_now altogether and simply use the datetime library.
MyTimeField = models.TimeField(default=datetime.now)
The big thing is that you should make it's the variable now instead of a function/getter, otherwise you're going to get a new default value each time you call makemigrations, which will result in generating a bunch of redundant migrations.

This is a combination of the answers by Hunger and using a decorator as suggested by Rahul Kumar:
In your admin.py, you just need:
#admin.register(Rating)
class RatingAdmin(admin.ModelAdmin):
readonly_fields = ('date',)
The fields specified in readonly_fields will appear in the add and change page i.e. inside the individual record. And - of course - are not editable.
The fields in list_display will constitute the representation in the main list page of the admin (i.e. the list of all records). In this case, it makes sense not to specify list_display = ('date',) only, because you will see only the dates. Instead, include also the main title / name of the record.
Example:
readonly_fields = ('title', 'date',)
if in the models.py this model is defined as:
class Rating(models.Model):
title = models.CharField('Movie Title', max_length=150)
...
date = models.DateTimeField(editable=True, auto_now_add=True)
def __str__(self):
return self.title

Related

Using Django ModelForm with non-persistent model.Field

Is there a way to add a field to a Django model class such that:
It doesn't get persisted to the database (i.e. no column in the DB)
It does get rendered by a ModelForm
The widget for that field can be customised
I believe 3. can be done with a custom widget, and 2. will happen if the field inherits from models.Field. However, I haven't found a way to achieve 1. without breaking 2. and 3. I was hoping for a persist=False or db_column=None type of solution.
Scenario:
I'm using this to quickly produce data capture forms by only adding a class to the model, but in order to insert headers for sub sections I still having to edit the template. Was hoping to do the following:
models.py
from django.db import models
class Applicant(models.Model):
sectionA = models.SectionField(help_text="Personal details")
title = models.CharField(max_length=100)
name = models.CharField(max_length=100)
sectionB = models.SectionField(help_text="Banking details")
account = models.CharField(max_length=100)
pin = models.CharField(max_length=100)
In the above example, sectionA and sectionB are instances of a custom model.Field that doesn't actually get persisted but cause a heading to be rendered by the ModelForm and a custom widget
Finally:
I realise this probably violates separation of View and Model.
Other questions have been asked about non-persisting fields but their solutions don't render in a ModelForm
Sort of, Just don't make them a model field, theres no need for them to be.
sectionA = "Personal details"
sectionB = "Banking details"
You can access them via form.instance where you need them, you could even make them a form field instead of a string as I've shown here.

Django changes pub_date when I do .save()

I have a model Question with an IntegerField named flags and a datetime Field called pub_date. pub_date is set to be auto_now=True.
I have a view for changing the flags field. And when I change the flags and do .save() to the Question object, its pub date changes to now.
I wan't the pub_date to be set only when it's being created and not when I'm changing some data in the record. How can I do this?
If you need to see my code, please tell me because I don't think you need to here.
you should set auto_now_add = True
You can just remove auto_now=True and set the field manually when you want to, in your view.

In the Django admin site, how do I change the display format of time fields?

I recently added a new model to my site, and I'm using an admin.py file to specify exactly how I want it to appear in the admin site. It works great, but I can't figure out how to get one of my date fields to include seconds in it's display format. I'm only seeing values like "Aug. 27, 2011, 12:12 p.m." when what I want to be seeing is "Aug. 27, 2011, 12:12*:37* p.m."
Try this in the ModelAdmin:
def time_seconds(self, obj):
return obj.timefield.strftime("%d %b %Y %H:%M:%S")
time_seconds.admin_order_field = 'timefield'
time_seconds.short_description = 'Precise Time'
list_display = ('id', 'time_seconds', )
Replacing "timefield" with the appropriate field in your model, of course, and adding any other needed fields in "list_display".
digging around I ended here but applied a different approach to my app.
Changing django admin default formats could be done changing the django locale formats for every type you want.
Put the following on your admin.py file (or settings.py) to change datetime default format at your django admin.
from django.conf.locale.es import formats as es_formats
es_formats.DATETIME_FORMAT = "d M Y H:i:s"
It will change the ModelAdmin's datetime formats on that file (or whole site if in settings).
It does not breaks admin datetime filters and order features as #Alan Illing has point out in comments .
hope this help in future
Extra info:
You can change it for every available locale in django, which are a lot.
You can change the following formats using this approach
from django.conf.locale.es import formats as es_formats
es_formats.DATETIME_FORMAT
es_formats.NUMBER_GROUPING
es_formats.DATETIME_INPUT_FORMATS
es_formats.SHORT_DATETIME_FORMAT
es_formats.DATE_FORMAT
es_formats.SHORT_DATE_FORMAT
es_formats.DATE_INPUT_FORMATS
es_formats.THOUSAND_SEPARATOR
es_formats.DECIMAL_SEPARATOR
es_formats.TIME_FORMAT
es_formats.FIRST_DAY_OF_WEEK
es_formats.YEAR_MONTH_FORMAT
es_formats.MONTH_DAY_FORMAT
If you've tried gabriel's answer but it did not work, try to set USE_L10N = False in settings.py, it works for me.
Note that if USE_L10N is set to True, then the locale-dictated format has higher precedence and will be applied instead
See: https://docs.djangoproject.com/en/2.0/ref/settings/#std:setting-DATETIME_FORMAT
The accepted answer is correct, however I found it a bit confusing to understand how/why it works. Below is a small example that I hope illustrates how to do this more clearly.
Django provides a few ways to display "custom" fields in your admin view. The way I prefer to achieve this behavior is to define a custom field in the ModelAdmin class and display that instead of your intended field:
from django.contrib import admin
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=50)
birthday = models.DateField()
class PersonAdmin(admin.ModelAdmin):
#admin.display(description='Birthday')
def admin_birthday(self, obj):
return obj.birthday.strftime('%Y-%m-%d')
list_display = ('name', 'admin_birthday')
Notice that instead of displaying the actual birthday field from the Person model, we define a custom field (admin_birthday) as a method in the PersonAdmin and display that instead by adding it to the list_display attribute. Furthermore, the admin.display() decorator modifies how Django will display this custom field in the admin view. Using this approach, the admin panel will show the NAME and BIRTHDAY fields but using your preferred date formatting for the date.
The reason I prefer this approach is you keep the Model field definitions separate from how you display them in the admin panel. You can read more about alternative approaches in the Django admin documentation.

Django: add model fields to list_display and display related values per entry

I have the following model definitions, see below.
models.py:
class Userstatus(models.Model):
label = models.CharField(...)
description = models.CharField(...)
class Foo(models.Model):
title = models.CharField(...)
visibility = models.ManyToManyField(Userstatus)
admin.py:
class FooAdmin(ModelAdmin):
list_display = ('id', 'title', )
admin.site.register(Foo, FooAdmin)
In the admin list view of "Foo" via FooAdmin the list_display list should include the "label"s from Userstatus so a column for each label will appear. I could create and call a method that creates the list for list_display.
But then no properties or callables actually exist that would allow me to return let's say a boolean for each label column, based on the visibility-many-to-many field.
What are my options? Should I try to intercept a callable or attribute request to Foo and create a boolean result on the fly? (Hitting the DB too often or making the columns sortable is another problem, but first things first).
Django documentation says ...
ManyToManyField fields aren't supported, because that would entail
executing a separate SQL statement for each row in the table. If you
want to do this nonetheless, give your model a custom method, and add
that method's name to list_display. (See below for more on custom
methods in list_display.)
Are you sure you want Userstatus to be a database table and not just a list of a few statuses that could be accessed through a "choices" tuple?

Is there a way to define which fields in the model are editable in the admin app?

Assume the following:
models.py
class Entry(models.Model):
title = models.CharField(max_length=50)
slug = models.CharField(max_length=50, unique=True)
body = models.CharField(max_length=200)
admin.py
class EntryAdmin(admin.ModelAdmin):
prepopulated_fields = {'slug':('title',)}
I want the slug to be pre-populated by the title, but I dont want the user to be able to edit it from the admin. I assumed that adding the fields=[] to the admin object and not including the slug would have worked, but it didnt. I also tried setting editable=False in the model, but that also didnt work (infact, stops the page from rendering).
Thoughts?
For this particular case you can override your save method to slugify (it's built-in method, look at django source) the title and store it in slug field. Also from there you can easily check if this slug is indeed unique and change it somehow if it's not.
Consider this example:
def save(self):
from django.template.defaultfilters import slugify
if not self.slug:
self.slug = slugify(self.title)
super(Your_Model_Name,self).save()
I'm not sure what you're asking for IS possible. Your best bet is probably to hide the slug from the admin interface completely by specifying your fieldsets, and than overriding the save method to copy the slug from the tile, and potentially slugifying it...
This Django Snippet does what you want by defining a custom Read-Only Widget. So you define a custom editor for the field which in fact doesn't allow any editing.
This snippet gives you an AutoSlugField with exactly the behavior you are seeking, and adding it to your model is a one-liner.
In addition to overriding save to provide the generated value you want, you can also use the exclude option in your ModelAdmin class to prevent the field from being displayed in the admin:
class EntryAdmin(admin.ModelAdmin):
exclude = ('slug',)

Categories

Resources