Django Extend AbstractUser and use email Field as default in other field - python

I'm using Django 1.9.2 with python 2.7.3, rest framework and allauth. I'm extending from django.contrib.auth.models.AbstractUser and I want to get the email field from AbstractUser and use it as default in other field:
from django.contrib.auth.models import AbstractUser
class MyUser(AbstractUser):
def get_email(self):
return self.email
email_from_work = models.EmailField(default=get_email())
But when I use this code, I get the following error:
File "./behnowapp/models.py", line 48, in MyUser
email_from_work = models.EmailField(default=get_email())
TypeError: get_email() takes exactly 1 argument (0 given)
What is the way for get the email attribute?

Thanks to RA123 for the orientation, I have also overwritten the save method of MyUser and instead of implementing my own UserManager, I have implemented the default and I have added the necessary fields:
class MyUser(AbstractBaseUser, PermissionsMixin):
def save(self, *args, **kwargs):
if not self.email_from_work:
self.email_from_work = self.get_email()
super(MyUser, self).save(*args, **kwargs)
def get_email(self):
return self.email
objects = UserManager()
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email']
username = models.CharField(
_('username'),
max_length=30,
unique=True,
help_text=_('Required. 30 characters or fewer. Letters, digits and #/./+/-/_ only.'),
validators=[
validators.RegexValidator(
r'^[\w.#+-]+$',
_('Enter a valid username. This value may contain only '
'letters, numbers ' 'and #/./+/-/_ characters.')
),
],
error_messages={
'unique': _("A user with that username already exists."),
},
)
first_name = models.CharField(_('first name'), max_length=30, blank=True)
last_name = models.CharField(_('last name'), max_length=30, blank=True)
email = models.EmailField(_('email address'), blank=True)
is_staff = models.BooleanField(
_('staff status'),
default=False,
help_text=_('Designates whether the user can log into this admin site.'),
)
is_active = models.BooleanField(
_('active'),
default=True,
help_text=_(
'Designates whether this user should be treated as active. '
'Unselect this instead of deleting accounts.'
),
)
date_joined = models.DateTimeField(_('date joined'), default=now)
email_from_work = models.EmailField(max_length=255, unique=True)

You cannot extend AbstractUser for this purpose. Extend AbstractBaseUser for this. Inherit PermissionsMixin, if you want to use those features. And also make a custom manager extending BaseUserManager.
Example -
class MyUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(max_length=255, unique=True)
objects = MyUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = [] # Fields necessary for making a user
def get_email(self):
return self.email

Related

Registration user with multiple usernames - Django REST

I'm trying to implement a user registration and authentication using django rest framework and I'm not sure how to implement it.
The thing is that I want a user to have multiple usernames/nicknames so that's why I have a little bit troubles.
The current models I have:
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(max_length=50,
unique=True,
error_messages={
'unique': _("Email already exists."),
},
)
is_active = models.BooleanField(
_('active'),
default=True,
help_text=_(
'Designates whether this user should be treated as active. '
'Unselect this instead of deleting accounts.'
),
)
gender = models.IntegerField(default=GENDER_MALE, choices=GENDER_CHOICES)
date_of_birth = UnixDateTimeField(null=True, blank=True, )
ip = models.GenericIPAddressField(null=True)
USERNAME_FIELD = 'email'
class Meta:
verbose_name = _('user')
verbose_name_plural = _('users')
class UserNicknames(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
username = models.CharField(max_length=10,
null=False,
unique=True,
validators=[username_validator],
error_messages={
'unique': _("A user with that username already exists."),
},
)
is_current = models.BooleanField(default=False)
As you can see I have the User model just like the django one but without the username and UserNicknames which contains the user nicknames (the UserNicknames.user field is the foreign key to the User.id field).
The question is what is right way to implement the registration serializer? Should I get all the fields in User and UserNicknames and then do the logic or there is some smarter way to do it?

Django Inner Join on Derived Query

I have two models shown as follows. I want to be able to execute this query through the django ORM, essentially giving me the CustomUser class alongside two derived fields: max(message.sent_at) and max(case when read_at is null then 1 else 0 end). Those two fields would enable me to sort threads of messages by usernames and latest activity.
Here are my classes:
class CustomUser(AbstractBaseUser, PermissionsMixin):
username_validator = UnicodeUsernameValidator()
username = models.CharField(_('username'), max_length=150, unique=True, help_text=_('Required. 150 characters or fewer. Letters, digits and #/./+/-/_ only.'), validators=[username_validator], error_messages={'unique': _('A user with that username already exists.'),},)
email = models.EmailField(_('email address'), blank=True)
first_name = models.CharField(_('first name'), max_length=30, blank=True)
last_name = models.CharField(_('last name'), max_length=150, blank=True)
is_staff = models.BooleanField(_('staff status'), default=False, help_text=_('Designates whether the user can log into this admin site.'),)
is_active = models.BooleanField(_('active'), default=True, help_text=_('Designates whether this user should be treated as active. Unselect this instead of deleting accounts.'),)
date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
bio = models.TextField(max_length=500, null=True, blank=True)
location = models.CharField(max_length=30, null=True, blank=True)
birth_date = models.DateField(null=True, blank=True)
phone_number = PhoneNumberField(default='+10000000000')
gender = models.CharField(max_length=32, choices=[(tag.name, tag.value) for tag in GenderChoice], default=GenderChoice.UNSPECIFIED.value)
objects = UserManager()
EMAIL_FIELD = 'email'
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email']
class Meta:
ordering = ['username']
verbose_name = _('user')
verbose_name_plural = _('users')
and
class Message(AbstractIP):
subject = models.CharField(_('Subject'), max_length=120, blank=True)
body = models.TextField(_('Body')) # Do we want to cap length or enforce non-blank?
sender = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='sender_messages', verbose_name=_('Sender'), on_delete=models.CASCADE)
recipient = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='receiver_messages', verbose_name=_('Recipient'), blank=True, on_delete=models.CASCADE)
parent_msg = models.ForeignKey('self', related_name='next_messages', null=True, blank=True, verbose_name=_('Parent message'), on_delete=models.CASCADE)
sent_at = models.DateTimeField(_('sent at'), null=True, blank=True)
read_at = models.DateTimeField(_('read at'), null=True, blank=True)
replied_at = models.DateTimeField(_('replied at'), null=True, blank=True)
sender_deleted_at = models.DateTimeField(_('Sender deleted at'), null=True, blank=True)
recipient_deleted_at = models.DateTimeField(_('Recipient deleted at'), null=True, blank=True)
ip = models.GenericIPAddressField(verbose_name=_('IP'), null=True, blank=True)
user_agent = models.CharField(verbose_name=_('User Agent'), blank=True, max_length=255)
objects = MessageManager() # Manager for Message queries
def new(self):
"""Returns whether the recipient has read the message or not"""
if self.read_at is not None:
return False
return True
def replied(self):
"""Returns whether the recipient has written a reply to this message"""
if self.replied_at is not None:
return True
return False
def __str__(self):
if self.subject is not None:
return self.subject
if self.body is not None:
return self.body[:40]
return None
def get_absolute_url(self):
return reverse('messages_detail', args=[self.id])
def save(self, **kwargs):
if not self.id:
self.sent_at = timezone.now()
super(Message, self).save(**kwargs)
class Meta:
ordering = ['-sent_at']
verbose_name = _('Message')
verbose_name_plural = _('Messages')
The query I want to be able to perform equates to this, but I cannot figure out how to do it in the ORM, where %s is a placeholder for the CustomUser.id (pk) field of a given user.
SELECT webrtc_customuser.*
,MAX(webrtc_message.sent_at) AS sent_at
,MAX(CASE WHEN webrtc_message.read_at IS NULL AND webrtc_customuser.id <> webrtc_message.sender_id THEN 1 ELSE 0 END) AS has_unread
FROM webrtc_customuser
INNER JOIN webrtc_message
ON (
webrtc_customuser.id = webrtc_message.sender_id
AND webrtc_message.sender_id = %s
AND webrtc_message.sender_deleted_at IS NULL
) OR (
webrtc_customuser.id = webrtc_message.recipient_id
AND webrtc_message.recipient_id = %s
AND webrtc_message.recipient_deleted_at IS NULL
)
I managed to get the correct user_id and derived fields with the following queries but cannot figure out how to get the CustomUser properties joined alongside them.
messages = self.values(
user_fk=Case(When(sender=user, then='recipient'), default='sender', output_field=models.IntegerField())
).exclude(
sender=user, recipient=user
).filter(
Q(sender=user, sender_deleted_at__isnull=True) |
Q(recipient=user, recipient_deleted_at__isnull=True)
).annotate(
max_sent_at=Max('sent_at'),
has_unread=Max(Case(When(~Q(sender=user) & Q(read_at__isnull=True), then=1), default=0, output_field=models.IntegerField()))
).order_by()
Thank you in advance for your time!
Edit: updated ORM query
You need to specify the desired user properties individually:
messages = self.values(
user_email=Case(When(sender=user, then='recipient__email'), default='sender__email'),
user_username=Case(When(sender=user, then='recipient__username'), default='sender__username'),
)
Not very pretty, particularly as you have to repeat the CASE statement for every column and may even need to specify an output_field for every one.
To get around that, ie. to get all user properties without selecting them one by one, you'd either need to a) select from CustomUser.object (figuring out how to select the relevant users and get the relevant annotations), or b) select full message objects rather than just a values() dictionary. Then you can access the full user objects via message.senderand message.recipient. But here again, the challenge would be how to filter and annotate the messages queryset using subqueries, since just omitting values() will bust the aggregates in your annotations as every message object will then be unique.

Django error "add a non-nullable field"

i am getting error django model like this when i try to makemigrations:
You are trying to add a non-nullable field 'person' to owner without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows)
2) Quit, and let me add a default in models.py
i use django 1.8 and this is my model:
class Person(models.Model):
user = models.OneToOneField(User)
alphanumeric = RegexValidator(r'^[0-9a-zA-Z]*$', message='hanya yang mengandung karakter alphanumeric')
email = models.EmailField(verbose_name='email address', unique=True, max_length=244)
username = models.CharField(unique=True, max_length=20, validators=[alphanumeric])
first_name = models.CharField(max_length=30, null=True, blank=True)
last_name = models.CharField(max_length=30, null=True, blank=True)
date_of_birth = models.DateTimeField()
date_joined = models.DateTimeField(auto_now_add=True)
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email']
def get_full_name(self):
fullname = self.first_name+" "+self.last_name
return self.fullname
def get_short_name(self):
return self.username
def list_operator(self):
return self.operators.all()
def __str__(self):
return self.email
class Operator(models.Model):
person = models.ForeignKey(Person, related_name="operators", null=True)
alphanumeric = RegexValidator(r'^[0-9a-zA-Z]*$', message='hanya yang mengandung karakter alphanumeric')
email = models.EmailField(verbose_name='email address', unique=True, max_length=244)
username = models.CharField(unique=True, max_length=20, validators=[alphanumeric])
first_name = models.CharField(max_length=30, null=True, blank=True)
last_name = models.CharField(max_length=30, null=True, blank=True)
date_of_birth = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.username;
i want to know where my code is wrong.
can you help me solved this problem?
Your code isn't wrong. Just follow the instructions provided by the message...
The person field within your Operator model can't be null (because null=True isn't set). You must already have Operators in your database, so Django doesn't know what to do with those.
You need to either: (a) provide a default value in your model, (b) provide a default during the migration process, or (c) enable null values for that field.

Django custom user

I created custom user
class CoinUser(AbstractBaseUser):
username = models.CharField(_('username'), max_length=30, unique=True,
help_text=_('Required. 30 characters or fewer. Letters, numbers and #/./+/-/_ characters'),
validators=[
validators.RegexValidator(re.compile('^[\w.#+-]+$'), _('Enter a valid username.'), _('invalid'))
])
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
first_name = models.CharField(_('first name'), max_length=30, blank=True, null=True)
patronymic = models.CharField(_('patronymic'), max_length=30,
help_text=_('Required. 30 characters or fewer. Letters, numbers and #/./+/-/_ characters'))
last_name = models.CharField(_('last name'), max_length=30, blank=True, null=True)
email = models.EmailField(_('email address'), max_length=255, unique=True,
validators=[
validators.RegexValidator(re.compile('^.+#.+\..+$', flags=re.IGNORECASE), _('Enter a valid email.'), _('invalid'))
])
post_code = models.CharField(_('post code'), max_length=10)
is_staff = models.BooleanField(_('staff status'), default=False,
help_text=_('Designates whether the user can log into this admin site.'))
is_active = models.BooleanField(_('active'), default=False,
help_text=_('Designates whether this user should be treated as active. Unselect this instead of deleting accounts.'))
date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
phone = models.CharField(_('phone number'), max_length=12, blank=True, null=True, unique=True,
validators=[
validators.RegexValidator(re.compile('^[0-9]{12,12}$', flags=re.IGNORECASE), _('Enter a valid phone number.'), _('invalid'))
])
objects = CoinUserManager()
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email', 'phone']
def get_full_name(self):
full_name = '%s %s' % (self.first_name, self.last_name)
return full_name.strip()
def get_short_name(self):
return self.first_name
def __str__(self):
return self.username
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
#property
def is_staff(self):
return self.is_admin
class Meta:
managed = True
db_table = "co_user"
verbose_name = _("Coin user")
verbose_name_plural = _("Coin users")
then I created UserAdmin
class CoinUserAdmin(UserAdmin):
form = UserChangeFrom
add_form = UserCreationForm
list_display = ('email', 'username', 'phone')
list_filter = ('is_admin',)
fieldsets = (
(None, {'fields': ('username',)}),
('Contact info', {'fields':('email','phone')}),
)
search_fields = ('username', 'email', 'phone')
ordering = ('username', 'email',)
filter_horizontal = ()
and added UserCreationForm
class UserCreationForm(forms.ModelForm):
"""docstring for UserCreationForm"""
password1 = forms.CharField(label=_('Password'), widget=forms.PasswordInput)
password2 = forms.CharField(label=_('Password confirmation'), widget=forms.PasswordInput)
class Meta:
model = CoinUser
fields = ('email', 'password', 'username', 'phone')
def clean_password2(self):
#Check that two password entires match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError(_("Passwords don't match"))
return password2
def save(self, commit=True):
#Save the provided password in hashed format
user = super(UserCreationForm, self).save(commit=False)
# user.phone = self.cleaned_data["phone"]
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
It works fine but when I tried to add email and phone
email = forms.CharField(label=_("Email"), widget=forms.EmailField)
phone = forms.CharField(label=_("Phone number"), widget=forms.TextInput)
fields to UserCreationForm they didn't view and when I tried to save my user without these field I got error "'EmailField' object has no attribute 'value_from_datadict'"
EmailField actually is form field. Try to use EmailInput widget.

django custom user model referencing to groups and permissions

I have made a custom User model..
class User(AbstractBaseUser, PermissionsMixin):
username = models.CharField(_('username'), max_length=30, unique=True,
help_text=_('Required. 30 characters or fewer. Letters, numbers and #/./+/-/_ characters'),
validators=[
validators.RegexValidator(re.compile('^[\w.#+-]+$'), _('Enter a valid username.'), _('invalid'))
])
first_name = models.CharField(_('first name'), max_length=30, blank=True, null=True)
last_name = models.CharField(_('last name'), max_length=30, blank=True, null=True)
email = models.EmailField(_('email address'), max_length=255)
is_staff = models.BooleanField(_('staff status'), default=False,
help_text=_('Designates whether the user can log into this admin site.'))
is_active = models.BooleanField(_('active'), default=False,
help_text=_('Designates whether this user should be treated as active. Unselect this instead of deleting accounts.'))
'''
groups = models.ManyToManyField(Group, verbose_name=_('groups'),
blank=True, help_text=_('The groups this user belongs to. A user will '
'get all permissions granted to each of '
'his/her group.'),
related_name="tmp_user_set", related_query_name="user")
user_permissions = models.ManyToManyField(Permission,
verbose_name=_('user permissions'), blank=True,
help_text=_('Specific permissions for this user.'),
related_name="tmp_user_set", related_query_name="user")
'''
date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
objects = UserManager()
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email',]
class Meta:
verbose_name = _('user')
verbose_name_plural = _('users')
def get_full_name(self):
full_name = '%s %s' % (self.first_name, self.last_name)
return full_name.strip()
def get_short_name(self):
return self.first_name
def email_user(self, subject, message, from_email=None):
send_mail(subject, message, from_email, [self.email])
Here when I reference groups to Group and user_permissions to Permission it gives error. How can I get these groups and permissions when I add it from admin side.
And when I make another model like Hospital and Inherit it from User like Hospital(User) then can I get the field of User in Hospital.
Any help ??

Categories