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.
Related
I'm creating an application that i have username and nickname for the same person:
username = models.CharField(
max_length=40, unique=True, db_index=True)
nickname = models.CharField(max_length=100, unique=True)
But i need to define this two variables as unique like:
If an user A has:
username: bird
nickname: dog
and an user B try to make registration like:
username: dog
nickname: butterfly
I will not accept because dog is already taken. Or if an user try to put nickname as same as username.
I'm thinking to create a registration view to make this validation manually. But is there a way to make this in the declaration?
You can use the unique_together setting under Meta.
eg.
class Meta:
unique_together = [[field1, field2]]
In your case this would mean that bird/dog would be unique, as would bird/butterfly. dod/bird would be allowed as the fields are different from bird/dog, but a second bird/dog would not be allowed.
SQL isn't generally made to enforce uniqueness across two columns, so the only solution I'm aware of would be to split this up into two tables, one for typed names, and one for all other user information. You'd adapt that answer to models with something like:
class User(models.Model):
# Define fields aside from username and nickname here
class Name(models.Model):
user = models.ForeignKey('Users', on_delete=models.CASCADE)
USERNAME = 'U'
NICKNAME = 'N'
TYPE_CHOICES = (
(USERNAME, 'username'),
(NICKNAME, 'nickname')
)
type = models.CharField(max_length=1, choices=TYPE_CHOICES)
name = models.CharField(max_length=100, unique=True)
class Meta:
constraints = [
models.UniqueConstraint(fields=['user', 'type'], name='unique_user_type'),
]
# Alternative more concise, but semi-deprecated, approach:
# unique_together = [['user', 'type']]
By doing this, you use a single shared column for all names; it's got a unique constraint, so no name can appear twice as either username or nickname. Similarly, the combined uniqueness constraint on the user and type fields means any given user can only have one of each type of name, user or nick, while the foreign key relationship means you can access username/nickname data through the User model, and the on_delete=models.CASCADE setting means that if the associated user is deleted, then so are the associated names.
Main downsides are:
This doesn't force you to create either a username or nickname for a given user; your program logic would have to ensure that a user is never (permanently) created unless both username and nickname are valid
Item #1 implies that you must explicitly operate transactionally, as opposed to relying on per-table insertion atomicity; when creating a new user, you'd need to begin a transaction, create the user, flush to get a valid user id, then create both names using the new user id, rolling back the whole transaction if any constraints are violated as you go
Inability to define different limits for username vs. nickname; since they share a field, you can't impose different length limits on each field (your wrapper code could do so, but the DB couldn't attempt to save space based on the different limits, even if you used complicated CheckConstraints to impose independent limits)
All that said, I'd discourage this approach. If nicknames aren't security-relevant, you can allow them to overlap (StackOverflow allows this; the link to the user profile is how you tell folks apart); they don't really need to be unique at all. Usernames obviously need to be unique, but there is no need to prevent a nickname from overlapping a username if the nickname is purely for display.
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.
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)
So I'm learning Django and trying to get values throught foreign key by using Django ORM functions only. I've got 2 tables: User Table (default Django auth_user system table) and Student Table containing student_id, user_id(FK) and nr_indeksu (it's a number containing additional info for student specific information).
class Student(models.Model):
user = models.ForeignKey(User)
nr_indeksu = models.BigIntegerField()
def __unicode__(self):
return unicode(self.user
I want to fetch nr_indeksu through User model. In other words execute this query (using QuerySet):
SELECT nr_indeksu FROM auth_user
INNER JOIN courses_student on auth_user.id = courses_student.user_id;
I have tried using select_related() function:
u = User.objects.select_related().get(pk=2)
but when i try to access nr_indeksu:
u.nr_indeksu
i got error that User object has no attribute (it makes sense because nr_indeksu is in Student model but shouldn't i be able to fetch it from User?)
Remember a ForeignKey is a one-to-many relation: there are many Users for each Student. From a user object, you can access the related Students by doing user_obj.student_set.all().
Adding to Daniel's answer, you can also use related_names , right now when you have to do a reverse foreign-key lookup, you need to write :-
user_obj.student_set.all()
However, with related_name attribute, the model would look like :-
class Student(models.Model):
user = models.ForeignKey(User, related_name='studentuser')
nr_indeksu = models.BigIntegerField()
def __unicode__(self):
return unicode(self.user
then for a reverse lookup, you need to write :-
user_obj.studentuser.all()
Basically, all I mean to say is, you can supply own names for reverse lookup by passing related_name attribute, if in case you don't want to use the default name used by django which is generally of the form <foreign_key_name>_set eg. in your case it is student_set.
s = Student.objects.get(user__id=2)
s.nr_indeksu
Ok, I am working on a Django application with several different models, namely Accounts, Contacts, etc, each with a different set of fields. I need to be able to allow each of my users to define their own fields in addition to the existing fields. I have seen several different ways to implement this, from having a large number of CustomFields and just mapping a custom name to each field used by each user. I have also seem recommendations for implementing complex mapping or XML/JSON style storage/retrieval of user defined fields.
So my question is this, has anyone implemented user defined fields in a Django application? If so, how did you do it and what was your experience with the overall implementation (stability, performance, etc)?
Update: My goal is to allow each of my users to create n number of each record type (accounts, contacts, etc) and associate user defined data with each record. So for example, one of my users might want to associate an SSN with each of his contacts, so I would need to store that additional field for each Contact record he creates.
Thanks!
Mark
What if you were to use a ForeignKey?
This code (untested and for demo) is assuming there is a system-wide set of custom fields. To make it user-specific, you'd add a "user = models.ForiegnKey(User)" onto the class CustomField.
class Account(models.Model):
name = models.CharField(max_length=75)
# ...
def get_custom_fields(self):
return CustomField.objects.filter(content_type=ContentType.objects.get_for_model(Account))
custom_fields = property(get_fields)
class CustomField(models.Model):
"""
A field abstract -- it describe what the field is. There are one of these
for each custom field the user configures.
"""
name = models.CharField(max_length=75)
content_type = models.ForeignKey(ContentType)
class CustomFieldValueManager(models.Manager):
get_value_for_model_instance(self, model):
content_type = ContentType.objects.get_for_model(model)
return self.filter(model__content_type=content_type, model__object_id=model.pk)
class CustomFieldValue(models.Model):
"""
A field instance -- contains the actual data. There are many of these, for
each value that corresponds to a CustomField for a given model.
"""
field = models.ForeignKey(CustomField, related_name='instance')
value = models.CharField(max_length=255)
model = models.GenericForeignKey()
objects = CustomFieldValueManager()
# If you wanted to enumerate the custom fields and their values, it would look
# look like so:
account = Account.objects.get(pk=1)
for field in account.custom_fields:
print field.name, field.instance.objects.get_value_for_model_instance(account)