The permissions of my proxy Model of a User Model are not well created.
In my "customers" app, I have:
models.py file:
from django.contrib.auth.models import User
class Customer(User):
class Meta:
proxy=True
app_label = 'customers'
verbose_name = 'Customer account'
verbose_name_plural = 'Customer accounts'
admin.py file:
from django.contrib.auth.models import User
from django.contrib.auth.admin import UserAdmin
class CustomerAdmin(UserAdmin):
def queryset(self, request):
qs = super(UserAdmin, self).queryset(request)
qs = qs.exclude(Q(is_staff=True) | Q(is_superuser=True))
return qs
admin.site.register(Customer, CustomerAdmin)
When I look at the permissions table, I see that the created permissions for my proxy Model are related to the User Content Type and not the Content Type of my proxy Model.
I then have in the admin permissions like that:
auth | Customer account | Can add Customer account
instead of:
customers | Customer account | Can add Customer account
I manually changed the content type of the permissions on the database and it worked but why is it not created the way I was expecting? Is that a bug or am I wrong?
Thanks
This was a known bug in Django. https://code.djangoproject.com/ticket/11154. It's reported as fixed in version 2.2.
For earlier versions, you can either insert them yourself or use a post_syncdb handler, if you run into this again.
Related
I have a Group model in my group/models.py file:
class Group(models.Model):
leader = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=55)
description = models.TextField()
joined = models.ManyToManyField(User, blank=True)
and an Account model, which is an extension of django's standard User, in users/models.py:
class Account(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
joined_groups = models.ManyToManyField(Group, related_name='joined_group')
created_groups = models.ManyToManyField(Group)
in users/admin.py:
class AccountInline(admin.StackedInline):
model = Account
can_delete = False
verbose_name_plural = 'Accounts'
class CustomUserAdmin(UserAdmin):
inlines = (AccountInline,)
admin.site.unregister(User)
admin.site.register(User, CustomUserAdmin)
The issue I'm having trouble understanding is when I create a new User, the Account for that User doesn't seem to really be registering. At the bottom of the new User's page (via django admin site) the new Account looks like this:
Now, this new User seems to have an account which contains joined_groups and created_groups but when I try to join or create a Group with that new User, I get an error DoesNotExist - Account matching query does not exist
I'm not sure why the new User/Account isn't really registering its Account. In comparison, inside my AdminUser page its Account info looks like this:
Account: #1 for the new User vs. Account: Acount object (6) for Admin User.
Finally, when I go onto the django admin site and add my new User to a Group and hit save, Account: #1 changes to Account: Acount object (7) which then allows the new User to create and join other Groups.
I'm completely lost on what is happening and why it is. It's important because I want new Users who register to be able to join and create Groups with an admin starting them off. Did I mess up my Account model? Or is this something to do with django's general User model? Or is it something else entirely?
Basically you have two models connected by a relationship, but I can't see the code for creating an account object. It is a good practice to create a user-related profile with the post_save signal.
from django.contrib.auth.models import User
from django.dispatch import receiver
from django.db.models.signals import post_save
from .models import Account
#receiver(post_save, sender=User)
def create_save_account(sender, instance, created, **kwargs):
if created:
Account.objects.create(user=instance)
instance.account.save()
In addition, I refer to the documentation and examples.
I am creating a payment/paid-subscription for my django project. I decided to create a separate payment app and connect it to my django project. In below, you see the model for payment which I expect to have user ids with their payment status(for now just want to start with default=False):
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
class Payment(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
paid = models.BooleanField(default=False)
class Meta:
db_table = 'payment'
I created this, but in the database table, I see the user_id and
paid are empty, while I have already a lot of users signed up. How
to bring those ids here, with a default false paid?
And what should I do to say django that after each new sign up fill
this model as well?
Part 1 - Updating existing users to have a Payment
Django won't automatically do this for you, you can go into the shell, and create Payment instances for each user:
Enter the shell (python manage.py shell)
from myapp.models import Payment
users = User.objects.all()
for user in users:
Payment.objects.create(user=user, paid=False)
If you want to be more effecient you could do something like this:
payments = [Payment(user=user, paid=False) for user in User.objects.all()]
Payment.objects.bulk_create(payments)
If this is an app that you have already deployed somewhere else you should create a data-migration to do this for you:
from django.db import migrations
def create_payments(apps, schema_editor):
Payment = apps.get_model('yourappname', 'Payment')
User = apps.get_model('yourappname', 'User')
payments = [Payment(user=user, paid=False) for user in User.objects.all()]
Payment.objects.bulk_create(payments)
class Migration(migrations.Migration):
dependencies = [
('yourappname', '0001_initial'),
]
operations = [
migrations.RunPython(create_payments),
]
Part 2 - Creating Payments on every new sign-up
This will depend alot on how you are doing your sign-ups, so its difficult to give an exact answer. But wherever your new user object is created you just want to add something like:
Payment.objects.create(user=user, paid=False)
If you have a form that is handling user sign-ups maybe do it in the save method of that form. If you're using something like django rest framework, it would go in whatever view creates the User.
I am on Django 2.1.2.
What I am trying to do is override the user model as pre suggestion here
It work perfectly fine, my problem is about the custom user model show under "Admin > myapp" instead of "Admin > Authentication and Authorization"
After some search I have tried 2 things.
1) Make use of the app_label = 'auth' statement to put it back to app auth, but it break AUTH_USER_MODEL = myapp.User in setting.py, coz it is now auth_user.
class User(AbstractUser):
pass
class Meta:
app_label = 'auth'
2) Move Group to myapp with below statement, so I can put both User and Group together, but it break the user model coz it moved auth_group to myapp_group
apps.get_model('auth.Group')._meta.app_label = 'myapp'
Any input are welcome
Bill
You can use a proxy model:
class User(AbstractUser):
pass
class ProxyUser(User):
pass
class Meta:
app_label = 'auth'
proxy = True
verbose_name = 'user'
and add the following to admin.py:
from django.contrib.auth.admin import UserAdmin
from .models import User, ProxyUser
admin.site.register(ProxyUser, UserAdmin)
I'm trying to add fields to the User model and add them to the admin page. There is a recommended method in the django docs here:
https://docs.djangoproject.com/en/dev/topics/auth/#storing-additional-information-about-users
So, I created a OneToOne field for my new model:
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.OneToOneField(User)
designs = models.ManyToManyField('Design', blank=True)
prints = models.ManyToManyField('Print', blank=True)
rating = models.IntegerField(null=True, blank=True)
reliability = models.IntegerField(null=True, blank=True)
av_lead_time = models.IntegerField(null=True, blank=True)
Added an AUTH_PROFILE_MODULE to settings.py:
AUTH_PROFILE_MODULE = 'website.UserProfile'
Tried to add the UserProfile fields to the admin page:
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from website.models import UserProfile
from django.contrib.auth.models import User
# Define an inline admin descriptor for UserProfile model
# which acts a bit like a singleton
class UserProfileInline(admin.StackedInline):
model = UserProfile
can_delete = False
verbose_name_plural = 'profile'
# Define a new User admin
class UserAdmin(UserAdmin):
inlines = (UserProfileInline, )
# Re-register UserAdmin
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
Now, when I try to access a registered user via the admin menu, I get:
Caught DoesNotExist while rendering: User matching query does not exist.
In template /usr/local/lib/python2.7/dist-packages/django/contrib/admin/templates/admin/includes/fieldset.html, error at line 19
19 {{ field.field }}
And when I try to add a new user via the admin menu, I get:
Caught DoesNotExist while rendering: User matching query does not exist.
In template /usr/local/lib/python2.7/dist-packages/django/contrib/admin/templates/admin/includes/fieldset.html, error at line 19
19 {{ field.field }}
Why doesn't it recognise that particular field?
Edit: After looking on the full error message I can see the error is not solely related to extending User. The error happens when rendering checkboxes and corresponding labels that are used to assign prints to UserProfile you are editing/adding. Django admin is calling Print.__unicode__ for rendering label for each Print instance, which in turn access (on line 33 of /threedee/website/models.py) the Print's "printer" attribute which is a foreign key to User. And for some reason one of the Prints does have invalid printer value which doesn't point to any User.
Can't really tell what is really happening here without seeing the Print model, I recommend you checking the Print database table (should be named website_print) and find if there is anything unusual (are you using PostgreSQL?). If you are not having any important data there, truncating whole Print table should do the trick.
This is my old answer which you should still follow but it's not related to the error you are experiencing:
I would just comment on others answers but there doesn't seem to be a way of doing that for me. You need to combine both Alexey Sidorov's and Like it's answers:
First use django shell to create UserProfile instances for existing users - just run commads provided by Like it's answer in the shell (python manage.py shell).
After that you should setup signal that will automatically create UserProfile for each new user according to answer from alexey-sidorov.
Add this to models.py, after UserProfile class.
from django.db.models.signals import post_save
def create_user_profile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
post_save.connect(create_user_profile, sender=User)
more info https://docs.djangoproject.com/en/dev/topics/auth/#storing-additional-information-about-users
Add UserProfile entry for you existing users:
from django.contrib.auth.models import User
from website.models import UserProfile
for user in User.objects.all():
profile = UserProfile.objects.get_or_create(user = user)
and create profile for new user as well.
use signals for what.
I am using django profiles with having different types of profiles.
My Profile Model of Company is similar to:
from django.db import models
from django.contrib.auth.models import User
from accounts.models import UserProfile
from jobs.models import City
from proj import settings
from django.core.mail import send_mail
class Company(UserProfile):
name=models.CharField(max_length=50)
short_description=models.CharField(max_length=255)
tags=models.CharField(max_length=50)
profile_url=models.URLField()
company_established=models.DateField(null=True,blank=True)
contact_person=models.CharField(max_length=100)
phone=models.CharField(max_length=50)
address=models.CharField(max_length=200)
city=models.ForeignKey(City,default=True)
def send_activation_email(self):
self.set_activation_key(self.username)
email_subject = 'Your '+settings.SITE_NAME+' account confirmation'
email_body = """Hello, %s, and thanks for signing up for an
example.com account!\n\nTo activate your account, click this link within 48
hours:\n\nhttp://"""+settings.SITE_URL+"/accounts/activate/%s""" % (self.username,self.activation_key)
send_mail(email_subject,
email_body,
'acccounts#site.com',
[self.email])
Here I am inheriting Company from UserProfile and in send activation email, I am trying to use properties and methods of parent classes user and userprofile. Its direct parent is userprofile while user has onetoone relation with userprofile. So I tried to call self.activation_key that is defined in userpofile and called self.username that is property of user class/table and getting error on self.username .
So seems like I am calling self.username in wrong way,so how can I access self.username ? Any detail will be helpful and appreciated.
Company inherits from UserProfile, but as you say UserProfile doesn't inherit from User - it has a OneToOne relationship with it. So there's no such thing as self.username - there's simply a relationship from self to User.username. I'm going to guess that that relationship is via a field called user, in which case you want self.user.username.