So I recently added an optional user profile model that is linked to a user via a OneToOneField like so:
class UserProfile(models.Model): # Creating class
user = models.OneToOneField(User, on_delete=models.CASCADE)
This worked fine, and my current UserProfile models were intact both before and after I added in this field to link the profile to a user.
The problem comes when I log in on the website as a valid user, after submitting the log in form comes an error:
AttributeError at /login/
'User' object has no attribute 'profile'
I have searched through my files for anything along the lines of 'User.profile', and similar queries, however I can't seem to find anything that would allow me to properly log in as a user.
I wasn't sure what other code to post here, and didn't want to spam this question with potentially unnecessary code so tell me if there's anything more specific (views.py, models.py, forms.py, etc) that will be needed to solve this sort of problem, or if you know of any possible solutions.
Thank you
You haven't set any related_name attribute on that one-to-one field, so the reverse accessor will be called userprofile not profile.
Make sure your app is in settins.py INSTALLED_APPS
Related
To avoid the XY problem, I will describe my problem and my attempted solution separately.
My problem
I have an Appointment model which I want to write fixtures for. There is a one-to-many mapping from the Django User model to the Appointment model (every appointment has only one client, but a client can have multiple appointments).
I know I can hard code the primary key for the Users in my appointment fixtures, but would be a brittle solution. Hard coding the foreign keys also compromises the readability of my fixtures.
My attempted solution
I looked at this question, which has an answer linking to Django documentation for natural keys. However, I ran into a problem attempting to use this approach.
I believed I could create a proxy model for the User model, so I could create a custom Manager for natural keys. Here is my proxy model:
class UserProxy(User):
objects = UserManager # The UserManager class's code is omitted
class Meta:
proxy = True
unique_together = [['username']]
(If the UserManager class's code is relevant, please let me know in a comment, and I will add it.)
However, when I run manage.py makemigrations, I get this error:
ERRORS:
accounts.UserProxy: (models.E016) 'unique_together' refers to field 'username' which is not local to model 'UserProxy'.
HINT: This issue may be caused by multi-table inheritance.
I understand this error message: the username field belongs to the User model, not to the UserProxy model.
My questions
Is my proxy model approach a good approach? If it is not, what should I do instead?
If my proxy model approach is a good approach, how can I correctly refer to the User model's username field in my unique_together list?
I have this Django project that I'm working on, which won't allow users to select an entry (User entries) on the raw_id_fields popup, if they don't have change permissions (which they can't have at all). That's really weird cause that doesn't happen with the select tag list if I remove the raw_id_fields attribute on my ModelForm class at admins.py.
How can this permission behavior be consistent if it changes according to a different interface setting? I mean, user only have permission to select users on the form if they are displayed as a select tag. It seems to me that it's a big consistency failure with the way Django permissions was designed, which, in my opinion, should have native can_view permission, in addition to can_|add, change, delete.
While googling around I found a few topics discussing this matter, but all of them end up with some really painful solutions that don't seem straightforward to me. I wonder if something so simple could have a straightforward solution that won't require lots of workarounds.
Here is an example that looks like my actual code:
models.py
class Project(models.Model):
manager = models.ForeignKey(User)
...
admins.py
class ProjectAdmin(admin.ModelAdmin):
raw_id_fields = ['manager',]
...
As you've said, this is really weird. Thats why I've opted to "extend" the django admin to my specific requirements sometimes.
The easiest way to meet this goal is by overriding the has_change_permission of the referenced ModelAdmin
As you have the request object as an argument of the method, you can evaluate:
if the request comes from a raw_id_field or not
if the user has permissions to see that models or not
any other constraint you have
A simple prototype for the method:
def has_change_permission(self, request, obj=None):
if obj is None and '_popup' in request.GET:
return True
return super(MyAdmin, self).has_change_permission(request, obj)
I'm trying to use django auth ldap (v1.1.7) with a custom user model and, while I have everything else taken care of, I still run into a familiar error message that I just don't know how to fix.
Running python manage.py syncdb returns:
CommandError: One or more models did not validate:
django_auth_ldap.testprofile: 'user' defines a relation with the model 'auth.Use
r', which has been swapped out. Update the relation to point at settings.AUTH_US
ER_MODEL.
My question here is - where can I find django_auth_ldap.testprofile and update the relation, to fix the issue?
Thanks in advance for helping me out.
L.E.: Ok, after a little googleing, i found out that this testprofile is located in django_auth_ldap/models.py and get this: I searched through all of my files and found the file, modified it to point to settings.AUTH_USER_MODEL and still I receive the same error.
Can anyone please help me out with this issue?
This is the part of django_auth_ldap's models.py -
class TestProfile(models.Model):
"""
A user profile model for use by unit tests. This has nothing to do with the
authentication backend itself.
"""
user = models.OneToOneField('auth.User') # <-- here is the trouble
is_special = models.BooleanField(default=False)
populated = models.BooleanField(default=False)
You cannot fix it unless you fix this part of the code and do as said in Django documentation -
Instead of referring to User directly, you should reference the user
model using django.contrib.auth.get_user_model(). This method will
return the currently active User model – the custom User model if one
is specified, or User otherwise.
And I wont recommend modifying the 3rd party packages yourself. If you can, go suggest the change to the developer, or send them a pull request. Once it's accepted, update the package.
I have a couple of different profiles. I want to associate permissions with these profiles. I've done so like this:
class StudentProfile(UserProfile):
school = models.CharField(max_length=30)
class Meta:
permissions = (
("is_student","Can access student pages"),
)
however, when I try and check if that permission exists using has_perm on that profile object, I get an error "'StudentProfile' object has no attribute 'has_perm'" am I not supposed to check for permissions in this way? I've read the docs and that's what I thought I was supposed to do
Edit: After reading the docs again, it seems that has_perm is a method belonging to Users and NOT their profiles. However, when I try to show the permissions:
print user.get_all_permissions()
I get an empty set. Shouldn't I see something like "appname.is_student"
.has_perm is a method on the User object, not on a UserProfile object. If you are trying to validate that a user has the permission has_student, you'd need to do something like this:
user.has_perm('profiles.is_student')
assuming that your StudentProfile model is in a profiles application.
EDIT: To address your rephrased question, you should assign permissions the normal way, either to the group or to a particular user, and use User.has_perm. Your latter example goes completely against the point of the Django permission system.
I'm developing a system based on Django admin. So all models could be edited also only from admin site. Model has a char field 'user'. I want to set current logged in admin username (or firstname, or lastname) as default value to 'user' field. How could I implement this?
Default values are set as parameters when defining model fields, so I guess no request object could be recieved? Maybe I should set the value when creating instance of model (inside init method), but how I could achieve this?
I found this recipe helpful: http://code.djangoproject.com/wiki/CookBookNewformsAdminAndUser
This is how you do it on the form level and not the save http://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.formfield%5Ffor%5Fforeignkey