How to display a value where there is none in Django admin? - django

Is there a Djangotastic way to display a default value for a field in the admin when there isn't a value? Like 'n/a', but not to save that to the database?
When I set all the fields in the model below to readonly in the admin, the front-end display looks like the image at the bottom. It feels visually collapsed like it should have a value or a box or something. If there isn't an easy way to do what I am looking for, then is there another solution to make the front-end admin more clear for the user?
class Package(models.Model):
packaging_format = models.CharField(max_length=40)
package_delivery_pattern = models.CharField(max_length=30, blank=True)
package_delivery_comments = models.CharField(max_length=250, blank=True)
package_manifest_filename = models.CharField(max_length=50)
package_description = models.CharField(max_length=250, blank=True)
package_naming_pattern = models.CharField(max_length=50)
Screenshot of fields as displayed in the admin:

What's happening is that your actually saving a empty string '' in your CharFields instead of None values (because of the blank=True). So the Django-admin is showing the string you saved in the db (in this case, nothing).
If you change your CharFields to null=True instead of blank=True, you will be saving NULL in your database instead of an empty string. And that way, you will get the behaviour you want.
EDIT: I know this solution is not recommended (following Django Docs), but that's the behaviour you wanted. Django-admin is just showing you the string you have in the database, which is ''.
Another solution that comes to my mind is to modify the ModelAdmin for your Package model, something like:
class PackageAdmin(admin.ModelAdmin):
readonly_fields = ['show_package_delivery_pattern', ...]
def show_package_delivery_pattern(self, obj):
if obj.package_delivery_pattern:
return obj.package_delivery_pattern
else:
return 'N/A'
# same with all your CharFields..

As of Django 1.9 you can use empty_value_display at the site, model, or field level in the Django admin. At the model level:
class YourModelAdmin(admin.ModelAdmin):
empty_value_display = '---'

Related

Slow Django many to many query

I have 9 Million records.
It will be 200M soon.
It can take 15min + to fetch this:
class Follower():
hashtags = models.ManyToManyField(
"instagram_data.Hashtag", verbose_name=_("hashtags_name"))
class Hashtag(models.Model):
name = models.CharField(_("HashtagName"), max_length=150, null=True, blank=True, unique=True)
def __str__(self):
return self.name
Ubunto htop:
I think it reverse lookup for all values.
I think it will have maybe 2000 records found.
What am I doing wrong ?
The image you post looks like the model admin, if that is the case try adding the field hashtags to the raw_id_fields [Django docs] of the model admin (although then you won't get the select tag and will have to manually enter the id/pk) or the autocomplete_fields [Django docs] which would use select2 to load the choices asychronously. This would work something like:
class HashtagAdmin(admin.ModelAdmin):
ordering = ['name']
search_fields = ['name']
class FollowerAdmin(admin.ModelAdmin):
autocomplete_fields = ['hashtags']
admin.site.register(Follower, FollowerAdmin)
admin.site.register(Hashtag, HashtagAdmin)
If this is not in the model admin you can change the widget you use in the form on the form class (you will need to build a custom widget or look for some package that provides widget that can allow comma separted values), or you can use the package Django-Select2 to give the user a searchable select tag (again using select2).

Django-Jet: How do I set a foreign key null, if it is autocompleted via AJAX requests?

I am using Django-Jet and have a model with many ForeignKey fields. For those fields I want their values retrieved dynamically via AJAX and not preloaded. One of the field is like this:
class Person(Base_Entity):
first_name = models.ForeignKey(
'Name',
null = True,
blank = True,
default = None,
verbose_name = _('first name of person'),
on_delete = models.SET_NULL,
related_name = 'is_first_name_of_%(app_label)s_%(class)s',
)
)
#staticmethod
def autocomplete_search_fields():
return 'first_name__name',
(The Name model has hundreds of entries, and there will be even more later)
It seems I cannot set that field to NULL in Django Admin (no line with dashes appears):
If I turn on autocomplete (i.e. remove the autocomplete_search_fields method), I do get that NULL entry, BUT I also get all the possible values preloaded in the HTML select, and that slows down the page loading to a point it is not usable.
I am using Django 2.1.4, Django-Jet 1.0.8 (I suspect the issue is closely related to Django-Jet)
Any help is appreciated.
I am using djangojet and this relation shows an empty value choice in admin ("-----"):
someModel_FK= models.ForeignKey(someModel,
related_name='this-model',
null=True,
blank=True,
on_delete=models.SET_NULL)
a - Remove django-jet and check on default admin.
b- Are you missing migrations ? is this "null=True,blank=True, " migrated to DB ?

How can I dynamically change list of fields displayed in admin interface depending on the choice in the first field?

I want the admin interface to show disctrict field only if I choose 'B' as the category. If I choose 'W' I want all fields of Offer model to be displayed. Is it possible to show selected (filtered) fields in admin page depending on the choice in other field in the same model? Thanks in advance for your help.
My models:
class Category(models.Model):
NAME_CHOICES = (
('B', 'BLACK'),
('W', 'WHITE'),
)
name = models.CharField(max_length=200, choices=NAME_CHOICES)
class Meta:
verbose_name_plural = 'Categories'
def __unicode__(self):
return self.get_name_display()
class Offer(models.Model):
category = models.ForeignKey(Category, verbose_name='Kategoria')
city = models.CharField(max_length=128, verbose_name='Miasto')
province = models.CharField(max_length=3)
district = models.CharField(max_length=128, verbose_name='Dzielnica')
def __unicode__(self):
return "Offer number %s" % (self.id)
First of all I must to tell, that django works only in sync way. So if you want to choose which input to use, you must send a request and wait a feedback. In my opinion there're no straight way to do this task correctly.
And I see a few solutions:
1) You can use jQuery for that. But the main problem is that django has a own admin system with a built-in widgets. You can try to customize it in two ways:
Take an app with this option (for example, django-admin-tools) and create custom behavior on your form;
manage.py collectstatic and after that going to admin folder and create custom jQuery script.
2) Build a custom admin form for your model with ModelChoiceField. I don't quit sure about this field behavior really help you, but you can investigate that.
If I need to do this task, I choose first way with admin static and custom jQuery.

Django admin list_display not showing several objects

I have just begun to play around with Django admin views, and to start off, I am trying to do something very simple: showing several fields in the listing of objects using list_display as explained here: https://docs.djangoproject.com/en/dev/ref/contrib/admin/
This is my dead simple code:
class ArticleAdmin(admin.ModelAdmin):
list_display = ('title', 'category')
Unfortunately, the list_display option is causing the columnar view to appear, but only some of the objects (40 out of 85) are now displaying in the listing. I cannot deduce why certain objects are showing over the others - their fields look like they are filled similarly. It's clearly not paginating, because when I tried it on an admin of another model, it showed only 2 objects out of about 70 objects.
What might be going on here?
[UPDATE] Article Model:
class Article(models.Model):
revision = models.ForeignKey('ArticleRevision', related_name="current_revision")
category = models.ForeignKey('meta.Category')
language = models.ForeignKey('meta.Language', default=get_default_language)
created = models.DateTimeField(auto_now_add=True, editable=False)
changed = models.DateTimeField(auto_now=True, editable=False)
title = models.CharField(max_length=256)
resources = models.ManyToManyField('oer.Resource', blank=True)
image = models.ManyToManyField('media.Image', blank=True)
views = models.IntegerField(editable=False, default=0)
license = models.ForeignKey('license.License', default=get_default_license)
slug = models.SlugField(max_length=256)
difficulty = models.PositiveIntegerField(editable=True, default=0)
published = models.NullBooleanField()
citation = models.CharField(max_length=1024, blank=True, null=True)
Before adding list_display:
After adding list_display:
[UPDATE] This behaviour occurs only when ForeignKey fields are included in list_display tuple. Any of them.
[UPDATE] Category model code:
class Category(models.Model):
title = models.CharField(max_length=256)
parent = models.ForeignKey('self')
project = models.NullBooleanField(default=False)
created = models.DateTimeField(auto_now_add=True, editable=False)
slug = models.SlugField(max_length=256, blank=True)
def __unicode__(self):
return self.title
This behavior is caused by a foreign key relation somewhere that is not declared as nullable, but nonetheless has a null value in the database. When you have a ManyToOne relationship in list_display, the change list class will always execute the query using select_related. (See the get_query_set method in django.contrib.admin.views.ChangeList).
select_related by default follows all foreign keys on each object, so any broken foreign key found by this query will cause data to drop out when the query is evaluated. This is not specific to the admin; you can interactively test it by comparing the results of Article.objects.all() to Article.objects.all().select_related().
There's no simple way to control which foreign keys the admin will look up - select_related takes some parameters, but the admin doesn't expose a way to pass them through. In theory you could write your own ChangeList class and override get_query_set, but I don't recommend that.
The real fix is to make sure your foreign key model fields accurately reflect the state of your database in their null settings. Personally, I'd probably do this by commenting out all FKs on Article other than Category, seeing if that helps, then turning them back on one by one until things start breaking. The problem doesn't have to be with a FK on an article itself; if a revision, language or category has a broken FK that will still cause the join to miss rows. Or if something they relate to has a broken FK, etc etc.

Referencing a Django contrib.admin user via a foreign key?

I'm developing a small Django site and I'm using django.contrib.admin to handle content management. I'd like to capture the first name & last name of the author (an Admin user) of an Article on its initial save (and not update it if another user edits the Article).
ie.
class Article(models.Model)
title = models.CharField(max_length=50)
pub_date = models.DateTimeField('date published')
author = ForeignKey(???)
...
What do I need to write to grab this user's first name & last name fields when creating a new Article object? I'd default to their admin username if those fields are blank.
Have your model use the User object:
author = models.ForeignKey(User)
To prevent this field from being changeable on update, check out this other SO post:
Django admin: exclude field on change form only
To change the admin's Select field to use first/last name, you could try this snippet:
http://djangosnippets.org/snippets/1642/
To change the admin's view, assuming you are using the built-in templates, you could add a custom column as described on this post: How do I add a custom column with a hyperlink in the django admin interface?
class AuthorAdmin(admin.ModelAdmin):
list_display = ('author_name',)
def my_author_name(self, obj):
if obj.author.first_name and obj.author.last_name:
return '%s %s' % (obj.author.first_name, obj.author.last_name)
else:
return obj.author.username
my_author_name.allow_tags = True
my_author_name.short_description = 'Author'
I think you are looking for this:
author = models.ForeignKey(User)
It looks like the best way to handle a None or blank result from get_full_name is to just populate User.author with models.ForeignKey(User) and then — at the template level — use the following:
{{ user.get_full_name|default:user.username }}
... via this SO answer. This allows me to perform queries on a User's Articles, but still gracefully handles blank first_name & last_name fields if a User hasn't entered them yet, but will also update dynamically when they have).