I created a working "Log in with facebook" setup with django-allauth. However, I want those new user accounts that allauth creates to not be activated automatically.
Basically I want to activate all new accounts from the Django admin pages.
What would be a best practice solution to this?
Thanks
How do you know that an account is activated or not? You need some kind of field in your User model.
Let's say that your field is called is_activated:
class User(BaseUser):
is_activated = models.BooleanField(default=False)
and that's it. This field's default value will be False which means that a created user is not activated by default.
Then, you can add this field to the admin page and toggle it from there.
Hope it helps!
I'd suggest what follows because when I made cogofly I had this huge problem where some people (few but some of them do) click sometimes on "log in with google" and sometimes on "log in with facebook" and this is the same person! So be careful with that and this solution will help you to avoid such problem. The only thing to remember: there's only one primary key for all social networks: the email.
Like it's written in the documentation, I'd make a OneToOne link to the User model.
From this I would suggest this:
precise the date of the first login
precise the date of the last login
precise if the account has been validated
Like this:
from django.contrib.auth.models import User
class Person(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
is_activated = models.BooleanField(default=False)
And make a social login model where you precise how the user logged in:
class SocialLogin(BaseModel):
S_GOOGLE = 1
S_FACEBOOK = 2
TAB_S_LOGIN = {
S_GOOGLE: _("Google"),
S_FACEBOOK: _("Facebook"),
}
logged_in = models.IntegerField(
choices=[(a, b) for a, b in list(TAB_S_LOGIN.items())],
default=S_GOOGLE)
date_first_login = models.DateTimeField(auto_now_add=True,
verbose_name=_('First login'))
date_last_login = models.DateTimeField(auto_now=True,
verbose_name=_('Last login'))
person = models.OneToOneField(Person, on_delete=models.CASCADE)
def logged_in_desc(self):
return SocialLogin.TAB_S_LOGIN[self.logged_in]
def __str__(self):
return '{} / {}'.format(
self.logged_in_desc(),
description if self.description is not None else '?')
Related
I am building a BlogApp and I am trying to get all the users that's profile's BooleanField are True.
What i am trying to do:-
I made a feature of Users that are banned and I made a BooleanField for each user, AND i am trying to get all the Users that's profile's BooleanValue is True.
models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE,default='',unique=True)
block_users = models.BooleanField(choices=BLOCK_CHOISES,default=False)
The Problem
def block_users(request):
profile = request.user.profile
blocked = Profile.objects.filter(block_users=profile.block_users)
context = {'blocked':blocked}
return render(request, 'blocked.html', context)
When i runthis code, This only shows me user that's value is False. BUT i want users that's Value is True.
I have no idea how to get it.
Thanks in Advance.
Any help would be Appreciated.
It looks like you are trying to list out users as per logged in user. I mean, if logged in user is Blocked, it will list blocked users and if not it will list not-blocked users.
this instead:
In your models.py, create a related_name
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="profile_user",unique=True)
block_users = models.BooleanField(choices=BLOCK_CHOISES,default=False)
In views.py, when you will do "request.user.profile_user.block_users", it will give logged in users blocking status.
Now, if you want users which are blocked, filter directly with True.
Profile.objects.filter(block_users=True)
I have 2 types of users on my site, one is the store owner, I want to log him in with the usual custom user email and password, the other is the buyer, I want to login the buyer using just a pin number only. Is it possible to have both types of login users in the same django app. Thanks in advance.
class Store(models.Model):
store_name = models.CharField(max_length=200)
store_status = models.BooleanField()
store_details = models.CharField(max_length=300, blank = True)
store_balance = models.IntegerField(default=0)
user = models.OneToOneField(User, on_delete=models.CASCADE)
college = models.ForeignKey(Institute, on_delete=models.CASCADE )
def __str__(self):
return str(self.store_name)+" "+ str(self.store_status)
class Customer(models.Model):
name = models.CharField(max_length=200)
branch = models.CharField(max_length=200, choices=BRANCHES)
sem = models.CharField(max_length=200, choices=SEMESTERS)
reg_no = models.IntegerField(default=0)
balance = models.IntegerField(default=0)
pin_no = models.IntegerField()
college = models.ForeignKey(Institute, on_delete=models.CASCADE )
To make a custom authentication you need to add an Authentication Backend. Firstly your customer model is not related to your user model try adding a OnetoOne field in that. After that try adding code like this in one of your apps:-
from django.contrib.auth.backends import BaseBackend
class MyBackend(BaseBackend):
def authenticate(self, request, token=None):
try:
customer = Customer.objects.get(pin_no=token)
user = customer.user
except Customer.DoesNotExist:
return None
return user
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
Refer the documentation on Customizing authentication in Django for more information.
Now after making an AuthenticationBackend you need to make it so that Django uses it, you do this by adding it to AUTHENTICATION_BACKENDS in your settings.py, since you want the default username and password to remain something like this would work:
AUTHENTICATION_BACKENDS = ['django.contrib.auth.backends.ModelBackend', 'path.to.MyBackend']
You have several ways for this. One is making an index place where they choose the option "owner" or "buyer" and after ask for login auth. Other approach is to make url specifying those options already. If you want to do it in the same "form" you could add specification under the hood for manage this input data provided also could be done by several ways, or make a checkbox like so it changes form input. Choose the one that suits you. Does this help you?
I have this model in accounts.models:
from django.contrib.auth.models import User
class UserProfile(BaseModel):
user = models.OneToOneField(
User, related_name="user_profile", on_delete=models.CASCADE
)
# ...
def __str__(self) --> str:
return self.user.username
And the following in memberships.models:
class ExternalServiceProfileMembership(BaseModel):
created_at = models.DateTimeField()
expires_at = models.DateTimeField()
profile = models.ForeignKey(
"accounts.UserProfile",
on_delete=models.CASCADE,
related_name="ext_memberships",
)
plan = models.ForeignKey("memberships.MembershipPlan", on_delete=models.CASCADE)
ext_subscription_id = models.CharField(max_length=128)
When I try to access the admin view of an individual ExternalServiceProfileMembership object (for example: http://localhost:8000/admin/memberships/externalserviceprofilemembership/1/change/), the site gets stuck, eventually returning a 503. So I started out commenting out fields in the AdminModel, and once I remove profile, the object change view loaded fine.
I brought back profile into AdminModel but removed UserProfile's __str__() method, and it also worked. Which makes me think the whole issue is with this method; but I have no idea why.
Any help is appreciated!
On the change page for ExternalServiceProfileMembership, the profile dropdown displays the name of every user. This causes one extra query for every user in the dropdown.
The quick fix is to add 'profile' to readonly_fields, autocomplete_fields or raw_id_fields. These three options mean that a single profile is displayed on the change form, so there is only one extra query to fetch the user.
Another approach, which is more complicated, is to create a custom form that overrides the queryset to use select_related to fetch all of the users, then use that form in your model admin.
I am just learning Django so I thought of creating a project called job board to understand more in detail. I have drawn the following use case.
People can register as job seekers, build their profiles and look for
jobs matching their skillsets
Companies can register, post jobs.
Multiple representatives from a company should be able to register
and post jobs.
Independent Recruiter can create an account as well.
The company can contact to that independent recruiter.
How would be the model design for such a use case? I am confused with the multiple user types in Django. Some favors creating a user profile, while some favors using Groups.
For now, I could only do the following
class User(AbstractUser):
'''
Abstract user because django recommends to start with custom user
'''
username = None
email = models.EmailField(_("Email Address"), unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = UserManager()
def __str__(self):
return self.email
class Company(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
I could create a model for User and Company. But I have no idea on handling multiple user types like user can be either job seeker or recruiter. Also, multiple representatives from a company should be able to register and post jobs as well as there can be independent recruiter as well. How would you handle such a case if you have to? Can anyone help me in a step by step guide, please? This way it will clear my confusion and will help me in better design of tables in the future.
Update with example in a nutshell
class User(models.Model):
'''
User can be of any 3 types or can have multiple role as well
'''
is_job_seeker = models.BooleanField(default=False)
is_recruiter = models.BooleanField(default=False)
is_mentor = models.BooleanField(default=False)
class Company(models.Model):
user = models.ForeignKey(User) # only user with is_recruiter flag active can be
class JobSeeker(models.Model):
user = models.OneToOneField(User)
# job seeker profile related fields like experiences, skills, education, profile image etc
class Recruiter(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
company = models.ForeignKey(Company, null=True, blank=True)
# recruiter related profile
Your implementation is almost there. It doesn't look like you need a custom user model right now, so I would just use Django's default.
I would have something like:
from django.conf import settings
from django.db import models
class Company(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
# Other company-related fields
class JobSeeker(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
# Other jobseeker-related fields
class Recruiter(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
company = models.ForeignKey(Company, null=True, blank=True)
# Other recruiter-related fields
When you create any of the models above, you can assign them a user account; and for recruiter, you can assign the company they work for. For example, a company named stack_overflow can have its own company account with a username/password/etc. Then, recruiters who work for stack_overflow could also have their own accounts with their own username/password/etc. Running a command like stackoverflow.recruiter_set will give you all recruiters who work for stack_overflow.
Note that I do not reference User directly. Using the above approach makes your life easier if you decide to switch User models in the future.
I am assuming you don't want to create a User, then create a Company and link it to that user - you just want to do it in one go. That's a slightly different question and the solution will involve you creating a sign-up Form, or something of that sort, where you can add some logic about whether the user is a company, recruiter or jobseeker.
Regarding your other points, it looks like you're looking to set user permissions. Here are the docs for setting default permissions for your custom users, and here are the general docs for Django's built-in permissions system. For example, your Company and Recruiter model could return True for has_perm('your_app.add_job'), while your Jobseeker model returns False. I.e. Companies and Recruiters can create Jobs, but jobseekers cant.
Hope this helps!
I've been trying to learn django for the past couple of days, and I've made a basic bug tracking software as of now (using the admin part of django)
Ive created a table called bugs:
from django.db import models
# Create your models here.
class Bugs(models.Model):
STATUS_CHOICE = (
('Work In Progress', 'Work In Progress'),
('Incomplete', 'Incomplete'),
('Completed', 'Completed')
)
Project_Name = models.CharField(max_length=100)
Basic_Description = models.CharField(max_length=100)
Detailed_Description = models.TextField(default='The Description, here.')
Status = models.CharField(max_length=18, choices=STATUS_CHOICE)
Assigned_to = models.CharField(max_length=100)
Reported_by = models.CharField(max_length=50, blank=True, null=True)
Reporters_Mail_ID = models.CharField(max_length=50, blank=True, null=True)
Reported_Date = models.DateTimeField(null=True, blank=True)
Created = models.DateTimeField(auto_now_add=True, null=True, blank=True)
Updated = models.DateTimeField(auto_now=True, null=True, blank=True)
Deadline_Date = models.DateTimeField(null=True, blank=True)
image = models.FileField(null=True, blank=True)
def __str__(self):
return self.Project_Name + ' [' + self.Status + '] ' + self.Basic_Description + ' [' + self.Assigned_to + ']'
class Meta:
verbose_name_plural = "Bugs"
How do I make it so that when a project name is selected, the Assigned_to is also automatically selected?
And how do I make sure that once it is assigned to the person/ Status is edited/ or any sort of edit is made by the SuperUser, a mail is sent to the person it is assigned to, and when an edit is made by the Person it is assigned to, the super user gets a mail saying an edit has been made?
Not that important but, I was also wondering if there is any way to make sure that when the Super user Assigns some work to one of the admins, Only the admin specified can view the Issue??
UPDATE:
Let me try to be more descriptive this time..
So i have 2 types of users:
1st is the Super User who decides what bugs should be placed into the list and also manages the other users as well.
2nd is the other normal users, selected by the superuser (Users can only edit the posts added by the superuser)
The database has 12 columns out of which Project_Name and Assigned_To are 2.
My question is,
How do I make it such that when the superuser enters the Project_Name, the Assigned_To Column is already filled?
take this as an example
Project_Name: Project1 ---> Assigned_To: Person1
Project_Name: Project2 ---> Assigned_To: Person2
Project_Name: Project3 ---> Assigned_To: Person3
Project_Name: Project4 ---> Assigned_To: Person4
Now if the Super User Decides that the bug is in Project 1, and Project 1 is handled by Person 1, How do i make the program such that If Project 1 is chosen, Person 1 will automatically be selected in the Assigned_To Column?
And Once the SuperUser Selects the SAVE option(taking the same case as above). How do I make the program send a mail to Person1 when ever SuperUser Updates the database? And how do I make the program send a mail to the SuperUser when the Person1 Makes changes to the Database?
Well I'm not sure what your questions really are, but as I understood, you first need to add another field for user as following :
from django.contrib.auth import get_user_model
user = models.ForeignKey(get_user_model(), blank=True, null=True)
regarding sending email when an object of the model is saved or updated, you should override the save() method of the model and put the code you want to execute.
You can use django signals,
When the SuperUser saves or edits. You can write your code to achieve whatever you want.
from django.db.models.signals import post_save
def send_email(sender, instance, created, **kwargs):
# your code goes here...
post_save.connect(send_email, sender=Bugs)
ref: https://docs.djangoproject.com/en/2.0/ref/signals/#post-save
Ok, so first off, it's common practice to use all lower case for model fields. Python has a style guide called PEP8 which documents all the best practices for writing python. So take a look here to get started; https://www.python.org/dev/peps/pep-0008/#descriptive-naming-styles
Now if your assigned_to model should reference a user for the model to relate to you should indeed do as Milad said & use a ForeignKey to the User model because there are many benefits to using relationships where it makes sense for your data.
If you want the assigned_to to be automatically filled based on the project_name then you'd have to use javascript. You'd probably send an AJAX request on selection of the project to go to the backend with the project value. Then send back the assignee for that project which would be used in the javascript to set the value of the assigned_to field.
As far as sending emails go when changes are made to your model, you should use signals in python. Signals get fired when changes are made to objects, for example;
from django.core.mail import send_mail
from django.db.models.signals import post_save
from django.dispatch import receiver
from bugs.models import Bugs
#receiver(post_save, sender=Bugs)
def bugs_post_save(sender, instance=None, created=None, update_fields=None, **kwargs):
if created or 'assigned_to' in update_fields:
# We have a new object or the assignee has changed
send_mail(
'Subject here',
'Here is the message.',
'from#example.com',
['to#example.com'],
fail_silently=False,
)
The docs on email sending are here
Your receiver functions like this can be included underneath your models or in a specific signals.py module which you'd import in the application config. That would like something like;
# bugs/apps.py
from django.apps import AppConfig
class BugsConfig(AppConfig):
name = 'bugs'
verbose_name = "Bugs"
def ready(self):
# importing signals
import signals