Django inheritence question - django

some body please explain me the following i have two classes Userprofile and Staff.staff inherits userprofile
My Question is that if any entry has to be made to a staff table .1.It would be mandatory to fill out the details of user profile right?
Please explain this inheritence.Thanks
class Profile(models.Model):
user = models.ForeignKey(User, unique=True)
created_date = models.DateTimeField(auto_now_add=True)
emp_first_name = models.CharField(max_length=255)
emp_last_name = models.CharField(max_length=255)
gender = models.CharField(max_length=2, choices = GENDER_CHOICES, null=False)
date_of_birth = models.DateField(blank=True,null=True)
address1 = models.CharField(max_length=255)
city = models.CharField(max_length=48)
state = models.CharField(max_length=48)
country = models.CharField(max_length=48)
email_id = models.EmailField(blank=True)
class Staff(UserProfile):
role = models.ManyToManyField(Role)
designation = models.CharField(max_length=48, blank=True, null=True)
education = models.CharField(max_length=255, blank=True, null=True)

If you take a look at https://docs.djangoproject.com/en/dev/topics/db/models/#multi-table-inheritance you'll see that automatic One-to-One mappings are created. Therefore, an entry for UserProfile is saved, and an entry for Staff is saved with a OneToOne field that points to the UserProfile entry.
However, if you want Staff to just inherit all the fields, I'd recommend setting abstract = True in your UserProfile. This means that Staff inherits all those fields, but you can never create a UserProfile by itself (as described at
https://docs.djangoproject.com/en/dev/topics/db/models/#abstract-base-classes )
class Meta:
abstract = True

Related

Django: Get objects of first model by comparing attribute of second OneToOne related model

I have two models, User and Card. One user has one card. I need to get objects of User if the 'card_written' of Card model is False in a view.
class User(model.Model):
phone = PhoneNumberField(null=False, blank=False, unique=True)
email = models.EmailField(verbose_name="email", max_length=60, unique=True)
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
class Card(models.Model):
user = models.OneToOneField(User, null=True, blank=True, on_delete=models.CASCADE)
card_number = models.CharField(max_length=200)
card_written = models.BooleanField(default=False, null=False)
card_write_date = models.DateTimeField(null=True, blank=True)
card_delivered = models.BooleanField(default=False, null=False)
You can query on related models quite easily in Django by separating related fields by double underscores.
A query like this should work for you:
User.objects.filter(card__card_written=False)
Here card is the related name since you haven't specified it in the Card model if you want it to be something else you need to specify like so in the Card model:
user = models.OneToOneField(User, null=True, blank=True, on_delete=models.CASCADE, related_name='something_else')

Django admin - Filter foreignKey in an Inline

I have these models:
class Country(models.Model):
name = models.CharField(unique=True, max_length=50)
class Person(models.Model):
name = models.CharField(max_length=50, blank=True, null=True)
country = models.ForeignKey(Country, models.DO_NOTHING, db_column='countries', blank=True, null=True)
class Organization(models.Model):
name = models.CharField(max_length=50, blank=True, null=True)
class Membership(models.Model):
person= models.ForeignKey(Person, models.DO_NOTHING, db_column='people', blank=True, null=True)
organization= models.ForeignKey(Organization, models.DO_NOTHING, db_column='organizations', blank=True, null=True)
There are a high number of people (over 1000) that can be members of several organizations.
I have a view in the admin page as follows
class MembershipInline(admin.StackedInline ):
model = Membership
extra = 1
class OrganizationAdmin(admin.ModelAdmin):
inlines = [MembershipInline]
admin.site.register(Organization,OrganizationAdmin)
Therefore I can manage any organization and see the people that belongs to it. I can also add new people to the organization.
The problem is that the number of people is too high and the list shows too many of them. Is there any way to filter this StackedInline?
For example placing another field in the Inline where a country can be chosen to filter the people that can be added, or a search field to filter the person's name.
Thanks in advance!
Finally got to work using the option "autocomplete_fields "
class PersonAdmin(admin.ModelAdmin):
search_fields = ['country__name','name']
admin.site.register(Person,PersonAdmin)
class MembershipInline(admin.StackedInline ):
model = Membership
extra = 1
autocomplete_fields = ['person',]
How it looks

django charge users based on how many counties they want to access

I'm building a web app,
basically I currently have 3 models ,
1- State: which represents all US states
2- County: which represents all counties with foreign key of state
3- Home: which represents all homes with foreign key of County
the app will show homes,
but users needs to subscribe for certain counties (the counties prices can vary)
the goal is : when users subscribe to certain counties they can see the related "Homes" to these counties
I'm not sure how should I represent these relations between users, subscriptions and how to connect it to County model I have.
and how to make a view for the user to add new counties.
Thank you.
Update (My models):
class State(models.Model):
state_name = models.CharField(max_length=50)
def __str__(self):
return self.state_name
class County(models.Model):
county_name = models.CharField(max_length=50)
state = models.ForeignKey(State, on_delete=models.CASCADE)
def __str__(self):
return self.county_name
class Meta:
unique_together = ("county_name", "state")
verbose_name_plural = 'Counties'
class Home(models.Model):
owner_name = models.CharField(max_length=100, null=True, blank=True)
street_address = models.CharField(max_length=100, null=True, blank=True)
city = models.CharField(max_length=50, null=True, blank=True)
county = models.ForeignKey(County, on_delete=models.CASCADE)
postal_code = models.CharField(max_length=50, null=True, blank=True)
price = models.CharField(max_length=50, null=True, blank=True)
sqft = models.CharField(max_length=50, null=True, blank=True)
home_type = models.CharField(max_length=100, null=True, blank=True)
geom = models.PointField()
added = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
return '{}, {}, {}'.format(self.street_address, self.city, self.county.state.state_name)
class Meta:
verbose_name = 'Home'
verbose_name_plural = 'Homes'
#property
def state_county(self):
return f'{self.county.county_name}_{self.state}'
#property
def state(self):
return self.county.state.state_name
Here is a basic idea, you should evaluate from this point.
class State(models.Model)
name = models.CharField(max_length=100)
class County(models.Model)
state = models.ForeignKey(State)
name = models.CharField(max_length=100)
class Home(models.Model)
county= models.ForeignKey(County)
name = models.CharField(max_length=100)
class Subscription(models.Model)
county = models.ForeignKey(County)
user = models.ForeignKey(User)
Basically, you can then charge your user per County (observe that one can have more than one County subscription)
Another aproach would be to use a hierarchy to have State>County>Home, on a MPTT, but maybe its not what you want.
One way would be to add ManyToMany County relationship field in the Subscriptions model and then you would query subscribed county and filter Home.
Something in the sense of:
class County(models.Model):
county = models.CharField(max_length=255)
class Home(models.Model):
county = models.ForeignKey(County, on_delete=models.PROTECT)
class Subscription(models.Model):
user = models.ForeingKey(User, on_delete=models.PROTECT)
county = models.ManyToMany(County)
Then you'd query subscriptions and filter based on that.
subscriptions = Subscription.objects.filter(user=request.user).values_list('county', flat=True)
homes = Home.objects.filter(county_id__in=subscriptions)
You could further improved that with models Manager on Subscription to avoid filtering user every time with something like:
class SubscriptionManager(models.Manager):
def user_subscriptions(self, user):
return super().get_queryset().filter(user=user)
class Subscription(models.Model):
user = models.ForeingKey(User, on_delete=models.PROTECT)
county = models.ManyToMany(County)
objects = SubscriptionManager()
and then filter either with:
subscriptions = Subscription.objects.filter(user=request.user).values_list('county', flat=True)
or
subscriptions = Subscription.objects.user_subscriptions(request.user).values_list('county', flat=True)

Changing django default pk with AutoField to BigAutoField

My model has a default pk with AutoField (integer) but later on i discovered that i need to use BigAutoField instead!
And also i have data in then with other models referencing the student model:: how do i change the pk field to BigAutoField and also reflects on other referencing models
class Student(models.Model):
matric_no = models.CharField(max_length=20, unique=True) # first set it to U(random)
password = models.CharField(max_length=128)
session = models.ForeignKey(Session, null=True)
programme = models.ForeignKey(Programme, null=True)
school = models.ForeignKey(School, null=True)
course_comb = models.ForeignKey(CourseComb, null=True)
serial = models.IntegerField(null=True)
current_level = models.CharField(max_length=3, choices=LEVEL_CHOICES, default='100', null=True)
last_login = models.DateField(null=True)
is_active = models.CharField(max_length=1, default=1, choices=((1, 1), (0, 0)))
created_at = models.DateTimeField(default=timezone.now)
updated_at = models.DateTimeField(auto_now=True)
a model referencing Student
class Profile(models.Model):
student = models.OneToOneField(Student, on_delete=models.CASCADE)
attachment = models.ImageField(null=True, blank=True, verbose_name="Profile Image")
surname = models.CharField(max_length=255, null=True, verbose_name="Surname")
othernames = models.CharField(max_length=255, null=True, verbose_name="Othernames")
SEX_CHOICES = (
("M", "Male"),
("F", "Female")
)
Set primary_key=True in the field definition:
id = models.BigAutoField(primary_key=True)
If you want to use this in multiple models you could also make an abstract model and let others inherit it:
class BigPkAbstract(models.Model):
id = models.BigAutoField(primary_key=True)
class Meta:
abstract = True
And in your other models:
class SomeModel(BigPkAbstract):
<your model here>
‌

Using two database tables for one control in Django Admin

I am creating a small application to help our Training Department manage their cirriculum using Django. When we talk about students we have two type; Employee and Customer.
Since all of the employees will be in auth_user I would rather not have to populate another table with that data. The behavior that I want is when a Class is displayed in the Django Admin I would like one control to be filled with data from two tables for the student list. Is this even possible in Django. My suspicion is that it is not. This is what I am messing around with:
from django.db import models
from django.contrib.auth.models import User
class Student(models.Model):
cell_phone = models.CharField(max_length=14)
class Meta:
abstract = True
class EmployeeStudent(models.Model, Student):
user = models.OneToOneField(User)
extension = models.CharField(max_length=4, null=True, blank=True, default=None)
class CustomerStudent(models.Model, Student):
first_name = models.CharField(max_length=25)
last_name = models.CharField(max_length=25)
email = models.CharField(max_length=25)
However, just thinking about it does it make more sense to do:
from django.db import models
from django.contrib.auth.models import User
class Student(models.Model):
user = models.ForeignKey(User, null=True, blank=True, default=None)
first_name = models.CharField(max_length=25, null=True, blank=True, default=None)
last_name = models.CharField(max_length=25, null=True, blank=True, default=None)
email = models.CharField(max_length=25, null=True, blank=True, default=None)
extension = models.CharField(max_length=4, null=True, blank=True, default=None)
I cringe at the thought of a blank record.
Any recommendations? Does it make sense to add everything to auth_user and leave the staff flag to false then just use a one to one field to map an auth_user to a Student? I do not really want to do that if I don't have to because I am not going to give anyone else access to the auth_user table so all additions to this table would need to be done by me.
You could try to use model inheritance (i.e User model inheritance : https://docs.djangoproject.com/en/dev/topics/auth/customizing/#extending-user) for your Student model, or mixing Student(models.Model) with User in your EmployeeStudent and CustomerStudent models :
class Student(models.Model):
cell_phone = models.CharField(max_length=14)
class Meta:
abstract = True
class EmployeeStudent(User, Student):
user = models.OneToOneField(User)
extension = models.CharField(max_length=4, null=True, blank=True, default=None)
class CustomerStudent(User, Student):
first_name = models.CharField(max_length=25)
last_name = models.CharField(max_length=25)
email = models.CharField(max_length=25)
or :
class Student(User):
cell_phone = models.CharField(max_length=14)
class Meta:
abstract = True
class EmployeeStudent(models.Model):
user = models.OneToOneField(Student)
extension = models.CharField(max_length=4, null=True, blank=True, default=None)
class CustomerStudent(models.Model):
first_name = models.CharField(max_length=25)
last_name = models.CharField(max_length=25)
email = models.CharField(max_length=25)
If I understand correctly, you'd then want to display Customers as well as Employees in the same changelist in admin ? Using Student(User) with Employee / Customer as inlines might solve your problem.
Hope this helps,
Regards
This is a fairly common use-case (i.e. different types of userprofiles) in Django. In your case, I think the approach below would suit your scenario:
from django.db import models
from django.contrib.auth.models import User
class Student(models.Model):
STUDENT_TYPES = (
('E', 'EmployeeStudent'),
('C', 'CustomerStudent'),
)
user = models.OneToOneField(User, null=True, blank=True, default=None)
user_type = models.CharField(max_length=1, choices=STUDENT_TYPES)
class EmployeeDetails(models.Model):
student = models.OneToOneField(Student)
extension = models.CharField(max_length=4, null=True, blank=True, default=None)
class StudentDetails(models.Model):
student = models.OneToOneField(Student)
# BTW: all the fields below are redundant since they are already in User
first_name = models.CharField(max_length=25, null=True, blank=True, default=None)
last_name = models.CharField(max_length=25, null=True, blank=True, default=None)
email = models.CharField(max_length=25, null=True, blank=True, default=None)
This way, you can check the student.user_type and infer if you need to get EmployeeDetails or StudentDetails
NOTE:: Even though this is a recommended approach, it is not quite easy to enter data using the default admin interface in this manner. You might want to see how profile inlines are done to show the user profile fields in the admin as well.