I am designing a model, view and template for my news aggregation app. I want the template to offer the user a multiple-choice field form with options from the database. How do I design this in my model?
I was reading the Django documentation about ManyToManyField (the one with journalists and articles) but I don't think that is quite the right relationship because in my case, "articles" can exist without a journalist and journalist without an article.
I have Users. I have Streams. Streams is a collection of news sites a user can sign up to follow and see aggregated headline snippets, such as from CNN,Twitter, Google News, etc etc. A Stream can exist with no Users. A Stream can have many Users. A User can have no Streams, in fact all user accounts start in my app with no Streams until they choose one. A User can have many Streams.
In the template, I want to create a form with the list of all the Stream options in the database (this will likely change as I ad more options in the future). When a User selects a Stream, it will be added to their dashboard view. They can add and delete Streams. However, there is only 1 Twitter, 1 Google News, etc source. I can't use the typical choices option in the User model, I want it to be "dynamic" and pull straight from the Streams database.
This is what I have now but I know it's not right:
streams/models.py
from django.db import models
from django.contrib.auth.models import User
class Stream(models.Model):
user = models.ManyToManyField(User, blank=True, null=True)
name = models.CharField(max_length=30)
user/models.py
from django.db import models
class User(models.Model):
name = models.CharField(max_length=30)
'''''
#TODO: make this dynamic, streams is pulling from Streams model
streams = (
('Google News'),
('Yahoo News'),
('Twitter'),
('CNN'),
('New York Times'),
('NBC News'),
('Huffington Post')
)
stream_choices = models.CharField(max_length=9, choices=streams)
'''''
Just add one model for list of streams and another model for user selected streams
class Stream(models.Model):
name = models.CharField(max_length=50)
class UserStream(models.Model):
user = models.ForeignKey(User)
name = models.ForeignKey(Stream)
That's it. Insert possible streams to Stream model and user selected streams to UserStream model.
The ManyToManyField already implicitly creates the 'intermediary table' described in the accepted answer. As per the documentation:
Behind the scenes, Django creates an intermediary join table to
represent the many-to-many relationship.
You can pass a callable to the choices field of the ChoicesField which you display to the user, allowing the list of available choices to be determined dynamically when the form is generated.
The list of valid choices in the User<->Stream relationship is already constrained by the relationship, so there's no benefit in specifying the available choices on the model field.
Related
I'm creating a simple weight management application where users can register, login and update information such as weight, body measurements etc. I've not used Django for a little while and slowly learning best practices from where i left off a little while ago.
I'm using the django-allauth to manage the user registration as this allows people to login with Facebook etc.
I've created a simple app called 'Stats' with a ForignKey to the Users.
class Stat(models.Model):
user = models.ForeignKey(User, default=False)
height = models.CharField(max_length=20)
weight = models.CharField(max_length=20)
waist = models.CharField(max_length=20)
hips = models.CharField(max_length=20)
upperleg = models.CharField(max_length=20)
upperleg = models.CharField(max_length=20)
calf = models.CharField(max_length=20)
bodyfat = models.CharField(max_length=20)
What i would like the user to be able to do is login and update stats on a daily / weekly basis. Then to be able review previous stats. This will probably be done via a model form based on the above approach. I will add more complexity as time goes on.
Is there another way to do that would have any advantages? If the best approach is the best? Is there a way i can list all the objects from that model inside the users page in the admin to be able to reviews users stats easily enough?
Thanks in advance.
It is recommended that you create a separate user profile model for app-specific functionality that relates to a User of your app. It's best to create a UserProfile model which has a OneToOneField link to User object. Then, your Stat model can ForeignKey to UserProfile instead of User. This is to provide abstraction to the User object and give flexibility if you decide to create another Django app in the same project that requires different specifications for the user. Also, with UserProfile you can add customised fields that are app specific.
Another thing you can do to improve this modelling is create separate entities for each stat. For example, HeightWeightStat, WaistStat. But, this is not completely necessary and totally depends on your preference.
To display all of the user related Stat instances in the admin page, use Django Admin inlines: https://docs.djangoproject.com/en/1.10/ref/contrib/admin/#inlinemodeladmin-objects
I am designing a Django 1.8 application in which I have the concept of trials and assessors. I will have six assessors, who will use the Django admin to log in and make assessments.
I want each trial to have two attached assessors. How can I use the Django User model in models.py to ensure that the assessors are Users, and can be managed using the full power of Users?
Right now I have this, in which the assessors are not Users, but are just ordinary models:
class Assessor(models.Model):
name = models.CharField(max_length=200)
class Trial(models.Model):
title = models.CharField(max_length=800)
publication_date = models.DateField()
first_assessor = models.ForeignKey(assessor)
second_assessor = models.ForeignKey(assessor)
I want the assessors to be Users, so that I can manage them in the usual way through the User tables, but I don't know how to make this change.
They probably don't need any custom fields on top of the standard User attributes.
(NB: I don't need full-on permissions management within the admin, it's OK for any assessor to be able to edit the trial.)
UPDATE: Apologies, this is rather hard to explain! I don't care about the Django front-end at all, only the admin. I want a user to be able to log into the admin, see all the trials on which they are a primary assessor, and edit those trials. I'm not sure if it's best to do this with the User model, or not.
Instead of two foreign keys add a manytomany relation from Trail to user. Later, if you want you can add more assessors to a trail.
You can do like:
from django.contrib.auth.models import User
class Trial(models.Model):
title = models.CharField(max_length=800)
publication_date = models.DateField()
assessors = models.ManyToManyField(User,related_name="trials")
You can add assessors to Trial like:
trial = Trial.objects.get(id=give-trial-id)
user = User.objects.get(id=give-assessor-id)
trail.assessors.add(user)
You can get more info about manytomany here
I just saw your UPDATE. Any one who logs in to admin will have access to all objects of all models.
In your case all assessors who login to admin will have access to all trails irrespective of they are assigned to it or not.
If you want Filter django admin by logged in user then refer this question
So I am trying to implement a user favorites system in Django. I need to store the time at which a Gallery object was favorited, so I am using Django's many to many through pattern. As you can see below I have a Gallery object which has the many to many relationship to Users who have favorited it, and the Favorite object which has a many to one with both User and Gallery. I would like to do some things like display a page with all the user's favorites on it, query a users favorites to see if a certain Gallery is in them, etc. So basically be able to get the galleries a certain user has favorited. What is the easiest way to do this with the ORM, or is this something I would need to write raw SQL for?
class Gallery(models.Model):
favoriters = models.ManyToManyField(
User, through='Favorite', null=True, related_name="favoriters")
def __unicode__(self):
return self.name
class Favorite(models.Model):
user = models.ForeignKey(User)
gallery = models.ForeignKey(Gallery)
date = models.DateField(auto_now_add=True)
Thanks.
You can easily do this with the Django ORM.
display a page with all the user's favorites on it
user.favoriters.all() # though that is not a good related_name
query a user's favorites to see if a certain Gallery is in them
if user.favoriters.filter(pk=my_gallery.pk).exists():
pass
See the documentation for more examples.
I am currently working on a django application and I am trying to develop a little recommendation system for it. I already extended the User model and made a user profile in an app called profile like so:
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class UserProfile(models.Model):
user = models.OneToOneField(User)
skills = models.CharField(max_length=150)
skillsNeeded = models.CharField(max_length=150)
bio = models.CharField(max_length=300)
industry = models.CharField(max_length=70)
occupation = models.CharField(max_length=70)
User.profile = property(lambda u: UserProfile.objects.get_or_create(user=u)[0])
However now I made a separate app within the same Django project called matches and I was wondering how I could pull the current user's data from their profile as well as getting a list of every other user that is in the database. I am using postgresql as my database management system, any ideas or help would be much appreciated. I would think I would need to find out where the profile data is stored in the database and make manual sql queries. However, I am still relatively new to django and this is my first time using postgre for dbms instead of mysql.
Manual SQL queries are almost never necessary. It sounds to me like you just need to use the data models in their basic form to do queries. For example, the current user is available in your views as request.user, so you could get their profile like so:
UserProfile.objects.get(user = request.user)
And getting all of the users is as easy as:
User.objects.all()
I think there is a slight confusion here. Apps in Django are just a heavy-sounding name for a module. Usually, all of your different "apps" will share the same database and can and should import other apps' models to get their work done.
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'