Creating Schema for Users with Friends without many to many relationship? - python

I'm working on my first Django app and trying to create the models for it but am stuck on how to create what I think should be a simple model relationship. I want to create a model for a user, with typical attributes like username, password(hash of course), date joined, etc. Then would like to be able to link this user to all of their friends/followers on the site. But where i'm stuck is how i setup that relationship since one user can have many friends, I can key off that primary key for the User table, but how do i create a model for the friends table that has the primary key for the user table serve two functions, one as the mapping to the user, and the mapping to the primary key for all of their friends?
from django.db import models
class User(models.Model):
username = models.CharField(max_length=50)
password = models.CharField(max_length=200)
dateJoined = models.DateField('date joined')
class Friends(models.Model):
user = models.ForeignKey(User)

First, I would recommend you not create your own User model, instead use the one that comes built in Django. It takes care of all the fields that you're looking for.
Second, I would also create a "profile" model and store my friends in that. Have a look here on what profiles are: http://docs.djangoproject.com/en/1.2/topics/auth/#storing-additional-information-about-users
Third, in your profile model, I would add a field for friends exactly as it's shown here: http://docs.djangoproject.com/en/1.2/ref/models/fields/#django.db.models.ManyToManyField.symmetrical
You can then access friends for a user like user.get_profile().friends.all(). A bit verbose, but keeps things clean.

CREATE TABLE friends (user_id int, friend_id int)
Both columns reference the user ID. I don't know Django models, but guessing from your code, it'd look like:
class Friends(models.Model):
user = models.ForeignKey(User)
friend = models.ForeignKey(User)

Related

When to use each model relationship in Django?

I've been reading through the Django documentation and looking over some of the other answers on the site for a couple of hours now, yet I still can't get it to sink in. I know this isn't Django specific, but the examples I use will be from a Django project.
My question boils down to when is it appropriate to use each:
Many-to-many relationships
Many-to-one relationships
One-to-one relationships
One-to-one, more or less makes sense to me.
Now for the other two. While I understand the differences between them in isolation, when it comes to using them practically in a project, I get confused. Here is an example:
class User(AbstractUser):
pass
class Listing(models.Model):
title = models.CharField(max_length=64)
description = models.TextField()
class Watchlist(models.Model):
user = models.ForeignKey(User, related_name='watchlist', on_delete=models.CASCADE)
item = models.ManyToManyField(Listing)
class Comment(models.Model):
user = models.ForeignKey(User, related_name='comments', on_delete=models.SET_NULL)
comment = models.TextField()
Would this be the correct use of Many-to-one(ForeignKey) and Many-to-many?
Should Watchlist.item be a ForeignKey? Or is M2M correct?
Wouldn't it simplify to make the 'Watchlist' part of the User class? (give them an empty list to populate with listing ID's)
Why is Watchlist.user not a One-to-one relationship, if each watchlist belongs to a single user, and a user can only have one list?
Apologies for my stupidity, I just can't get this to sink in!
Thank you.
edit: Context, the models are from a 'learning' project I was working on intended to be an auction site, similar to eBay. The watchlist is sort of a 'wish' list... for the user to watch an item, not for site to watch a user!
To explain it simply these django-models or objects represents tables in your database and the fields are like the columns in them. So with a one-to-one relation you can only have one row in one table relating to one row in another table. For example one user in the user table (represented by one row) can only relate to one row in a profile table. But your user can have many comments, so this would be a one-to-many/foreignkey relation (if you set unique=true on a fk, it will in practice function as 1:1). If the users can collaborate on writing comments, or for example as here on stackoverflow where users can edit other users comments, that would be a many-to-many relation.
Database design can be complicated/complex, especially using an ORM without basic knowledge of SQL and how it all works beneath. In general it requires a bit of planning even for a simple application.

Python - Multiple user types implementation in Django 2.2

I'm working on a project using Python(3.7) and Django(2.2) in which I have to implement four types of users as (1): Personal - Below 18 (2): Personal 18 or Above (3): Coach (4): Parent, each user will share some basic fields like First & Lat name, Email, Gender, Account type but also will have different permissions, dashboards and functions and need to provide different signup forms but one login form. Along with that I also need to use the Email as the username for this project.
what is a good and scalable approach? any resource or tutorial links will be appreciated.
and how can I utilize django-allauth in this scenario?
and here's how I was thinking to implement this:
class BaseUser(AbstractBaseUser):
email = models.EmailField(max_length=255, unique=True)
is_personal_above_18 = models.BooleanField(default=False)
is_personal_below_18 = models.BooleanField(default=False)
is_parent = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
def __str__(self):
return self.email + '/s account'
class PersonalAccountAbove18(BaseUser):
customer_id = models.BigIntegerField(default=generate_cid())
class PersonalAccountBelow18(BaseUser):
customer_id = models.BigIntegerField(blank=False)
class ParentAccount(BaseUser):
customer_id = models.BigIntegerField(default=generate_cid())
The reason to use customer_id in each model is because later we need to connect different accounts, for example if someone wants to create an as pERSONAL - BELOW 18 he will require to provide a customer_id of his Parent account.
See if making an extra field in the BaseUser model for separating the accounts work but if it seems complex and you want to accommodate a whole bunch of customization for each then it does make sense to create a separate model for each.
If the latter is true then in theory, you should use a single User model and keep a one-to-one from the separate accounts to this model. And keep the common logics in the User model while keeping those specific to the account models in them.
The implementation you wrote has some issues:
Your all individual *Account* models inherit from BaseUser and also has a one-to-one with it; this will cause all sorts of havocs down the line regarding field mappings and retrieval. BaseUser is a concrete model so only keep the one-to-one relation and inherit from django.db.models.Model e.g:
class PersonalAccountAbove18(Model):
user = models.OneToOneField(BaseUser, on_delete=models.CASCADE, primary_key=True)
The coutomer_id field is not necessary as Django has an id (AutoField) that uniquely identifies each row so you can leverage that. Also as you have not used primary_key on the customer_id field so id field will be created anyways. If for some reason you need to have the BigIntegerField (because of scalability in the long run) you better make that the primary_key so the id field is not created (assuming generate_cid() returns unique values for the table each time):
class PersonalAccountAbove18(Model):
user = models.OneToOneField(BaseUser, on_delete=models.CASCADE, primary_key=True)
customer_id = models.BigIntegerField(primary_key=True, default=generate_cid)
You were setting default=generate_cid() which means all the instances will have the same default as the default is being set at definition time. You need to drop the call to generate_cid (i.e. default=generate_cid) just like I did in the above point to make the evaluation when the field value is actually needed for an instance
If you want to use permission related fields (is_superuser, groups, user_permissions) and associated logics in the BaseUser model, you also want to inherit from PermissionsMixin (django.contrib.auth.models.PermissionsMixin):
class BaseUser(AbstractBaseUser, PermissionsMixin):
...
You would also want to create a custom model manager to update create_user/create_superuser methods to use the email field for user creation instead of the username field. You can take inspiration from here.
It would make sense to rename the UserBase model as User to keep consistency with the Django procedures/methodologies.

Django admin edit integer field

I have a model with two integer fields which are supposed to be foreign keys. In my admin view, those two fields are editable but I would like to display a search icon next to the field, so I can retrieve the id of another model and append to the field. Does django have this feature?
class Linkage(models.Model):
user_id = models.IntegerField(default=1)
parent_id = models.IntegerField(default=0)
If your model has 2 fields that should actually be foreign keys, then you need to use ForeignKey instead of IntegerField as so:
from django.db import Models
from app.models import yourModel
class Linkage(models.Model):
user_id = models.ForeignKey(yourModel)
parent_id = models.ForeignKey(yourModel)
This Django feature will take care of linking your Linkage to your other model of choice automatically. In the admin, you will no longer need to set an integer with the id of the foreign key, you will be able to simply select an instance of the linked model.
You can read more about Django fields references here.
EDIT: In the way you designed yoour models, there might for example not be a parent_id, so you can add options such as null=True to the parent_id field as so:
parent_id = models.ForeignKey(yourModel, null=True)
I strongly recommend that you read the Django documentation, it is really good for beginners as it is very detailed and clear. You can access the documentation here.
They also have a set of tutorials to get you through the steps and introduce you to the different basics you need to know to get started with Django here.

Setting up two different types of Users in Django 1.5/1.6

Please note--this is an updated version of my original question on this subject, but deserves to be asked again with the change in how Django deals with users and authentication.
I'm working on a website with two very different kinds of users--let's call them Customers and Store Owners. Both register on the site, but have very different functionality. Customers simply have a single profile and can shop among the stores that they like. Store Owners have a single account but can have access to multiple stores, and each store can have multiple Store Owners.
The exact details of the models don't matter, but the two types of users would require very different fields. The models ideally would look something like this:
Customer
email (username)
password
name
address
time_zone
preferred_shipping
favorite_stores (many-to-many field)
...
Store Owner
email (username)
password
name
balance
stores_owned (many-to-many field on Stores)
stores_managed (many-to-many field on Stores)
...
Originally, when Django had poor custom user support, I had a UserProfile class with some additional fields with a OneToOne on User, and then additional Customer and StoreOwner classes that were OneToOne on UserProfile. This didn't work very well.
Given the changes in Django 1.5/1.6, I'm trying to come up with the best way to structure this. Right now, I have the following:
class CustomerUser(AbstractBaseUser):
...
class StoreOwnerUser(AbstractBaseUser):
...
But because there would be two types of user, I can't set AUTH_USER_MODEL to only one of them.
What is the best way to structure this so that I can have two different types of users with different fields, without causing me any problems in user authentication, user creation, or the admin?
Also, how will I be able to tell from login alone whether this user is a CustomerUser or a StoreOwnerUser?
It seems like there are some common features and uncommon features to your user types. If there are common features in your user types that Django's default User model doesn't support out of the box, you should subclass it directly.
Adding in extra, uncommon features to your user types are best done not by subclassing but by using a profile. My rationale for this is because your authentication for these user types doesn't fundamentally change, but details about the user does depending on the type of user it is. To accomodate this, you create a separate model with these details and reference your User class as a OneToOne/ForeignKey relationship (depending on your design).
You can make modifications to your user creation process to identify what kind of user type it should be, and set its associated OneToOneField/ForeignKey (depending on your design) to the appropriate customer type model.
By doing it this way, you should only have one AUTH_USER_MODEL, and you should be able to handle details for your different customer types.
What is the best way to structure this so that I can have two
different types of users with different fields, without causing me any
problems in user authentication, user creation, or the admin?
You actually only have one type of user. Just that some users have specific properties set and others do not. Consider how django has "users" and "admins". They are the instances of the same model, but with different properties and permissions.
You should approach it similarly. Have one user model for your entire application. You can set properties/methods in your custom user class to identify what flags this user has set (which would determine the "type" of user there is).
Also, how will I be able to tell from login alone whether this user is
a CustomerUser or a StoreOwnerUser?
You can use the user_passes_test decorator, which takes an argument that is a function name and will only process the view if the function returns a truth value.
Create a BaseUser which extends Django's Abstract base User
Create two Sub Classes Named CustomerUser and StoreOwnerUser which extends BaseUser
from django.db import models
from django.contrib.auth.models import AbstractUser
class BaseUser(AbstractUser):
# all the common fields go here, for example:
email = models.EmailField(max_length=10,unique=True)
name = models.CharField(max_length=120)
class StoreOwnerUser(BaseUser):
# All Store Owner specific attribute goes here
balance = models.some_balance_field()
stores_owned = models.some_stores_owned_field()
class Meta:
verbose_name = 'Store Owner'
class CustomerUser(BaseUser):
# All Customer specific attribute goes here
customer_id = models.CharField(max_length=30, unique=True)
address = models.some_address
time_zone = models.something...
...
class Meta:
verbose_name = 'Customer'

get user profile in django

hello i'm new in python and django
I need a view that get current user profile I know I shoud use get_profile from User but I don't know how to use it . i read the django document and It didn't help me.
this is what I found from doc:
from django.contrib.auth.models import User
profile=request.user.get_profile()
Django's documentation says it all, specifically the part Storing additional information about users. First you need to define a model somewhere in your models.py with fields for the additional information of the user:
models.py
from django.contrib.auth.models import User
class UserProfile(models.Model):
# This field is required.
user = models.OneToOneField(User)
# Other fields here
accepted_eula = models.BooleanField()
favorite_animal = models.CharField(max_length=20, default="Dragons.")
Then, you need to indicate that this model (UserProfile) is the user profile by setting AUTH_PROFILE_MODULE inside your settings.py:
settings.py
...
AUTH_PROFILE_MODULE = 'accounts.UserProfile'
...
You need to replace accounts with the name of your app. Finally, you want to create a profile every time a User instance is created by registering a post_save handler, this way every time you create a user Django will create his profile too:
models.py
from django.contrib.auth.models import User
class UserProfile(models.Model):
# This field is required.
user = models.OneToOneField(User)
# Other fields here
accepted_eula = models.BooleanField()
favorite_animal = models.CharField(max_length=20, default="Dragons.")
def create_user_profile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
post_save.connect(create_user_profile, sender=User)
Accessing the Profile
To access the current user's profile in your view, just use the User instance provided by the request, and call get_profile on it:
def your_view(request):
profile = request.user.get_profile()
...
# Your code
Basically django User models will provide access only for the fields ( firstname,lastname,email,password,is_staff,is_active,last_login).
However if we want to add any extra fields to this model, say we need to add a new column named dateofbirth for every user, then we need to add a column named DOB into User model. But this is not possible as we aren't able to edit django User models.
To achieve this either
1.We can have a separate new table with email id & DOB column, such that a column in User model is mapped with a column in the new table. But this will create a new db instance for every db request. Say if u want to find the DOB of a customer,
First we need to fetch the value of mapped id of a customer from the
User table.
WIth the above value, get DOB from the new table.
In the second method,
Instead of using django User model, use your own customize model with all the fields needed. However if any updation related to security or some enhancement made to django User model we can't use it directly. We need to do more code changes at our end( wherever we use our customize models.) This will be a bit pain for a developer to identify the code & make changes.
To overcome the above issues, django introduce django profile which is very simple and more flexible. The advantages are
Updation/enhancement to the User model can be applied without modifying the code much
No need of creating new db instance to fetch the extra values.
Since the field has onetoone mapping deletion of data from one table will delete others also.
More secure, since we use django models ( no sql injection)
How to Use this:
In settings.py create a variable AUTH_PROFILE_MODULE = "appname.profiletable"
In models.py, create a new table with the fields needed and make sure that the id in User model is onetoone mapped with new table.
create a signal which inserts a row into the new table whenever a new entry is added into User model.
The value in the new table can be accessed using User object itself.
Say, we created a new table extrauser which has DOB, emailid. To find the DOB of a customer, use
a=User.objects.get(email='x#x.xom')
a.get_profile().DOB will give the dateofbirth value from extrauser table.
Hope the above details make you clear in understanding django profile. Incase of any help further, let me know. I have used django profile in my project.
Old question but I thought anyone seeing it today may benefit from this:
Django 1.5 adds the ability to - easily - extend the User model. This may be preferable as you now only got one object to deal with rather than two! Seems the more modern way.
https://hurricanelabs.com/blog/django-user-models/
You need to specify which class is your "Profile" by setting AUTH_PROFILE_MODULE = 'accounts.UserProfile' (for example)
https://docs.djangoproject.com/en/1.4/topics/auth/

Categories

Resources