I'm trying to extend the basic user registration form and profile included in satchmo store, but I'm in problems with that.
This what I've done:
Create a new app "extendedprofile"
Wrote a models.py that extends the satchmo_store.contact.models class and add the custom name fields.
wrote an admin.py that unregister the Contact class and register my newapp but this still showing me the default user profile form.
Maybe some one can show me the correct way to do this?
It sounds like you are doing it right, but it would help if you post your source. When I take this route, I treat the extended profile as an inline to the user model:
class UserProfileInline(admin.StackedInline):
model = UserProfile
fk_name = 'user'
max_num = 1
fieldsets = [
('User Information', {'fields': ['street', 'street2', 'city', 'state', 'country', 'latitude', 'longitude']}),
('Site Information', {'fields': ['sites']}),
('User Account', {'fields': ['account_balance']}),
]
class NewUserAdmin(admin.ModelAdmin):
inlines = [UserProfileInline, ]
admin.site.unregister(User)
admin.site.register(User, NewUserAdmin)
Hopefully that helps you.
Wrote a models.py that extends the
satchmo_store.contact.models class and
add the custom name fields.
wrote an admin.py that unregister the
Contact class and register my newapp
but this still showing me the default
user profile form.
This is related to overriding the django registration User class; the satchmo project creates a foreign key to the User class (as of 0.9.2). But what you want to do is create an extended profile class with new fields.
So, in this specific case you're going to need to do a few things to override the profile template that shows the Contact information:
Write your own models that subclass the Contact class (you already did this)
Write your own view(s) to use your new model class (base on satchmo_store.contact.views but use your own class instead of the Contact class)
Override the urlpatterns for the satchmo_store.contact application to point at your new view
Extend the satchmo_store.contact.forms.ExtendedContactInfoForm form class with entries for your editable form fields.
Modify the contact/view_profile.html template to include the custom name fields.
Then you may want to unregister the Contact class as above, admin.site.unregister(Contact), and only admini your new subclass.
Related
I have a Profile model that has a one to one relationship with the User model from django.contrib.auth.models , when I add a new profile from the admin panel I noticed that the password field is not transformed into dots when typing , it shows the actual password , that's not the issue though , the issue is , when ever I create a new profile which in turns creates a new User , and mark the is staff attribute as true, I can't log in into the admin panel with that created account, unless I reset the password manually with
python manage.py changepassword the-user-name
after I have reset the password and only then even with the same password, I can log in into the account normally, does anybody know why is that happening ?
I made sure it's not a mistake in typing the password and I tried it several times until I made sure that this is what is actually happening
Update
when I enter the Users model from the Authentication and Authorization section opposed to entering it from the app name, I find that written besides the password section
Invalid password format or unknown hashing algorithm
how can I fix it ?
I forgot to say that I am using an UpdateView from generic views , and using the model Profile as the the model attribute set on that view
the code of my update view
class ProfileUpdate(UpdateView):
model = Profile
fields= [
'username',
'bio',
'avatar_thumbnail',
'location',
'tags',
'contact_information'
]
def get_object(self):
return Profile.objects.get(pk = self.kwargs.get('user_pk'))
def get_queryset(self):
base_qs = super(ProfileUpdate, self).get_queryset()
return base_qs.filter(username=self.request.user.username)
That would inherit from ModelAdmin instead of UserAdmin in your admin.py.
Can you instead try this:
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
from app.models import Profile
class ProfileAdmin(UserAdmin):
def __init__(self, *args, **kwargs):
super(UserAdmin,self).__init__(*args, **kwargs)
UserAdmin.fieldsets += (('profile', {'fields': ('attr1', 'attr2')}),)
admin.site.unregister(User)
admin.site.register(Profile, ProfileAdmin)
Explanation
When you registered the Profile admin like so, admin.site.register(models.Profile), internally it was inheriting from ModelAdmin class which is perfect for all other classes. But for User we need hashing for saving the passwrd field, so there is a separate class UserAdmin that must be inherited from.
Once you inherited, the password issue was resolved but since the base model was UserAdmin, only user related fields were showing. We needed to append the profile fields for which we added the __init__ method and appended the profile fields to the admin section.
I'm using django 2 and python 3.
In my model I have Users that can own a list of Applications. Applications can have only one Owner.
I used a ForeingKey like so:
class User(AbstractUser):
# nothing interresting for this question here
pass
class StoreApplication(models.Model):
owner = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name="applications"
)
Now I would like to list the User's applications in the User's admin page, like a list of application names, just readonly stuff. Not in the list view, in the edit view.
I'm aware of InlineModelAdmin and it does not seem to resolve my issue, as it includes the whole Application forms for each of the user's application.
If I try to reference the field as "applications" in my user admin:
class UserAdmin(admin.ModelAdmin):
list_display = ("username", )
fieldsets = (
("Général", {
"fields": ("username", "applications", )
}),
)
An error occurs:
Unknown field(s) (applications) specified for User. Check fields/fieldsets/exclude attributes of class UserAdmin.
You could add a method to the UserAdmin that returns all the applications as a comma separated list. I'm going to assume there is a CharField on the StoreApplication model that names the object (name)
def get_applications(self, obj):
return ', '.join([app.name for app in obj.applications])
# set the short_description to how you want that field displayed in admin
get_applications.short_description = 'Applications'
Then just add get_applications to fields and readonly_fields
I'd like to create a formView(based on Django build-in CreateView class) to allow creating new user records, which are from two different models.
Both models sounds like one is user model and another is user profile model.
I wish one form with one submit button to approach it, but I found only one form_class could be assigned in one createView class in Django.
So I wonder is that possible to use CreateView to approach it? if not, any solution recommended? Appreciated if any assistance from you.
So you have two models for user and user_profile. One user one profile
so:
Try this:
#models.py
class User_profile(models.Model):
User= models.Foreignkey('User')
#add more user data
#forms.py
class UserProfileForm(ModelForm):
model = User_profile
fields = ['User']
#views.py
class SomeView(CreateView):
form_class = UserProfileForm()
Actually, I find the solution: use the User model and add profile's field in the same form as below
class userCreateForm:
email = forms.EmailField(label=_("E-mail"))
contact_number = forms.CharField(label=_("Contact"))
contact_address = forms.CharField(label=_("Address"))
class Meta:
model = User
fields = (UsernameField(), "email", "contact_number", "contact_address")
This may be a very simple question, but I haven't been able to find it in SO.
I created a User Profile Model for additional user info via OnetoOneField. Now for the Admin of the User Profile Model, I want to display the email field found in the User model. I tried:
# models.py
def email(self):
return self.user.email
# admin.py
fieldsets = [
('', {'fields': [
...
'email',
...
]})
]
list_display = (
...
'email',
...
)
This worked for the list_display section, but for fieldsets, the following error popped up:
Unknown field(s) (email) specified for UserProfile. Check fields/fieldsets/exclude attributes of class UserProfileAdmin.
Is there a way to work around this? Thank you in advance!
From the documentation:
fields can contain values defined in readonly_fields to be displayed
as read-only.
If you add the name of a callable to fields, the same rule applies as
with the fields option: the callable must be listed in
readonly_fields.
So you need to add:
readonly_fields = ('email',)
to your model admin class, and then it will be available in the fieldset.
Put this
def email(self, obj):
return obj.user.email
in your admin class of userprofile and you will be able to use it in fieldsets.
I'm a complete n00b to django & python. I come from a PHP background so you'll have to accept my apologies for that :p.
I'm trying to use the admin panel functionality in django to show different options to different people.
The system should allow admins to add "projects" to a list. "Developers" should then be able to view only projects assigned to them, and only change certain fields.
So I guess the question is two fold:
1) Is allowing the "Developers" to login to the admin system the best method of doing it?
1.a) If so, How do I get a boolean field to display on the admin's user form? I just want to flag is_developer. I've added it as a userProfile but don't understand how to make it display on the form
2) Should I disallow them to login (to the admin panel) and make "frontend" whereby they can only see what they're allowed?
I hope that made sense. I'm a bit all over the place at the moment as it's a complete departure to what i'm used to!
Thanks in advance for any help you can offer me :)
There's a lot going on here, so I'm going to piecemeal my answer.
Is allowing the "Developers" to login to the admin system the best method of doing it?
That depends on your setup. Generally, the admin should only be available to "staff": people that are employed by or directly related to your organization. In fact, in order to login to the admin, a user must have is_staff=True. If all of the users belong to your organization (and can be considered "trusted" as a result), then yes, it's fine to allow them to all access the admin. Otherwise, it's not a good idea, as you're opening yourself up to security risks.
If so, How do I get a boolean field to display on the admin's user form?
In the most simplistic sense, you can add a field to a form by literally adding it to the form class, even if it's a ModelForm which pre-populates its fields from the fields on the model.
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
is_developer = forms.BooleanField(default=False)
I've added it as a userProfile but don't understand how to make it display on the form
UserProfile is a different model, obviously, so its fields are not made available on a form for a User. However, Django does provide the ability to add/edit related models inline with edit form for another model. This is done through inline formsets. In the admin, these are just called "inlines".
class UserProfileInlineAdmin(admin.StackedInline):
model = UserProfile
max_num = 1
can_delete = False
class UserAdmin(admin.ModelAdmin):
inlines = [UserProfileInlineAdmin]
The view you get from an inline admin is clearly distinct from the main form (in this case, that of User), though. You can try it out to see what I mean. It's not horrible, but it's still a noticeable break in the form. The reason I mentioned how to add a field to a form earlier, is that if you wanted, you can make it look all like one form with a little bit of clever misdirection.
class UserAdminForm(forms.ModelForm):
class Meta:
model = User
is_developer = forms.BooleanField(default=False)
def save(self, commit=True):
user = super(UserAdminForm, self).save(commit=commit)
if user.pk:
profile = user.get_profile()
profile.is_developer = self.cleaned_data.get('is_developer')
profile.save()
That's a simplistic example, but the idea is that you add the field(s) manually to the form, and then use them to actually update the other object manually when the main object being edited is saved.
Special notes related to User
Now, since you're dealing with User here, there's a lot more sticky details. First, User already has a UserAdmin and its own forms -- yes plural, forms. If you want to add new functionality, you need to make sure you keep the existing Django functionality in the process.
from django.contrib.auth.admin import UserAdmin
form django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
class CustomUserCreationForm(UserCreationForm):
# do stuff
class CustomUserChangeForm(UserChangeForm):
# do stuff
class CustomUserAdmin(UserAdmin):
form = CustomUserChangeForm
add_form = CustomUserCreationForm
admin.site.unregister(User)
admin.site.register(User, CustomUserAdmin)
Also, UserAdmin has its own set of fieldsets defined. The defaults are:
fieldsets = (
(None, {'fields': ('username', 'password')}),
(_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
(_('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser', 'user_permissions')}),
(_('Important dates'), {'fields': ('last_login', 'date_joined')}),
(_('Groups'), {'fields': ('groups',)}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('username', 'password1', 'password2')}
),
)
If you want to add a field or fields, you'll need to redefine those two attributes with your fields added where you want them.