How to not require extended user model fields for a superuser - django

I have extended the in built user model in django via AbstractUser. However when it cam to deployment and to create a superuser it failed because of having a null entry in some of the additional fields in the extended model. Is there a way to have these fields not required for a superuser but required for a normal user. (I presume this is a typical use case - as I don't need an admin to fill out address, account number etc...)
models.py
class User(AbstractUser):
title = models.CharField(max_length=255, null=True)
date_of_birth = models.DateField()
phone_number = models.IntegerField(null=True)
account_name = models.CharField(max_length=255)
account_number = models.IntegerField()
house_name_number = models.CharField(max_length=255, verbose_name="house name or number")
street_name = models.CharField(max_length=255)
town_city = models.CharField(max_length=255)
county = models.CharField(max_length=255)
postcode = models.CharField(max_length=8)

Instead of using mandatory fields in models, you have to set them to optional using null=True, blank=True and let the validation happen in forms. For users other than admin create a form that checks for extra fields andvalidate those fields. Render this form through templates at the time of signup/registration. Also instead of using modelforms use forms.Form this will give you a better level of customization. This will make extra fields mandatory for all users other than Admin.

Related

Filtering Django query filtering

I'm doing some querying currently and I was wondering if I would be able to query something from these 3 models where the return would give me all the projects the users are working on. I know about the basic filtering however thats not really enough in this case, how would one go about querying through 2 foreign keys.
class User(models.Model):
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
email = models.EmailField()
class ProjectUser(models.Model):
project = models.ForeignKey("Project", on_delete=models.CASCADE)
user = models.ForeignKey("User", on_delete=models.CASCADE)
is_lead = models.BooleanField(default=False)
class Meta:
unique_together = (("project", "user"),)
class Project(models.Model):
name = models.CharField(max_length=255)
client = models.CharField(max_length=255)
complete = models.BooleanField(default=False)
You can obtain the Projects a user is working on with:
Project.objects.filter(
projectuser__user=user
)
The double underscores are used to look "through" relations. Furthermore the default related_query_name=… parameter [Django-doc] is, if not specified, the name of the model in lowercase.

Best practices for extending Custom User Model in django

I have a Custom User model in my app
class User(AbstractBaseUser, PermissionsMixin):
uuid = models.UUIDField(default=uuid.uuid4, unique=True)
email = models.EmailField(_('email address'), db_index=True, unique=True)
and this AUTH_USER_MODEL = 'users.User' in my settings file.
Now I want to create a model on the top of this custom user model(User), lets call it Agent, this model will have three columns:
user_uuid #Foreign Key Refernce(OnetoOne) to the Custom User Model
uuid # unique identifier for Agent model
scope # CharField specific to Agent model
What is the best way to do that?
While there is no best practice, it all depends on what you are doing, the most likely to work method is a type field specifying Agent and a one-to-one table (docs) for extra fields.
It'll be up to you to create the records as-needed. There isn't anything special about what you are doing just because it is a user.
class AgentDetails(Model):
user = OneToOneField(User, primary_key=True, on_delete=CASCADE)
...
A more complete user model would look something like this:
class User(AbstractBaseUser, PermissionsMixin):
USERNAME_FIELD = 'email'
EMAIL_FIELD = 'email'
REQUIRED_FIELDS = ["name"]
email = EmailField(unique=True, db_index=True)
name = CharField(max_length=100)
type = ChoiceField(choices=[('user','User'),('agent','Agent')])
is_staff = models.BooleanField(default=False, help_text='If the user can log into this admin site.')
is_active = models.BooleanField(default=True, help_text='If the user is active, instead of deleting')
created_at = models.DateTimeField('Date Joined', default=timezone.now)
objects = MyUserManager() #
In addition, you are probably going to need to add:
Custom admin page
Custom UserManager
You can derive one table from an abstract base, but this will generate 1 table for each user type which will not work with the standard authentication. For info, see Django's Model Inheritance.
class User(Model):
email = EmailField()
class Meta:
abstract = True
class Agent(User): # generates table 1
extra_field = CharField()
class Standard(User): # generates table 2
extra_field = CharField()
If the user model you have given is complete, then I don't think it will work with the default django infrastructure. From your question its not clear if you need help on that.

How To? django model field whose value is a choice of a manytomany field of the same model

I have a django model called company with a manytomany field where company members are added.
I have another field, called 'company_contact' where I want to be able to choose from one of the company_members as if it was a ForeingKey to company_members.
Is there an easy way of doing this without customized forms, ajax request, django-autocomplete-light, etc?
I intend to fill this model using django admin.
Thanks
class Dm_Company(models.Model):
company_name = models.CharField(max_length=80, blank=True, verbose_name="Razon Social")
company_members = models.ManyToManyField(conf_settings.AUTH_USER_MODEL, verbose_name="Miembros")
#company_contact = models.ForeignKey(conf_settings.AUTH_USER_MODEL, related_name="company_members", on_delete=models.CASCADE)
company_phone = models.CharField(max_length=80, blank=True, verbose_name="Telefono compania")
company_email = models.CharField(max_length=80, blank=True, verbose_name="Email compania")
The one way that I can think of would be to use a ManyToMany with a through model.
class Dm_Company(models.Model):
company_name = models.CharField(max_length=80, blank=True, verbose_name="Razon Social")
company_members = models.ManyToManyField(conf_settings.AUTH_USER_MODEL, through='CompanyMembership')
...
class CompanyMembership(models.Model):
company = models.ForeignKey(Dm_Company)
user = models.ForeignKey(conf_settings.AUTH_USER_MODEL)
is_contact = models.BooleanField(default=False)
The difficulty with this model is that you need to write logic to prevent more than one CompanyMember from being set as is_contact. However, it does structure your data model such that there's no way for the company_contact to reference a user in a different company.
There is no way to filter the company_contact queryset in the way you describe. An alternative is to add the following to your model:
def clean_fields(self, exclude=None):
super().clean_fields(exclude=exclude)
if not self.company_members.exists(id=self.company_contact_id):
raise ValidationError('contact is not member')
That will prevent a contact being selected that is not a member

Django ModelForm: Huge ForeignKey queryset leads to crash when loading form

Basically, I have two models: User and Event. An event is always associated with one user.
class User(models.Model):
user_id = models.AutoField(primary_key=True)
username = models.CharField(max_length=255, unique=True)
hashed_password = models.CharField(max_length=255)
class Event(models.Model):
event_id = models.AutoField(primary_key=True)
title = models.CharField(max_length=255)
description = models.TextField(max_length=255, blank=True, default='')
user = models.ForeignKey(User)
And then I have the following form for Event.
class EventForm(forms.ModelForm):
class Meta:
model = Event
fields = ['title', 'description', 'user']
I can succesfully show this form in my template to create an event. I can also associate a user to a form successfully with Select field when the users number are still few.
Now the problem is, when I have 1M users in database, my browser crashes when loading the template. Any idea how to solve this one? I was thinking about using AJAX and then search user that matches the username, but I'd like to hear other better approaches. Thanks!

ManyToManyField with extra information

I'm working on a django website and I need to store some information about the user like a isVerified BooleanField and a profile picture in an ImageField as well as ratings which stores ratings a user has given different elements. So I made a model like this:
class UserProfile(AbstractBaseUser):
is_verified = models.BooleanField(default=True)
current_profile = models.ImageField(default=static('img/default_profile.jpg'))
ratings = models.ManyToManyField(Element, on_delete=models.CASCADE)
however I'd like to save some more about these ratings (like a timestamp and the actual value the user rated)
Do I need to make a seperate model just for that or can this be acchieved in a better way?
You need to use intermediary table that can be specified via the through keyword.
For example:
class UserProfile(AbstractBaseUser):
is_verified = models.BooleanField(default=True)
current_profile = models.ImageField(default=static('img/default_profile.jpg'))
ratings = models.ManyToManyField(Element, on_delete=models.CASCADE, through='UserProfileElement')
class UserProfileElement(models.Model):
user = models.ForeignKey(UserProfile, models.CASCADE, verbose_name=_('User'))
element = models.ForeignKey(Element, models.CASCADE, verbose_name=_('Element'))
timestamp = models.DateTimeField(_('Timestamp'), auto_now_add=True)
rating = models.PositiveIntegerField(_('Rating'))
class Meta:
unique_together = ('user', 'element')
Django docs: ManyToManyField.through