Django admin list_editable profile - django

In Django, I made a UserProfile class and linked it to the User with
user = models.OneToOneField(User)
That works fine, looks like this:
Where the UserProfile is visible (with only one field).
However, I am also using the list_editable option that I discovered today. I can get the User fields editable in list view, like this:
Very nice feature, but one I can find little information about.
What I want to do is add UserProfile fields to this list in an editable way (the email_verified field in the above example, to begin with).
Is that possible to do (without changing Django code)? If so, how would I do that?
Many thanks,
UPDATE: Seriously, how can I make the question more useful if I can't use links, images, nothing? Information about list_editable is in the Django help, hopefully Google helps.

You can use inheritance of User model and get rid from Profile. In my opinion this is better way. Here you can read about this: http://scottbarnham.com/blog/2008/08/21/extending-the-django-user-model-with-inheritance/
And then just add email_verified to list_editable

Related

Django comment(s) on users in database

I'm currently building a Django website where staff has control over users, and, within those powers, I'd like to add one where the staff members can add private comments on users so that they can be read by whoever has the power to do so.
So I started building the user models.py here what I did:
class user(models.Model):
name = models.CharField(max_length=30)
comments = models.TextField()
date = models.DateField(default=datetime.now())
def __str__(self):
return self.name
My question: how can I add a comment field every time a staff member wants to? Like, with the above code, I can only have one comment per user.
Everything is appreciated.
Thanks!
There are a few ways to do this.
1. ForeignKey
Make a separate model for the comments and have a ForeignKey to the User model. That way, multiple comments can be linked to the same user.
2. ArrayField
If you're using Postgres database, you can use the ArrayField.
Cons: Editing in the admin panel is not very user friendly.
3. JSONField
You can also keep multiple comments in a JSON array.
Cons: Editing in the admin panel is not user friendly.
P.S.: If you decide to use either ArrayField or JSONField, check out an app I've made called django-jsonform. This will make editing JSON and ArrayField nice and user-friendly.

Django admin foreign key field filtering

I have client model which has a foreign key field to a country model.
So in Django admin, when I create a client and I select the country where this client belongs to. but the problem is the select list is too long(too many countries on this planet). Sometimes it takes just too long to get the one I need.
So I wonder if there is other widget in djano admin that provides a select-input-combo widget.
When I type in the input and it will filter out the right one for me to select.
Hope you can understand what I need here.
did you see raw_id_fields ?
you would do in admin.py something like:
class ClientAdmin(admin.ModelAdmin):
raw_id_fields = ("country",)
admin.site.register(Client, ClientAdmin)
then select widget will become something like:
Since Django 2.0 there is autocomplete_fields. From the documentation:
autocomplete_fields is a list of ForeignKey and/or ManyToManyField fields you would like to change to Select2 autocomplete inputs.
and
The Select2 input looks similar to the default input but comes with a search feature that loads the options asynchronously. This is faster and more user-friendly if the related model has many instances.
Note that you need to define search_fields in the related object's ModelAdmin since it is used by the widget.

Django admin filter

I've got multiple instances of a model, and each instance has a related email address. However, several instances have the same connected email address but when I put filter['email'] into my admin.py, I get a long list of the instances' emails, i.e. multiple copies of the same email in several cases.
Is there a way I can remove emails being listed multiple times? Or a way of customising the filter view into something a little nicer? (drop down menu maybe?)
I don't have a ManyToManyField relationship currently, or anything like that. I just have instances in my database with the fields name and email. My models.py looks like this:
import ldapdb.models
from ldapdb.models.fields import CharField, IntegerField, ListField
class Item(ldapdb.models.Model):
item = CharField(db_column='item', max_length=30, primary_key=True, unique=True)
email = CharField(db_column='mail', max_length=20)
My admin.py looks like so:
from items.models import Item
from django.contrib import admin
class ItemAdmin(admin.ModelAdmin):
readonly_fields = ('email',)
list_display = ('item', 'email')
list_filter = ['email']
search_fields = ['item']
admin.site.register(Item, ItemAdmin)
Obviously I've been looking at https://docs.djangoproject.com/en/1.3/ref/contrib/admin/ but I can't really see much by the way of customising my admin's filter view.
Can you post some of your code? I'm not entirely sure I understood the relationship between the instances to your email - is it an email field? a ForeighKey to a different model? how is there more than one if it's not a ManyToMany or similar relationship? And how is the filtering done in the admin?
EDIT
Ok now I understand the problem. What you want is not possible. See for the django admin site the fact that they are the same email doesn't matter because it's still a different object. There's no way around that without either specifying that field to be unique or messing with the admin site code.
A better solution would be to configure the email as searchable in the admin model and then when you search for email example#example.com it would bring all matches back.
Another good solution is to make email a different model and link it to the Item model through a ManyToMany relationship. Then you create an EmailAdmin with a method that shows you all related items for each email.
It all depends on what you actually need. Ultimately you might want to write your own view or mess around with the admin site to modify it to what you need.
Also, you might want to change the email from CharField to EmailField. Hope this helps!

Django form with ManyToMany field with 500,000 objects times out

Lets say for example I have a Model called "Client" and a model called "PhoneNumbers"
class PhoneNumbers(models.Model):
number = forms.IntegerField()
class Client(models.Model):
number = forms.ManyToManyField(PhoneNumbers)
Client has a ManyToMany relationship with PhoneNumbers. PhoneNumbers has almost 500,000 records in it so when it comes to editing a Client record from a model form with a MultiSelect widget that comes with a M2M filed, it takes forever to load. In fact, it never does. It just sits there trying to load all of those phone objects I am assuming.
My workaround was to so some tedious things with ajax and jquery to edit only the phone numbers in a Client record. Before wasting my time with all of that I wanted to see if there is somehow another way to go about it without having my page hang.
You need to create a custom widget for this field that lets you autocomplete for the correct record. If you don't want to roll your own: http://django-autocomplete-light.readthedocs.io/
I've used this for its generic relationship support, the M2M autocomplete looks pretty easy and intuitive as well. see video of use here: http://www.youtube.com/watch?v=fJIHiqWKUXI&feature=youtu.be
After reading your comment about needing it outside the admin, I took another look at the django-autocomplete-light library. It provides widgets you can use outside the admin.
from dal import autocomplete
from django import forms
class PersonForm(forms.ModelForm):
class Meta:
widgets = {
'myformfield': autocomplete.ModelSelect2(
# ...
),
}
Since Django 2.0, Django Admin ships with an autocomplete_fields attribute that generates autocomplete widgets for foreign keys and many-to-many fields.
class PhoneNumbersAdmin(admin.ModelAdmin):
search_fields = ['number']
class ClientAdmin(admin.ModelAdmin):
autocomplete_fields = ['number']
Note that this only works in the scope of Django admin of course. To get autocomplete fields outside the admin you would need an extra package such as django-autocomplete-light as already suggested in other answers.
Out of the box, the model admin has a raw_id_fields option that let your page load much quicker. However, the user interface of raw id fields isn't very intuitive, so you might have to roll your own solution.
We use this 3rd party widget for this:
https://github.com/crucialfelix/django-ajax-selects
Btw, your 'example' above is really bad DB design for a bunch of reasons. You should just have the phone number as a text field on the Client model and then you would have none of these issues. ;-)

For the django admin, how do I add a field to the User model and have it editable in the admin?

I'm trying to understand the django admin better and at the same time, I'm trying to add one more field to the current user admin. In models.py I've done
User.add_to_class('new_field', models.BooleanField(default=False))
and in admin.py I've got the following (with fieldsets basically just copied from django/contrib/auth/admin.py)
class AdjUserAdmin(UserAdmin):
list_display = UserAdmin.list_display + ('new_field',)
list_filter = UserAdmin.list_filter + ('new_field',)
fieldsets = UserAdmin.fieldsets
fieldsets[1][1]['fields'] = ('first_name','last_name','email','new_field')
The problem is, when I do this I get the error:
AdjUserAdmin.fieldsets[4][1]['fields']' refers to field 'new_field' that is missing from the form.
I've looked at UserChangeForm, but it looks like it's already correctly pulling in User as the model. I'm not sure as to why new_field is missing from the form.
Thanks
In regards to this being smelly code
I know this is a smelly monkey patching way to go about doing this, but subclassing gives me issues mainly for these reasons.. if I could get it to work the way stated above, I'd be happy.. and maybe smelly.
In regards to the recommended way
I'm aware of the recommended way of creating a user profile, just that in particular situations, I don't see the merit in creating an entire new table and having an additional call to the database when all I want to store is an extra bit of information such as is_private or some such. If I'm storing lots more info, then I agree, setting up a user profile is preferable.
First the "is it plugged in?" question -- Have you manually added new_field to the users table in the database? Syncdb wouldn't have taken care of that, of course.
After that, I would try appending the fields onto the existing UserAdmin rather than rebuilding it from scratch:
from django.contrib.auth.admin import UserAdmin
UserAdmin.list_display += ('new_field',) # don't forget the commas
UserAdmin.list_filter += ('new_field',)
UserAdmin.fieldsets += ('new_field',)
Just figured this out, perhaps this could help you as well.
Since you don't mention that you have a separate profile, if you want to simply add a column to the existing User admin, you can do the following in admin.py:
First you create a custom admin by subclassing UserAdmin:
class CustomUserAdmin(UserAdmin):
list_display = UserAdmin.list_display + ('is_complete',)
def is_complete(self, obj):
# Example here, you can use any expression.
return SomeOtherClass.objects.get(my_field=obj).is_complete()
# Not required, but this gives you a nice boolean field:
is_complete.boolean = True
Then unregister the existing UserAdmin and register your own:
admin.site.unregister(User)
admin.site.register(User, CustomUserAdmin)
It is preferred to write your own user profile class, and attach it to the User model. Then you can use the get_profile() method to retrieve the profile from the user.
Subclassing the profile admin from an Inline Admin should also allow you to edit the profile on the user's page, which is almost what you're trying to do.
This post has a really good write-up on the issue: http://www.b-list.org/weblog/2006/jun/06/django-tips-extending-user-model/
Despite your DB look up concerns for having a UserProfile, that is really the way you should go for this problem. There are two main reasons for this:
The User Model is pretty tightly coupled to Django's authentication system and to many other plugins. Monkey patching it isn't a good idea.
Django has built-in support for creating User Profiles and many extensions know how to play nicely with these. By using User Profiles (see http://docs.djangoproject.com/en/dev/topics/auth/#storing-additional-information-about-users for the main discussion on this) you can benefit from that.
If you're looking to add functionality to the Admin interface for users, then this note may be helpful:
http://www.thenestedfloat.com/articles/displaying-custom-user-profile-fields-in-djangos-admin/index.html
Regards,
Ian
Based on #anschauung response, what worked for me in Django 3.2 is:
from django.contrib.auth.admin import UserAdmin
# don't forget the commas
UserAdmin.list_filter += ('new_field',)
UserAdmin.fieldsets += (('Extra Fields', {'fields': ('new_field', )}),)
I got the 'that is missing from the form' error, and discovered that it was due to my field being marked as 'editable=False' in the model.