Get related (via ForeignKey) object in my view - django

I have a model like this:
class database(models.Model):
db_name = models.CharField('Name', max_length=20)
server = models.ForeignKey(dbServer, unique=True)
user = models.ForeignKey(User)
In my view I want to grab every database realated to the current user (has to be logged in at that point).
I'm sure there is an easy way to do this, but I can't find it.

You could simply use:
some_user.database_set.all()
How ever I recommend trying related_name attribute, for example:
class database(models.Model):
db_name = models.CharField('Name', max_length=20)
server = models.ForeignKey(dbServer, unique=True)
user = models.ForeignKey(User, related_name="databases")
And then:
some_user.databases.all()

Use the backwards relationship:
databases = User.database_set.all()

Related

Django signals / notification system

Is it a good aproach to use Django signals to implement email notification system? I have CustomUser model related with CustomUserPreferences planned as follows:
class CustomUserPreferences(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, default=None, on_delete = models.CASCADE, primary_key = True)
lesson_notification = models.BooleanField(default=True)
journal_notification = models.BooleanField(default=False)
login_notification = models.BooleanField(default=False)
excercise_notification = models.BooleanField(default=False)
homework_notification = models.BooleanField(default=True)
class CustomUser(AbstractUser):
...
email = models.EmailField(_('email address'), unique=True)
preferences = models.OneToOneField(CustomUserPreferences, null = True ,default=None, on_delete = models.CASCADE)
students = models.ManyToManyField(to = 'self', related_name = 'teachers', symmetrical = False, blank = True)
Whenever a new object of lets say Lesson is created I want to send an email to the user and that's fine - becaouse it won't overload any server.
The question is: will it pay off to use signals for a list of users that contains lets say 100s or 1000s of users? I'm afraid it will slow down the whole application.
Is there any other "clear and elegant" way to do this? Django docs advices not to use signals whenever it's possible.

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.

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

Get all related field in Django model

I am struggling to understand how one-to-many and many-to-many relation works in Django model. My schema looks something like this so far, I am open for suggestions to make it better.
A many-to-many relation between users and team. Also, there will be schedules that belong to a particular user of a team.
This is how my model looks like so far,
class Team(models.Model):
tid = models.AutoField(primary_key=True)
team_name = models.CharField(max_length=30)
manager_name = models.CharField(max_length=30)
class Schedule(models.Model):
sid = models.AutoField(primary_key=True)
user = models.OneToOneField(User)
date = models.DateField()
start_time = models.TimeField()
end_time = models.TimeField()
pay_rate = models.CharField(max_length=30)
location = models.CharField(max_length=50)
class BelongsTo(models.Model):
bid = models.AutoField(primary_key=True)
user = models.OneToOneField(User)
team = models.ForeignKey(Team, on_delete=models.CASCADE)
schedule = models.ForeignKey(Schedule, on_delete=models.CASCADE)
Question: I want to get the information of each user, what are their schedules and which team each schedule belongs to. How would I to do it? I have tried BelongsTo.objects.select_related().all(), but it is not working for me.
Note: I am open for suggestions, if something is wrong with my schema or model or the approach, please let me know.
BelongsTo is seems like utility table.So
BelongsTo.objects.all().values('user', 'team__team_name', 'schedule')
Your schema looks almost right, but I would modify it a little bit. In particular, I will change how Schedule is implemented. Instead of having a sid in the User Belongs To join-table, I would include the user and team in the Schedule table as foreign keys.
This is how the Django models should then look like:
class User(models.Model):
username = models.CharField(max_length = 200)
# put other fields like password etc. here
class Team(models.Model):
team_name = models.CharField(max_length=30)
manager_name = models.CharField(max_length=30)
user = models.ManyToManyField("User")
class Schedule(models.Model):
user = models.ForeignKey("User")
team = models.ForeignKey("Team")
date = models.DateField()
start_time = models.TimeField()
end_time = models.TimeField()
pay_rate = models.CharField(max_length=30)
location = models.CharField(max_length=50)
Note the following:
You don't need to have a primary key field in the models because Django adds a primary key field called pk or id automatically.
Note the absence of the User Belongs To model. Django implements join-tables like User Belongs To automatically when you use a ManyToManyField. See the Django docs on many-to-many relationships.
You also don't need on_delete = models.CASCADE on ForeignKey fields, because this is the default behavior.
To see how to get information about users, teams and schedule from this configuration of models, consult the Django documentation on making db queries. It's quite easy.

constructing a joined django query

I'm interacting with a legacy db on another system, so the models are written in stone and not very django-ey.
My models.py:
class Site(models.Model):
site_code = models.CharField(max_length=30, primary_key=True)
name = models.CharField(unique=True, max_length=300)
class Document(models.Model):
id = models.IntegerField(primary_key=True)
site_ref = models.ForeignKey(Site)
description = models.CharField(max_length=1500)
class DocumentStatusCategory(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(unique=True, max_length=90)
class DocumentStatus(models.Model):
id = models.IntegerField(primary_key=True)
document = models.ForeignKey(Document)
status = models.ForeignKey(DocumentStatusCategory)
changed_by = models.ForeignKey(User)
created_at = models.DateTimeField()
In my views.py I want to retrieve a queryset with all the Document objects that belong to a specified Site (say site_ref=mysite) which do not have any related DocumentStatus objects with status=4.
Any idea how I can do this as a single (non-sql intensive) line?
Document.objects.filter(site_ref=mysite).exclude(documentstatus__status_id=4)
Document.objects.filter(site_ref=site_obj).exclude(documentstatus_set__in=DocumentStatus.objects.filter(status_id=4))
Not exactly one query, but I don't think that's achievable without going down to raw sql. Two queries isn't bad though I suppose.
I should mention that the above assumes that the reverse relation between Document and DocumentStatus is documentstatus_set. You can explicitly state what the reverse relation is like so:
# inside the DocumentStatus model definition
document = models.ForeignKey(Document, related_name='document_statuses')
Then the query becomes:
Document.objects.filter(site_ref=site_obj).exclude(document_statuses__in=DocumentStatus.objects.filter(status_id=4))