I have a concept where there is a model that has a OneToOne field with User. How can I query for all users that are not assigned to one of these?
For example:
class SpecialUser(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
Not all users are special users. How can I get all users that are not special users using objects (ie: User.objects.filter(something)).
Thanks!
You can do the following:
User.objects.filter(specialuser=None)
Or:
User.objects.filter(specialuser__isnull=True)
You can provide related_name to make it more readable or to avoid pottential collisions. Example:
class SpecialUser(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="special_user_profile")
In this case, you'd use the related name instead:
User.objects.filter(special_user_profile=None)
Related
I am having two model classes named as Leader and Member, both have a OnetoOne relationship with User, as you can see below:
from django.db import models
from django.contrib.auth.models import User
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.DO_NOTHING)
# Abstract model class for common fields in Leader and Member
class Meta:
abstract = True
class Leader(Profile):
# attributes
# def save(self) -> None:
# if Member.objects.filter(user=self.user).first() == None:
# return super().save()
# else:
# raise ValidationError("User is already a member, migrate it to make it leader.")
class Member(Profile):
# attributes
But if a user is already having a relation with anyone, among both of them, then it should not be allowed to have a relation with the other one.
For example:
If a user1 is referenced by Leader model, then it is not allowed to be referenced by Member model, if needed there should be a process by which we can remove and add user from Leader model to Member model, i.e. transferring Profile abstract model data from Leader model to Member model and receiving remaining data manually or vica versa.
By searching over the internet, I got to know that to solve this there is a way of raising ValidationError, when saving the models as shown in above code, but in my case, the admin panel is used by a non-tech guy, by using above approach there will be a error screen showing my validation error, which will be unusual for them to understand easily.
What should be the better approach to implement this?
I am using VS Code 1.69.1, python 3.10.2 and django 4.0.3.
Thanks in Advance!
If you make the column "user" in Profile unique, then I believe the problem is solved.
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.DO_NOTHING, unique=True)
By the way, if the extended models "Leader" and "Member" could have the same questions/fields/columns then the best option was to delete both of them and just make in profile a column to distinguish the two because you can make also two seperate tables like this:
leaders = Profile.objects.filter(usertype=1) # 1=leader
members = Profile.objects.filter(usertype=2) # 2=member
I have two models like below in django
class User(AbstractBaseUser, PermissionsMixin):
first_name = models.CharField(....)
last_name = models.CharField(_(....)
email = models.EmailField(...)
class VcsToken(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
as you can see VcsToken is related to User, and a user can have many VcsToken,
So how do I get all the VcsTokens of a User.
Similarly I have many one to many relationships from user to other models, so How do I know their reference name? (I know its a set but how do I know the set name? ) Is there any way to list the query set names for a model.
What you are looking for is the feature for walking backward on the foreign key relationships. This is covered here in the docs: https://docs.djangoproject.com/en/3.0/topics/db/queries/#following-relationships-backward
In your example you should be able to access VcsToken from User like this:
user = User.objects.get(pk=1) # let's get an example user
user.vcstoken_set.all() # returns all related VcsToken objects.
Optionally, when the ForeignKey is defined, you can specify a related_name argument that would be used by django for this purpose. For example:
class User(AbstractBaseUser, PermissionsMixin):
...
email = models.EmailField(...)
class VcsToken(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='tokens')
If such an argument is specified, then that is the reverse lookup name used by django and you would need to do user.tokens.all() to access them. When no such argument is specified a default name is used by django that ends with "_set".
Hope this helps, let me know if anything needs to be clarified.
For a given User object myuser, you can access this with:
myuser.vcstoken_set.all()
so How do I know their reference name?
This is the value for the related_name=… parameter [Django-doc] if there is no such parameter in the ForeignKey construction, it will default to modelname_set, with the modelname in lowercase.
Is there any way to list the query set names for a model.
You can access all ManyToOneFields with:
django.db.models.fields.reverse_related.ManyToOneRel
[f.get_accessor_name() for f in User._meta.get_fields() if isinstance(f, ManyToOneRel)]
This will construct a list of the names of ForeignKeys in reverse.
In my models.py, I have the request_author field defined as:
request_author = models.ForeignKey(
User,
on_delete = models.CASCADE
)
This makes the request_author field to be registered with a user code (int) number in the API database. However, I would like to have it as the user name. How do I do that?
You can use the to_field=... parameter [Django-doc], for that:
The field on the related object that the relation is to. By default, Django uses the primary key of the related object. If you reference a different field, that field must have unique=True.
So you can here set the to_field to 'username':
request_author = models.ForeignKey(
User,
on_delete = models.CASCADE,
to_field='username'
)
The username of the User model is unique=True, so this will not be a problem here. If you define a custom user model, than this does not per se holds.
Note that if you change the to_field, this might fail, since now it refers to a different field. In case you are just starting to build an application, it might be better to drop the database, remove old migrations, and then create a new migration file.
Let's say that I want to develop a simple todo-list app. This is what the models.py mght look like.
PRIORITIES = ["LOW", "MEDIUM", "HIGH", "URGENT"]
class User(models.Model):
username = models.CharField(max_length = 20)
password = models.CharField(max_length = 100)
email = models.EmailField()
class Task(models.Model):
text = models.TextField()
dueDate = models.DateField()
priority = models.CharField(choices = PRIORITIES, default = "LOW")
class UserTask(models.Model):
user = models.ForeignKey(User, on_delete = models.CASCADE)
task = models.ForeignKey(Task, on_delete = models.CASCADE)
Here, the UserTask model was created only with a view to reducing redundancies in the database.
Is it a good practice? I don't think that this is what models should be used for.
Here, the UserTask model was created only with a view to reducing redundancies in the database.
Given I understand it correctly, a Task belongs to a single User, at least based on your comment:
I read about ManyToMany, the problem is that this relation in question is in fact OneToMany.
In that case, I do not see how you are "reducing" redundancies in the database, in fact you create extra data duplication, since now you need to keep the Task and its user = ForeignKey(..) in harmony with UserTask, this thus means that all creates, edits and removals have impact, and some circumvent Django's signal tooling, so it makes it quite hard, if not impossible.
The fact is that you do not need to construct a table to query the relation in reverse. By default Django will put a database index on a ForeignKey, so the database can efficiently retrieve the Tasks that belong to a single (or multiple) users, it thus makes a JOIN with the user table more efficient.
One typically thus defines a ForeignKey like:
class Task(models.Model):
text = models.TextField()
dueDate = models.DateField()
user = models.ForeignKey(User, on_delete=models.CASCADE)
priority = models.CharField(choices = PRIORITIES, default = "LOW")
At the Python/Django level, Django also provides convenience to obtain the tasks of a User. If you want to retrieve all the Tasks of some_user, you can query with:
some_user.task_set.all()
or you can filter on the tasks, like:
some_user.task_set.filter(text__icontains='someword')
You can make the name of the relation in reverse more convenient as well, by specifying a related_name in the ForeignKey, like:
class Task(models.Model):
user = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name='tasks'
)
text = models.TextField()
dueDate = models.DateField()
priority = models.CharField(choices = PRIORITIES, default = "LOW")
In which case you thus query the Tasks of a User with:
some_user.tasks.all()
There is however a scenario where Django creates an implicit model that links two models together: in case one defines a ManyToManyField [Django-doc], since specifying an array of identifiers is typically hard (or even impossible) for a lot of relational databases (even if it is possible, typically one can no longer guarantee FOREIGN KEY constraints), etc.
In case the many-to-many relation between two models contains extra data (for example a timestamp when two users became friends), then one even defines an explicit model with two ForeignKey relations (and extra attributes), and uses this as a through [Django-doc] model.
I’m writing simple application with Django and PostgreSQL for managing a home book library, where I can have many borrower profiles for people who borrowed books (Borrower model). And I have users, who can borrow a book themselves, so that the book becomes borrowed by the user’s borrower profile.
On the other hand admin can lend books to any borrower, even to one unregistered as a user.
So I have a few MyUsers (and that field, btw, references Django’s User) and many Borrowers, and I want to create a one-to-one relation between them, but every MyUser has to reference one unique Borrower, but many Borrowers will not reference any existing MyUsers (they can only reference one or none, or in another words, be referenced by only one or no user).
My question is: how to model that optimally? Using models.OneToOneField, models.ForeignKey and which model should reference which?
I will probably have many borrowers, who do not have user accounts.
Natural solution seems to be OneToOneField(Borrower, null=False) in a User model. But then when searching for users based on borrowers I will have to mostly deal with DoesNotExists exceptions and only once in a while I will get a proper result.
I can also make ForeignKey(Borrower, unique=True, null=False) – then I will have to check sets having single element or empty.
And I can make ForeignKeys both ways:
class Borrower(models.Model):
# ...
user = models.ForeignKey(MyUser, unique=True, null=True)
class MyUser(models.Model):
# ...
borrower = models.ForeignKey(Borrower, unique=True, null=False)
That implicitly defines the relations and I can easily make searches both ways, but it also makes one additional, redundant field in database tables.
I will probably just stick with OneToOneField for now, but I’d like to know which approach makes most sense in this case. What are the proc and cons? And is there an alternative, better solution?
I would stick with the OneToOneField; as you say, it is the most natural solution.
The only downside you mentioned is that borrower.user can raise a DoesNotExist exception. If you don't like that, you can always define your own method (or property) to return something else (like None) instead. Something like:
class MyUser(models.Model):
borrower = models.OneToOneField(Borrower, null=False)
class Borrower(models.Model):
#property
def user(self):
try:
return self.myuser
except DoesNotExist:
return None
#user.setter
def user(self, user):
self.myuser = user