If I use normal user provided django default, my model will be like this.
from django.db import models
from django.contrib.auth.models import Users
class Photo(models.Model):
photographer=models.ForeignKey(User, on_delete=models.CASCADE, related_name='user') # 5
# other fields
If I want to implement allauth, what should I have to pass for the first argument in line#5, instead of User?
Django-allauth still uses the User model from django's auth, so you don't have to change anything. Unless you've extended a custom user model.
Related
How come to import User from the auth package that comes with Django, I need to do:
from django.contrib.auth.models import User
while to refer to the same User model to create a ForeignKey, I need to do:
owner = models.ForeignKey('auth.User', related_name='snippets')
and not 'auth.models.User'?
I am following the example here : http://www.django-rest-framework.org/tutorial/4-authentication-and-permissions
This is due to Django's "lazy relationships". You can see the code for this here. You don't need to specify the exact module, in this case models because anything inheriting from Django's models.Model will fire off a class_prepared signal once it's initialised and up to this point, it's still only a string.
Just provide the app and model, or just the model name if it's in the same app.
I'm using a custom user model myapp.MyUser in a Django 1.5 app. I updated my settings as documentation says to do, AUTH_USER_MODEL = "myapp.MyUser". As MyUser extends AbstractUser, I created the admin with this code:
from django.contrib.auth import get_user_model
from django.contrib.auth.admin import UserAdmin
admin.site.register(get_user_model(), UserAdmin)
And it works fine, except the creation form. When I try to create a new user, the following exception is raised:
DatabaseError at /admin/core/user/add/
(1146, "Table 'mydatabase.auth_user' doesn't exist")
The full traceback can be found here.
Digging out Django's source code it looks like UserCreationForm - which is used by UserAdmin - references django's built-in auth.User directly, instead of use get_user_model.
Can it be the problem? Why everything references myapp.MyUser, including admin's auth and the change form, except the creation?
As you say, the UserCreationForm references auth.User directly. The Django docs on custom users and built in auth forms state that you must rewrite it for any custom user model.
UserCreationForm
Depends on the User model. Must be re-written for any custom user model.
There is a related ticket Ticket 20086, which was initially closed as invalid, because the user creation form is working as documented.
There is a full example on the same page, which shows you how to rewrite the forms and register a custom user model in the admin.
If you don't mind to store your custom model in a table called auth_user you can simply set this in Meta and this solves auth_user table doesn't exist. All you need is:
class MyUser(AbstractUser):
class Meta(AbstractUser.Meta):
swappable = 'AUTH_USER_MODEL'
db_table = 'auth_user'
I'm trying to make sure that the first name and last name field are not optional for the auth User model but I'm not sure how to change it. I can't use a sub class as I have to use the authentication system.
Two solutions I can think of are:
to put the name in the user profile but it's a little silly to have a field that I can't use correctly.
To validate in the form rather than in the model. I don't think this really fits with Django's philosophy...
For some reason I can't seem to find a way to do this online so any help is appreciated. I would have thought that this would be a popular question.
Cheers,
Durand
Simplest solution
Just create a custom UserRegisterForm which inherits the django's default UserCreationForm.
The first_name and last_name are already attributes of django's default User. If you want to make them as required fields, then recreate those fields as forms.CharField(...).
Now use your own User register form.
# Contents usersapp/forms.py
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
# Inherit Django's default UserCreationForm
class UserRegisterForm(UserCreationForm):
first_name = forms.CharField(max_length=50) # Required
last_name = forms.CharField(max_length=50) # Required
# All fields you re-define here will become required fields in the form
class Meta:
model = User
fields = ['username', 'email', 'first_name', 'last_name', 'password1', 'password2']
I would definitely go with validating on the form. You could even go as far as having more form validation in the admin if you felt like it.
Thanks Mbuso for the advice. Here's my full implementation for those who are interested. Before taking a look at the source, let's see what it looks like:
I've implemented a profile model, but this will work just fine without it.
from django.core.exceptions import ValidationError
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.forms import UserChangeForm
from django.contrib.auth.models import User
from apps.profiles.models import Profile
# Define an inline admin descriptor for Profile model
# which acts a bit like a singleton
class UserProfileInline(admin.StackedInline):
model = Profile
can_delete = False
verbose_name_plural = 'profile'
class MyUserChangeForm(UserChangeForm):
def clean_first_name(self):
if self.cleaned_data["first_name"].strip() == '':
raise ValidationError("First name is required.")
return self.cleaned_data["first_name"]
def clean_last_name(self):
if self.cleaned_data["last_name"].strip() == '':
raise ValidationError("Last name is required.")
return self.cleaned_data["last_name"]
# Define a new User admin
class MyUserAdmin(UserAdmin):
form = MyUserChangeForm
inlines = UserProfileInline,
admin.site.unregister(User)
admin.site.register(User, MyUserAdmin)
Note: If you do implement a profile model, recommend using UserProfile as the name, since is this is what's in the documentation and seems to be the standard (this part was developed before I started working on the project). If you're using Django 1.5 or higher, skip UserProfile all together and extend the User model.
The Django way of extending the basic User model is through user profiles: see "Storing additional information about users".
If it does not fit your needs, django.contrib.auth is just a Django application, I would simply fork it. As long as you abide by the original interface, I think you will be out of trouble.
Another option is Pinax - it has OpenId support built in, you can use it with your own openid provider. OpenId native support is a battery I really miss in Django.
in django by default when syncdb is run with django.contrib.auth installed, it creates default permissions on each model... like foo.can_change , foo.can_delete and foo.can_add. To add custom permissions to models one can add class Meta: under the model and define permissions there, as explained here https://docs.djangoproject.com/en/4.1/topics/auth/customizing/#custom-permissions
My question is that what should I do if I want to add a custom permission to the User model? like foo.can_view. I could do this with the following snippet,
ct = ContentType.objects.get(app_label='auth', model='user')
perm = Permission.objects.create(codename='can_view', name='Can View Users',
content_type=ct)
perm.save()
But I want something that plays nicely with syncdb, for example the class Meta under my custom models. Should I just have these in class Meta: under UserProfile since that is the way to extend the user model. but is that the RIGHT way to do it? Wouldn't that tie it to UserProfile model?
You could do something like this:
in the __init__.py of your Django app add:
from django.db.models.signals import post_syncdb
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth import models as auth_models
from django.contrib.auth.models import Permission
# custom user related permissions
def add_user_permissions(sender, **kwargs):
ct = ContentType.objects.get(app_label='auth', model='user')
perm, created = Permission.objects.get_or_create(codename='can_view', name='Can View Users', content_type=ct)
post_syncdb.connect(add_user_permissions, sender=auth_models)
I don't think there is a "right" answer here, but i used the exact same code as you except i changed Permission.objects.create to Permission.objects.get_or_create and that worked find to sync with syncdb
An updated answer for Django 1.8. The signal pre_migrate is used instead of pre_syncdb, since syncdb is deprecated and the docs recommend using pre_migrate instead of post_migrate if the signal will alter the database. Also, #receiver is used to connect add_user_permissions to the signal.
from django.db.models.signals import pre_migrate
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth import models as auth_models
from django.contrib.auth.models import Permission
from django.conf import settings
from django.dispatch import receiver
# custom user related permissions
#receiver(pre_migrate, sender=auth_models)
def add_user_permissions(sender, **kwargs):
content_type = ContentType.objects.get_for_model(settings.AUTH_USER_MODEL)
Permission.objects.get_or_create(codename='view_user', name='View user', content_type=content_type)
This is a bit hacky but mentioning it here anyway for reference.
My site has a generic model called Setting, which stores various settings concerning the site I want certain users to be able to edit, without needing to go through me the developer (like registration limit, or an address, or the cost of items, etc).
All the permissions that don't nicely map onto other models (eg "Send Password Reminder Email to Student", "Generate Payment Reconciliation Report", "Generate PDF Receipt"), which really just relate to pages that get viewed in the admin area, get dumped onto this Setting model.
For example, here's the model:
class Setting(models.Model):
name = models.CharField(max_length=50, unique=True)
slug = models.SlugField(editable=False)
description = models.TextField()
value = models.TextField()
class Meta:
#for permissions that don't really relate to a particular model, and I don't want to programmatically create them.
permissions = (
("password_reminder", "Send Password Reminder"),
("generate_payment_reconciliation_report", "Generate Payment Reconciliation Report"),
("generate_pdf_receipt", "Generate PDF Receipt"),
)
Do each of those settings strictly relate to the Setting model? No, which is why I said this is a bit hacky. But it is nice that I can now just dump all those permissions here, and Django's migration commands will take care of the rest.
I'm learning Python Django framework. Thanks to StackOverFlow Community, i have learned how to use open-id in django (social_auth i'm using ).
with social_auth, sign in and sign out process are pretty easy and practical. But i want to build friendship relationship between users, for this i created new model class which is extended from from django.contrib.auth.models import User and add control when new user is created in auth_table, i create new user on CustomUser Table.(It is not efficient because the parameters coming from open-id are different for each open-id connection)
My model code is here
from datetime import datetime
from django.core.exceptions import ObjectDoesNotExist
from django.db import models
from django.contrib.auth.models import User
from django.contrib.auth.models import UserManager
# Create your models here.
class CustomUser(User):
gender = models.CharField(max_length=50)
location = models.CharField(max_length=50)
bio = models.CharField(max_length=50)
web_pages = models.CharField(max_length=50)
friends = models.ManyToManyField("self")
And How can i use CustomUser model and OpenID together in Django for authentication?
Any Help will be appreciated.
The way to extend the User class in Django is to provide user profile class. See here. You can then just use the User model as always and get the profile instance on demand.