I have a custom user model and a company model:
class User(AbstractUser):
username = None
email = models.EmailField(_('email address'), unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = UserManager()
company = models.ForeignKey(
Company, null=True, blank=False, on_delete=models.SET_NULL)
class Company(models.Model):
company_name = models.CharField(
default='', max_length=128, blank=True, null=True)
In settings.py I also have a customer_name constant:
CUSTOMER_NAME = os.environ.get('CUSTOMER_NAME')
How can I add a condition in my user model so that if the user is_staff boolean is TRUE then the company_name is fixed to be the CUSTOMER_NAME constant?
Do you have two options:
1) Option 1: Overriding save ( Overriding predefined model methods )
from django.conf import settings
class User(AbstractUser):
username = None
...
company = models.ForeignKey(
Company, null=True, blank=False, on_delete=models.SET_NULL)
def save(self, *args, **kwargs):
if self.is_staff:
#company_name = os.environ.get('CUSTOMER_NAME')
company_name = settings.CUSTOMER_NAME
target = Company.objects.get_or_create( company_name = company_name )
serf.company = target
super().save(*args, **kwargs) # Call the "real" save() method.
2) Option 2: Using pre-save signal:
from django.db.models.signals import pre_save
from django.dispatch import receiver
from django.conf import settings
#receiver(pre_save, sender=User)
def my_handler(sender, **kwargs):
if self.is_staff:
#company_name = os.environ.get('CUSTOMER_NAME')
company_name = settings.CUSTOMER_NAME
target = Company.objects.get_or_create( company_name = company_name )
serf.company = target
The best approach to do this is to override the save function of your model like this:
class User(AbstractUser):
username = None
email = models.EmailField(_('email address'), unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = UserManager()
company = models.ForeignKey(
Company, null=True, blank=False, on_delete=models.SET_NULL)
def save(self, force_insert=False, force_update=False, using=None,
update_fields=None):
if self.instance.id is None and self.is_staff is True: # instance.id is None indicates the instance is new and not an existing one
constant_company = Company('company_name'=CUSTOMER_NAME) # You could also search for an existing company with the CUSTOMER_NAME
constant_company.save()
self.company = constant_company
super().save(force_insert, force_update, using, update_fields)
This way will ensure you each time a staff user is saved no matter where a company with your constant name will be linked to it.
Related
I have user model that has a one to one relation with two other models.
these are my models:
class User(AbstractUser):
id = models.AutoField(primary_key=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
isPreRegistered = models.BooleanField(default=False)
username = models.CharField(unique=True, max_length=13)
first_name = models.CharField(max_length=32, null=True, default=None)
last_name = models.CharField(max_length=64, null=True, default=None)
progress_level = models.CharField(max_length=25, null=True, choices=USER_PROGRESS_LEVELS)
class ScientificInfo(models.Model):
id = models.AutoField(primary_key=True)
user = models.OneToOneField(User, on_delete=models.CASCADE)
final_assessment = models.TextField(null=True, blank=True)
is_interviewed = models.BooleanField(default=False)
class PsychologicInfo(models.Model):
id = models.AutoField(primary_key=True)
user = models.OneToOneField(User, on_delete=models.CASCADE)
final_assessment = models.TextField(null=True, blank=True)
is_interviewed = models.BooleanField(default=False)
I want to update the user's progress_level if PsychologicInfo.is_interviewed and ScientificInfo.is_interviewed are both True. So I thought I should override the save method and added this to the user model:
def save(self, *args, **kwargs):
if self.scientificinfo.is_interviewed == True and self.psychologicinfo.is_interviewed == True:
self.progress_level = USER_PROGRESS_LEVELS[1][0]
return super(User, self).save(*args, **kwargs)
But I have to save the User object one more time to see some results. how can I update my progress level field when PsychologicInfo and ScientificInfo get saved?
I think you can use the Django signals a post_save can be what you need.
U can make a check if the instance PsychologicInfo or ScientificInfo
are updated or created then update the progress
voila an example of what you may want:
from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import PsychologicInfo, ScientificInfo
# import your choices USER_PROGRESS_LEVELS
#receiver(post_save, sender=PsychologicInfo)
def pre_save_receiver(sender, instance, *args, **kwargs):
if instance:
if instance.psychologicinfo.is_interviewed:
instance.progress_level = USER_PROGRESS_LEVELS[1][0]
# Do other operation ...
You duplicate the this code by changing the sender and change the logique of your condition. it should work just fine
I am creating an API. When i create a new user, or edit an existing user and save, i get this error
"AttributeError at /admin/accounts/user/1/change/
'User' object has no attribute 'profile"
For clarity, I have a user model and a profile model lied o my User model with a onetoone relationship.
Here is my User model
artist_name = models.CharField(
max_length=255,
default='artist name',
unique=True
)
slug = models.SlugField(max_length=250, null=True, blank=True)
email = models.EmailField(max_length=300, unique=True)
active = models.BooleanField(default=True)
staff = models.BooleanField(default=False)
admin = models.BooleanField(default=False)
date_joined = models.DateTimeField(auto_now_add=True)
last_login = models.DateTimeField(auto_now_add=True)
My Profile model
class Profile(models.Model):
user = models.OneToOneField(
User,
on_delete=models.CASCADE,
related_name="user",
default=1
)
first_name = models.CharField(max_length=255, blank=True, null=True)
last_name = models.CharField(max_length=255, blank=True, null=True)
country = models.CharField(max_length=500, blank=True, null=True)
gender = models.CharField(max_length = 20, blank=True, null=True)
record_label = models.CharField(max_length=255, blank=True, null=True)
image = models.FileField()
And my signals
from .models import User, Profile
from django.dispatch import receiver
#receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_profile(sender, instance, **kwargs):
instance.profile.save()
I should also mention that I don't have views for my user and profile yet. But i don't think that should affect the admin area.
So far i have searched online but nothing worked.
Thank you in anticipation.
i would advice you not to create a seperate user model, rather use the default User model. note that some of the features you need on your Profile model are actually present in the User model. in User model you have first_name, last_name,email,username, password1 and password2 by default but if you only what to use the User model you specified then follow the steps. so in your profile model the fields you should specify should be as follows:
from django.contrib.auth.models import User
from .models import User, Profile
from django.dispatch import receiver
from django.db.models.signals import post_save
class User(models.Model):
artist_name = models.CharField(max_length=255, default='artist name', unique=True)
slug = models.SlugField(max_length=250, null=True, blank=True)
email = models.EmailField(max_length=300, unique=True)
active = models.BooleanField(default=True)
staff = models.BooleanField(default=False)
admin = models.BooleanField(default=False)
date_joined = models.DateTimeField(auto_now_add=True)
last_login = models.DateTimeField(auto_now_add=True)
class Profile(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE)
country = models.CharField(max_length=500, blank=True, null=True)
gender = models.CharField(max_length = 20, blank=True, null=True)
record_label = models.CharField(max_length=255, blank=True, null=True)
image = models.ImageField()
#receiver(post_save, sender=User)
def create_profile(sender, instance, created, *args, **kwargs):
if created:
Profile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_profile(sender, created, instance, **kwargs):
if not created:
instance.profile.save()
I hope this helps and if it does vote up this answer and give response.
I am new to django. Currenty I am trying to make social network website. Here is my model of profile class. I want to assign value of slug field to the username of the User. But can't find or think of any way to do this.
If anyone know any way of doing this I'll be thankfull if you suggest me how to do this
from django.contrib.auth.models import User
from django_countries.fields import CountryField
from django.db import models
class Profile(models.Model):
GENDER = [
('NONE', 'none'),
('MALE', 'male'),
('FEMALE', 'female')
]
first_name = models.CharField(max_length=100, blank=False)
last_name = models.CharField(max_length=100, blank=True)
email = models.EmailField(max_length=200, blank = True)
bio = models.TextField(default='No bio data', max_length=400)
user = models.OneToOneField(User, on_delete = models.CASCADE)
gerder = models.CharField(max_length=6, choices=GENDER, default='NONE')
country = CountryField()
avatar = models.ImageField(default='avatar.png', upload_to='avatars/')
friends = models.ManyToManyField(User, blank = True, related_name='friends')
slug = models.SlugField(unique = True, blank = True)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
favourite = models.CharField(max_length=300, blank=True)
def __str__(self):
return f'{self.user.username}-{self.created}'
```
I like using Django Autoslug https://pypi.org/project/django-autoslug/
pip install django-autoslug
After install, make sure you import it in your models.py file
from autoslug import AutoSlugField
Here is how the slug would look in your case:
slug = AutoSlugField(populate_from='user')
found out that using this in profile class will automatically assign username of the user
def save(self, *args, **kwargs):
self.slug = slugify(self.user.username)
super().save(*args, **kwargs)
this is my final profile class
from django_countries.fields import CountryField
from django.db import models
from django.template.defaultfilters import slugify
class Profile(models.Model):
GENDER = [
('NONE', 'none'),
('MALE', 'male'),
('FEMALE', 'female')
]
first_name = models.CharField(max_length=100, blank=False)
last_name = models.CharField(max_length=100, blank=True)
email = models.EmailField(max_length=200, blank = True)
bio = models.TextField(default='No bio data', max_length=400)
user = models.OneToOneField(User, on_delete = models.CASCADE)
gerder = models.CharField(max_length=6, choices=GENDER, default='NONE')
country = CountryField()
avatar = models.ImageField(default='avatar.png', upload_to='avatars/')
friends = models.ManyToManyField(User, blank = True, related_name='friends')
slug = models.SlugField(unique = True, blank = True)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
favourite = models.CharField(max_length=300, blank=True)
def __str__(self):
return f'{self.user.username}-{self.created}'
def save(self, *args, **kwargs):
self.slug = slugify(self.user.username)
super().save(*args, **kwargs)
```
I am working with slug on my model. Although, the entries for slug are not unique. When I try to go to a url containing slug, it says get() returned more than one object and I understand that it is because the entries are not unique. How am I supposed to change the slug a bit, if identical entries occur?
model
class Cabin(models.Model):
centre_name = models.ForeignKey(Centre, on_delete=models.CASCADE )
code = models.CharField(max_length=8, unique=True, default=unique_rand)
total_seats = models.IntegerField(blank='False')
category=models.CharField(max_length=100, default=False)
booked_date=models.DateField(blank='False')
released_date=models.DateField(blank='False')
price=models.IntegerField(blank=False, default=None)
slug = models.SlugField(unique=False,default=None,blank=True)
objects = UserManager()
def save(self, *args, **kwargs):
self.slug = slugify(self.category)
super(Client, self).save(*args, **kwargs)
First of all it might be better to set unique=True, such that this can never happen, furthermore you can :
class Cabin(models.Model):
centre_name = models.ForeignKey(Centre, on_delete=models.CASCADE )
code = models.CharField(max_length=8, unique=True, default=unique_rand)
total_seats = models.IntegerField(blank='False')
category=models.CharField(max_length=100, default=False)
booked_date=models.DateField(blank='False')
released_date=models.DateField(blank='False')
price=models.IntegerField(blank=False, default=None)
slug = models.SlugField(unique=True,default=None,blank=True)
objects = UserManager()
def save(self, *args, **kwargs):
slug = originalslug = slugify(self.category)
i = 0
while Cabin.objects.exist(slug=slug):
slug = '{}{}'.format(originalslug, i)
i += 1
self.slug = slug
super(Client, self).save(*args, **kwargs)
We here thus increment i until we found a slug that is not yet used.
Note that there exists an AutoSlugField in the django-extensions package [PyPi], that automates this slug procedure. For example:
from django.db import models
from django_extensions.db.fields import AutoSlugField
class Cabin(models.Model):
centre_name = models.ForeignKey(Centre, on_delete=models.CASCADE )
code = models.CharField(max_length=8, unique=True, default=unique_rand)
total_seats = models.IntegerField(blank='False')
category=models.CharField(max_length=100, default=False)
booked_date=models.DateField(blank='False')
released_date=models.DateField(blank='False')
price=models.IntegerField(blank=False, default=None)
slug = AutoSlugField(populate_from='category')
objects = UserManager()
I have following users in my Django applications:
1. Normal user (UUID, email, name, address, password)
2. Remote application (UUID, name, generated random secret)
3. (other type of remote application)
The authentication for the Normal user would be with webpage email + password
The authentication for the Remote application would be with UUID + random secret with JSON to ask for the temporary token
I do not know how to handle this in Django. I wanted to create AuthBaseUser from AbstractBaseUser like:
class AuthBaseUser(AbstractBaseUser, PermissionsMixin):
pk = models.UUIDField(primary_key=True, unique=True, default=uuid.uuid4, editable=False,)
name = models.CharField(_('name'), max_length=128, blank=False)
typ = models.CharField(max_length=16, choices=USER_TYPES, default='normaluser',)
date_joined = models.DateTimeField(_('date joined'), auto_now_add=True, default=timezone.now)
last_login = models.DateTimeField(_('last login'), auto_now_add=True)
is_active = models.BooleanField(_('active'), default=True)
Then I wanted to create a RemoteAppUser and NormalUser with 1:1 mapping like this:
class NormalUser(AuthBaseUser):
user = models.OneToOneField(AuthBaseUser, on_delete=models.CASCADE)
email = models.EmailField(_('email address'), unique=True)
is_superuser = models.BooleanField(_('superuser'), default=True)
#password = #not decided yet what to add here; for remote app we will have 256b of SHA256's random generated value
EMAIL_FIELD = 'email'
REQUIRED_FIELDS = AuthBaseUser.REQUIRED_FIELDS.append(['email', 'password', ])
objects = NormalUserManager()
def __init__(self, *args, **kwargs):
super(AuthBaseUser, self).__init__(*args, **kwargs)
def __str__(self):
return self.get_username()
def get_full_name(self):
return self.get_username()
def get_short_name(self):
return self.get_username()
Of course, I have to add the default auth user:
AUTH_USER_MODEL = 'myauth.AuthBaseUser'
Is there any recommended way to handle such different users?
Note that for example I would like store the RemoteApp's secret as SHA256, but I do not need to run the permutations several times with seed etc.
may be just create something like this:
class User(AbstractBaseUser, PermissionsMixin):
name = models.CharField(_('name'), max_length=128, blank=False)
is_normal = models.BooleanField(default=False)
is_other = models.BooleanField(default=False)
and one class for two types of the authentications, and just check is_normal user or is_other user
UPDATE:
try like this:
class EnterpriseEntry(models.Model):
user = models.ForeignKey('User', null=False, blank=False, verbose_name=u'Пользователь',
related_name='enterprise_entries')
position = models.CharField(
max_length=100, default="", blank=True, verbose_name=u'Позиция в компании')
ADMIN_ENTERPRISE = 0
USER = 1
ENTREPRENEUR = 2
UNKNOWN = 3
MODERATOR = 4
PROFILE_TYPES = (
(ADMIN_ENTERPRISE, u'Руководитель юридического лица'),
(USER, u'Пользователь приглашенный в предприятие'),
(ENTREPRENEUR, u'Индивидуальный предприниматель'),
(MODERATOR, u'Модератор компании'),
(UNKNOWN, u'Не известно'),
)