简体   繁体   中英

Django: Filtering by User Profile or a Foreign Key

For a simple activation key for an account, I have to create the key from random numbers while making sure that I'm not using the same key as another account. Right now, this is what I have:

def get_random_word():
    word = ''
    i = 0
    while i in range(10) and User.objects.filter(activation_key = word).exists():
        word += random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789')
        i+=1
    return word

The problem, I realize now, is that I use django's built in User class with a user profile like this:

def create_user_info(sender, instance, created, **kwargs):
    if created:
        UserInfo.objects.create(user=instance)

post_save.connect(create_user_info, sender=User)


class UserInfo(models.Model):
    user = models.OneToOneField(User)
    pen_name = models.CharField(max_length=30)
    activated = models.BooleanField()
    activation_key = models.CharField(max_length=40)
    def __unicode__(self):
        return self.email + '-' + self.pen_name

I need to filter by the user profile. So, in short, how do I filter by a key or, more specifically, a user profile.

first of all, add a related_name to your UserInfo:

class UserInfo(models.Model):
    user = models.OneToOneField(User, related_name='profile')
    ...

https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.ForeignKey.related_name

and then you can do something like this:

User.objects.filter(profile__activation_key=word).exists()

hope it helps :)

I am not 100% sure what exactly you want to achieve, but here are two answers which might be fitting your needs:

Generally

First you need to connect the Django built-in user model with your UserProfile model. This is done in settings.py setting the AUTH_PROFILE_MODULE setting

AUTH_PROFILE_MODULE = 'myapp.UserProfile'    # replace `myapp` with your application name

Answer 1

You can get the user profile for a specific user via user.get_profile() assuming user is a already existing instance of django.contrib.auth.User .

Answer 2

You can query your UserProfile model first by whatever key you want to query for and then map the result set back to your user directly, eg:

from myapp.models import UserProfile

profiles = UserProfile.objects.filter(activation_key='abcdef')
for profile in profiles:
    print profile.user    # this is the profiles connected user instance

First, you don't really care if 2 users have the same activation key. This case is so rare that it can't be a target for any kind of attack.

Second, why not include the username in the activation URL? This way you are assured to have an unique activation URL for each user. ex: yourwebsite.com/users/activate/{username}/{activationcode} .

Third, you can use an UUID instead of random. UUID are granted to be unique (well not exactly but 99.99% of the time). http://docs.python.org/library/uuid.html

Fourth, do you really need to keep the activation code in the profile informations? Why not create an independent activation table, you can even set the primary key to be the activation code. Most of the time, it is better to separate informations that won't be used much from the ones you will use often.

Fifth, You don't really need to query the User table at all. You just need to query the UserProfile table and check if the activation key exists. Then and only then, you can use the OneToOne relation to map to the original user.

You don't even need to add the related_name value to the user relationship. The following query works for your profile model.

User.objects.filter(userinfo__activation_key=word).exists()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM