I am a newbie and I am designing Django authentication software
My problem is that I have to check four separate levels for which there are predefined codes in the permission check.
A model class named province and a model class named city and a model named Student
My review model is such that I should be able to give a user the membership of the central office or the membership of a province or the membership of a city in a province.
The user can only be for one of these situations
My models is like this
class Province(models.Model):
province_id = models.IntegerField(primary_key=True, serialize=True, verbose_name='ID')
province_title = models.CharField(max_length=30, verbose_name=_('Province'))
class Meta:
ordering = ['province_id']
def __str__(self):
return self.province_title
class Center(models.Model):
id = models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')
center_title = models.CharField(max_length=150, verbose_name=_('Name of the training center'), null=True)
center_title_id = models.CharField(max_length=64, verbose_name=_('Code of the training center'), null=True)
province = models.ForeignKey(Province, on_delete=models.CASCADE, verbose_name=_('Province'))
class Meta:
verbose_name = _("center")
verbose_name_plural = _("centers")
def __str__(self):
return self.center_title`
class CulturalUser(AbstractUser):
pass
class UserPositions(models.Model):
class Position(models.TextChoices):
UNIVERSITY_STUDENT = '1', _('University student')
TRAINING_CENTER = '2', _('Training center')
PROVINCE = '3', _('Province')
CENTRAL_OFFICE = '4', _('Central office')
user = models.ForeignKey(CulturalUser, on_delete=models.CASCADE, verbose_name=_('User'))
position = models.CharField(max_length=2, verbose_name=_('Access level'), choices=Position.choices,
default=Position.UNIVERSITY_STUDENT)
province = models.ForeignKey(Province, on_delete=models.SET_NULL, blank=True, null=True)
center = models.ForeignKey(Center, on_delete=models.SET_NULL, blank=True, null=True)
def __str__(self):
return self.position
please direct me
According to the search I did, I could not find the right sources in my question mode
You can either extend or substitute an user model. Quotting the documentation:
If you’re starting a new project, it’s highly recommended to set up a custom user model, even if the default User model is sufficient for you. This model behaves identically to the default user model, but you’ll be able to customize it in the future if the need arises:
A full example
Django's user models counts with permissions and authorization and groups out of the box. So, instead of choices fields you would have four groups, for which you would handle access with permissions.
University student
Training center
Province
Central office
Here is one version of your model:
from django.utils.translation import gettext_lazy as _
from django.db import models
from django.contrib.auth.models import AbstractUser
class Province(models.Model):
name = models.CharField(
max_length=30,
verbose_name=_('Province')
)
class Meta:
ordering = ['id']
def __str__(self):
return self.title
class Center(models.Model):
name = models.CharField(
max_length=150,
verbose_name=_('Name of the training center'),
null=True,
)
code = models.CharField(
max_length=64,
verbose_name=_('Code of the training center'),
null=True,
)
province = models.ForeignKey(
Province,
on_delete=models.CASCADE,
verbose_name=_('Province')
)
class Meta:
verbose_name = _("center")
verbose_name_plural = _("centers")
def __str__(self):
return self.name
class User(AbstractUser):
province = models.ForeignKey(
Province,
on_delete=models.SET_NULL,
blank=True, null=True,
)
center = models.ForeignKey(
Center,
on_delete=models.SET_NULL,
blank=True, null=True,
)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
Note that I used AbstractUser, like you did, but you can do an even deeper customization with AbstractBaseUser, as shown in the example I linked above.
Related
I have a project in which some user can perform CRUD activities. I want to record who did what and when. Currently, I am thinking of making a model
class UserAction(models.Model):
user_id = models.CharField(max_length=100)
action_flag = models.CharField(max_length=100)
class_id = models.CharField(max_length=100)
action_taken_at = models.DateTimeField(default=datetime.now())
and making a function that fills my UserAction table. Is there any better way to do this?
app/models.py:
from django.db import models
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey
class Action(models.Model):
sender = models.ForeignKey(User,related_name='user',on_delete=models.CASCADE)
verb = models.CharField(max_length=255)
target_ct = models.ForeignKey(ContentType, blank=True, null=True,
related_name='target_obj', on_delete=models.CASCADE)
target_id = models.PositiveIntegerField(null=True, blank=True)
target = GenericForeignKey('target_ct', 'target_id')
created = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ('-created',)
def __str__(self):
return self.pk
app/admin.py
from .models import Action
admin.site.register(Action)
How you can use it ?
you can now import this models(Action) inside any of yours views.py.
Example if you have a post and a user likes it.you can just write
Action.objects.create(sender=request.user,verb="likes this post",target=post)
and now when you look at your admin you will see that tartget_id=post.pk
Here I assume that a user is authenticated and you can change it for your own.Happy coding!!!
You can do it by creating a model in
Models.py
class Auditable(models.Model):
ip = models.GenericIPAddressField(null=True)
user_agent = models.CharField(max_length=255, blank=True)
remote_host = models.CharField(max_length=255, blank=True)
created_at = models.DateTimeField(auto_now_add=True, blank=True, null=True)
created_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING, related_name="%(app_label)s_%(class)s_created_by", null=True, blank=True) # this is for web user
modified_at = models.DateTimeField(auto_now=True, blank=True, null=True)
modified_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING, related_name="%(app_label)s_%(class)s_modified_by", null=True, blank=True) # this is for web user
class Meta:
abstract = True
def get_fields(self):
list_fields = ['ip', 'user_agent',
'remote_host', 'created_by', 'modified_by']
return [(field.verbose_name, field._get_val_from_obj(self)) for field in self.__class__._meta.fields if field.name not in list_fields and not
(field.get_internal_type() == "DateTimeField" and
(field.auto_now is True or field.auto_now_add is True)) and
field.concrete and (not field.is_relation or field.one_to_one or
(field.many_to_one and field.related_model))]
You can give any class name (i have given auditable). So all you have to do is pass this class (auditable) in your every model instead of models.Model
For Eg:
class Student(Auditable):
By doing this it will add all the auditable fields records in every table you have created.
Hope you may get your answer by doing this.
I'm attempting to build out a rather large "Patient Onboarding" form using ModelForms.
I'm having trouble getting the choices within the foreign keys to appear in the admin area or to the rendered form without manually adding them to the Postgres database.
There has got to be a more efficient way to be doing this...thanks in advance!
#models.py
from django.db import models
from django.forms import ModelForm
from django import forms
class Patient(models.Model):
first_name = models.CharField(max_length=30, verbose_name='First Name', blank=False)
middle_name = models.CharField(max_length=30, verbose_name='Middle Name', blank=False)
last_name = models.CharField(max_length=30, verbose_name='Last Name', blank=False)
gender = models.ForeignKey('GenderChoices', on_delete=models.CASCADE, verbose_name='Gender', blank=False)
date_of_birth = models.DateField(verbose_name='Date of Birth', blank=False)
medications = models.ForeignKey('MedicationsYesNo', on_delete=models.CASCADE, verbose_name='Do you currently take any medications?', blank=False)
class MedicationsYesNo(models.Model):
medications_yes_no = models.CharField(
max_length=100,
choices = [
('Yes', 'Yes'),
('No', 'No')
]
)
def __str__(self):
return self.medications_yes_no
class OnboardingForm(ModelForm):
class Meta:
model = Patient
fields = '__all__'
Hi can't figure out a suitable data structure for my models. These are my requirements:
Each UserModel is represents a single Referee
A RefereeTeam is made of two Referees
One Game can have one referee or a RefereeTeam
A Referee or a RefereeTeam can request any Game (to supervise it)
Each Game can have arbitrary Requests
Each Game can have only one appointed Referee or Team
States are ('Declined', 'Open', 'Appointed') for each request
My current models are just not maintainable.
------ EDITED FROM HERE ------
From the n GameRequests only one will become the appointment. And if for some reason (life) the appointment becomes invalid I need to be able to pick someone of the other GameRequests for the specific game.
from django.core.exceptions import ValidationError
from django.db import models
from django.utils.translation import gettext_lazy as _
from django_filters import FilterSet
from users.models import CustomUser # AUTH_MODEL!
class Hall(models.Model):
"""PLACE OF GAME"""
# details
class team(models.Model):
name, etc.
class Game(models.Model):
home = models.ForeignKey(Team, on_delete=models.CASCADE, related_name='home')
gast = models.ForeignKey(Team, on_delete=models.CASCADE, related_name='team')
hall = models.ForeignKey(Halle, on_delete=models.CASCADE)
...
def clean(self):
if self.heim == self.gast:
raise ValidationError(_("..."))
class RefTeam(models.Model):
sr1 = models.ForeignKey(
CustomUser,
on_delete=models.CASCADE,
related_name='gsr1',
null=True,
blank=True)
sr2 = models.ForeignKey(
CustomUser,
on_delete=models.CASCADE,
related_name='gsr2',
null=True,
blank=True)
class Meta:
verbose_name_plural = 'Gespanne'
def clean(self):
# validation methods
class GameRequest(models.Model):
game = models.ForeignKey(Spiel, on_delete=models.CASCADE, null=True)
sr1 = models.ForeignKey(
CustomUser,
on_delete=models.CASCADE,
related_name='sr1',
null=True,
blank=True)
sr2 = models.ForeignKey(
CustomUser,
on_delete=models.CASCADE,
related_name='sr2',
null=True,
blank=True)
refTeam= models.ForeignKey(
RefTeam,
on_delete=models.CASCADE,
null=True,
blank=True)
STATI = (
('DC', 'Declined'),
('OP', 'Open'),
('AP', 'Approved')
status = models.CharField(choices=STATI, max_length=9, default='OP')
def clean(self):
# at least sr1, sr2 or team
# not team and single ref
# ...
class Appointment(models.Model):
game = models.OneToOneField(Game, on_delete=models.CASCADE, null=True)
appointed = models.OneToOneField(GameRequest, on_delete=models.CASCADE, null=True, blank=True)
Each UserModel is represents a single Referee
For That i will use a OneToOne:
class Referee(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
A RefereeTeam is made of two Referees
For that i will have a ForeignKey on Referee and a Model RefereeTeam
class Referee(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
referee_team = models.ForeignKey(
RefereeTeam,
blank=True,
null=True,
on_delete=models.DO_NOTHING)
class RefereeTeam(models.Model):
WHAT YOU WANT FIELDS
And dont forget that RefereeTeam object have reverse relation to Referee with obj.referee_set
One Game can have one referee or a RefereeTeam
It's a little more tricky but here a solution (not the best IMO) that will return you a Referee or a RefereeTeam model (more info about generic relations here):
class Game(models.Model):
content_type = models.ForeignKey(ContentType, on_delete=models.DO_NOTHING)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
A Referee or a RefereeTeam can request any Game (to supervise it)
Same model than the previous question.
Each Game can have arbitrary Requests
class Requests(models.Model):
game = models.ForeignKey(
Game,
blank=False,
null=False,
on_delete=models.CASCADE)
request = models.CharField(
max_length=255, blank=False,
null=False)
Each Game can have only one appointed Referee or Team
States are ('Declined', 'Open', 'Appointed') for each request
I dont really understant this one
I am a django newbie and have one more big struggle for longer time... :/
User can choose a 'main language' which is set as ForeignKey. User can choose 'further languages' as ManyToMany (Checkbox). Assuming, user selects english as 'main' language, so english has to be filterd out from the 'further languages'... have been searching so much and have no idea how to do it. Is this even possible without JavaScript?
Of course, I could set the 'queryset' in the second form but it would filter the objects after the submit... The similar problem is, when a selected country has to be connected to the proper zipcodes...
I am very thankful for any hints.
Best regards.
class Country(models.Model):
enter code here
country = models.CharField(max_length=40)
active = models.BooleanField(default=True)
class Meta:
verbose_name_plural = 'Länder'
def __str__(self):
return self.country
class ZipCode(models.Model):
zipcode = models.CharField(max_length=5)
city = models.CharField(max_length=255)
active = models.BooleanField(default=False)
class Meta:
verbose_name_plural = 'Postleitzahlen'
def __str__(self):
return '{0} {1}'.format(self.zipcode, self.city)
class MainLanguage(models.Model):
language = models.CharField(verbose_name='Hauptsprache', max_length=40)
active = models.BooleanField(default=True)
class Meta:
verbose_name_plural = 'Hauptsprachen'
ordering = ['language']
def __str__(self):
return self.language
class SecondLanguage(models.Model):
language = models.CharField(verbose_name='weitere Sprachen', max_length=40)
active = models.BooleanField(default=False)
class Meta:
verbose_name_plural = 'weitere Sprachen'
ordering = ['language']
def __str__(self):
return self.language
class CustomUserprofile(models.Model):
user = models.OneToOneField(User)
name = models.CharField(verbose_name='Vorname', max_length=40,
null=True, blank=True)
country = models.ForeignKey(Country, verbose_name='Land',
null=True, blank=True)
zipcode = models.ForeignKey(ZipCode, blank=True, null=True)
main_language = models.ForeignKey(
MainLanguage, verbose_name='Hauptsprache',
null=True, blank=True)
second_language = models.ManyToManyField(
SecondLanguage, verbose_name='weitere Sprachen',
null=True, blank=True)
class UserProfileForm(forms.ModelForm):
second_language = forms.ModelMultipleChoiceField(
queryset=SecondLanguage.objects.all(),
required=False,
widget=forms.CheckboxSelectMultiple)
class Meta:
model = CustomUserprofile
exclude = ('user',)
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.