Django ORM - querying many to many through models? - python

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.

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.

Django multiple-choice field of options in database

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.

Updating user information from separate model Django

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

Django: Including standard User table as foreign key in my models?

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

Django Admin Bulk Edit on Many to Many Relationship

In my Django app, I have two models: Publications and Tags. These two models have a many to many relationship:
class Tag(models.Model):
title = models.CharField(max_length=50,)
class Publication(models.Model):
title = models.CharField(max_length=200,)
tags = models.ManyToManyField(Tag, blank=True, related_name="publications", null=True)
On the admin site, I'd like to be able to make bulk edits to the publication objects. Specifically, I'd like to be able to update the tags for a group of publications.
For example, if I choose from the publications page, "publication 1, publication 2, and publication 3," and create an action that says "change_tags" and I hit go, I see the list of tags in the database and I can select from that list and add the chosen tags to all three publications.
I don't know if there is a way to do this. I checked the Django docs on adding actions: https://docs.djangoproject.com/en/dev/ref/contrib/admin/actions/#ref-contrib-admin-actions but the example given doesn't address the complexity of what I am trying to do.
After some further investigation in the Django docs, I discovered that I can add an action that directs the admin user to an intermediate page that I can create to make whatever edits are necessary. https://docs.djangoproject.com/en/dev/ref/contrib/admin/actions/#actions-that-provide-intermediate-pages

Categories

Resources