Django, suiting model structure - django

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

Related

Hi I'm having trouble customizing authentication in Django

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.

A better way to orgainize django-channels one to one private chat models?

I want to model the database table of a django channels private chat in the most effective way possible so that retrieving the messages would not take a lot of time.
For that I have create a one to one room since every two users should have their unique room.
And I created a separate message table with a foreign key relation with the (oneToOneRoom) table.But what bothers me is that since the sender and the receiver of the message can only be one of the two users of the room I do not want set (sender and receiver) as foreign Key to the users table. Can I have a better implementation of that. Or is their any other way of modeling those tables. Any help would be highly appreciated.
Here is the models.py file.
class singleOneToOneRoom(models.Model):
first_user = models.ForeignKey(
User, on_delete=models.SET_NULL, related_name="first_user", blank=True, null=True)
second_user = models.ForeignKey(
User, on_delete=models.SET_NULL, related_name="second_user", blank=True, null=True)
room_name = models.CharField(max_length=200, blank=True, unique=True)
def __str__(self):
return f"{self.first_user}-{self.second_user}-room"
class Meta:
unique_together = ["first_user", "second_user"]
class messages(models.Model):
room = models.ForeignKey(
singleOneToOneRoom, on_delete=models.CASCADE, related_name="messages")
message_body = models.TextField()
sender = models.ForeignKey(
User, on_delete=models.CASCADE, related_name="msg_sender")
receiver = models.ForeignKey(
User, on_delete=models.CASCADE, related_name="msg_receiver")
date_sent = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"{self.sender}_to_{self.receiver}"
The design seems ok. You can add more constraints to be sure, that message belongs to the right users.
Here my suggestions:
Make first_user and second_user NOT NULL fields.
Make sure, that you have exactly 1 room for users pair (first_user.id < second_user.id)
Make sure, that (receiver, sender) pair equals (first_user, second_user) pair
class singleOneToOneRoom(models.Model):
first_user = models.ForeignKey(
User, on_delete=models.CASCADE, related_name="first_user", null=False)
second_user = models.ForeignKey(
User, on_delete=models.CASCADE, related_name="second_user", null=False)
class Meta:
unique_together = ["first_user", "second_user"]
constraints = [
models.CheckConstraint(check=Q(first_user__id__lt=F('second_user__id')), name='unique_user_pair'),
]
class messages(models.Model):
room = models.ForeignKey(
singleOneToOneRoom, on_delete=models.CASCADE, related_name="messages")
message_body = models.TextField()
sender = models.ForeignKey(
User, on_delete=models.CASCADE, related_name="msg_sender")
receiver = models.ForeignKey(
User, on_delete=models.CASCADE, related_name="msg_receiver")
class Meta:
constraints = [
models.CheckConstraint(
check=Q(sender=F('singleonetooneroom__first_user') & Q(receiver=F('singleonetooneroom__second_user'))
| Q(sender=F('singleonetooneroom__second_user') & Q(receiver=F('singleonetooneroom__first_user')),
name='valid_sender_and_receiver'
),
]

Recording user activity in django?

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.

django retrieving all objects from one to many model relationship in shell

from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Board(models.Model):
title = models.CharField(max_length=50, null=True)
user = models.ForeignKey(User, null=True, on_delete=models.CASCADE)
def __str__(self):
return self.title
class Task(models.Model):
title = models.CharField(max_length=200, null=True)
done = models.BooleanField(default=False, null=True)
created_at = models.DateTimeField(auto_now_add=True, null=True)
user = models.ForeignKey(User, null=True, on_delete=models.CASCADE)
board = models.ForeignKey(Board, null=True, on_delete=models.CASCADE)
def __str__(self):
return self.title
how can I get all tasks that are inside one board? (every user can create a board and inside that board the user can create tasks) I've tried Board.objects.get(pk=1).title.title but that doesn't seem to work.
You can retrieve the Board object, and then query with task_set:
board = Board.objects.get(pk=1)
board.task_set.all() # queryset of related Tasks
If you are not interested in the Board itself, you can omit querying the Board, and filter with:
Task.objects.filter(board_id=1) # queryset of related Tasks

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.