How to create an associative entity with extra fields in django - django

I am facing the following problem.
I have to entities,Proposal and User, a user can vote up or down several proposals and a proposal can have several votes from several users.
This relation between Proposal and User is Many to Many, the thing is that here I want to add an extra field to indicate if the Vote is positive or negative.
Is there are a way to do this in Django using ManyToManyField?, or the only way to do this is creating the model entity of Vote by hand like this:
class Vote(models.Model):
user = models.ForeignKey(User,related_name='voter',null=False)
proposal = models.ForeignKey(Proposal,related_name='vote_to',null=False)
opinion = models.BooleanField(blank=False,null=False)
And in case I have to do it by hand, how I can do for saying to Django that the primary key is the composition of the others Foreign keys

Creating a separate model Vote is a better way to do it, because a vote is specific to a particular proposal for a particular user, so it can't be directly linked to the Proposal model or to the User model.
See this article regarding mutiple column primary keys support in Django, and also this answer.

Related

How to write relation where first model is connected to exactly four instances of another in Django?

Let's say I have two very basic model classes - for simplicity let's name them a Plan and a Task. My goal is to force every plan to have exactly 4 distinct tasks (order doesn't matter). Is there some good practice for this "many-to-many with a fixed quantity of related instances" case?
from django.db import models
class Task(models.Model):
name = models.CharField(max_length=20)
class Plan(models.Model):
name = models.CharField(max_length=20)
# four_tasks = ?
I searched through Django documentation but there's no answer there (or maybe I didn't know how to search for it). I thought of 4 separate foreign keys (which should be possible by setting related_name for those) in Plan, or maybe standard many-to-many many relations. Both solutions require additional checks to ensure that there are actually 4 different tasks and they look ugly to me.
In my opinion, from the point of view of databases, the best practice would be to have the 4 separate foreign keys (as you thought) as a primary key (composite key).
This can be achieved in Django using the uniqueConstraint which is the preferable way over unique_together option:
UniqueConstraint provides more functionality than unique_together. unique_together may be deprecated in the future.
EDIT: If you are wondering how to use it, here is an answer

Django: Having multiple foreign keys stored in the same attribute of a model

My question is related to this one, where the author wanted to store a reference to a model in the attribute of another model using Django's models.ForeignKey field type. My question is, would the exact same method work, if an article had multiple authors, or is something additional needed to establish this?
If an article can have multiple authors and each author can have multiple articles, then you want to use a ManyToManyField.

What are the pros and cons of using GenericForeignKey vs multitable inheritance vs OneToOneField?

Context
I am in the process of modeling my data using Django models.
The main model is an Article. It holds the actual content.
Then each Article must be attached to a group of articles. Those group may be a Blog, a Category a Portfolio or a Story. Every Article must be attached to one, and exactly one of those. That is, either a blog, a category or a story. Those models have very different fields and features.
I thought of three ways to reach that goal (and a bonus one that really looks wrong).
Option #1: A generic foreign key
As in django.contrib.contenttypes.fields.GenericForeignKey. It would look like this:
class Category(Model):
# some fields
class Blog(Model):
# some fields
class Article(Model):
group_type = ForeignKey(ContentType)
group_id = PositiveIntegerField()
group = GenericForeignKey('group_type', 'group_id')
# some fields
On the database side, that means no relation actually exists between the models, they are enforced by Django.
Option #2: Multitable inheritance
Make article groups all inherit from an ArticleGroup model. This would look like this:
class ArticleGroup(Model):
group_type = ForeignKey(ContentType)
class Category(ArticleGroup):
# some fields
class Blog(ArticleGroup):
# some fields
class Article(Model):
group = ForeignKey(ArticleGroup)
# some fields
On the database side, this creates an additional table for ArticleGroup, then Category and Blog have an implicit foreign key to that table as their primary key.
Sidenote: I know there is a package that automates the bookkeeping of such constructions.
Option #3: manual OneToOneFields
On the database side, it is equivalent to option #2. But in the code, all relations are made explicit:
class ArticleGroup(Model):
group_type = ForeignKey(ContentType)
class Category(Model):
id = OneToOneField(ArticleGroup, primary_key=True)
# some fields
class Blog(Model):
id = OneToOneField(ArticleGroup, primary_key=True)
# some fields
class Article(Model):
group = ForeignKey(ArticleGroup)
# some fields
I don't really see what the point of that would be, apart from making explicit what Django's inheritance magic implicitly does.
Bonus: multicolumn
It seems pretty dirty so I just add it as a bonus, but it would also be possible to define a nullable ForeignKey to each of Category, Blog, ... directly on the Article model.
So...
...I cannot really decide between those. What are the pros and cons of each approach? Are there some best practices? Did I miss a better approach?
If that matters, I'm using Django 1.8.
It seems noone had advice to share on that one.
I eventually chose the multicolumn option, despite having said it looked ugly. It all came down to 3 things:
Database-based enforceability.
The way Django ORM works with the different constructs.
My own needs (namely, collection queries on the group to get the item list, and individual queries on the items to get the group).
Option #1
Cannot be enforced at the database level.
Could be efficient on queries because the way it is constructed does not fall into usual generic foreign key pitfalls. Those happen when the items are generic, not the collections.
However, due to how the ORM handles GFK, it is impossible to use a custom manager, which I need because my articles are translated using django-hvad.
Option #2
Can be enforced at the database level.
Could be somewhat efficient, but runs into ORM limitations, which is clearly not built around this use. Unless I use extra() or custom queries alot, but at some point there is no reason to use an ORM anymore.
Option #3
Would actually be a bit better than #2, as making things explicit allows easier query optimisation while using the ORM.
Multicolumn
Turns out not being so bad. It can be enforced at the database level (FK constraints plus a manual CHECK to ensure only one of the columns is non-null).
Easy and efficient. A single intuitive query does the job: select_related('category', 'blog', ...).
Though it does have the issue of being harder to extend (any new type will require altering the Article's table as well) and limiting the possible number of types, I'm unlikely to run into those.
Hope it helps anyone with the same dilemma, and still interested in hearing other opinions.

Which model should be higher?

Which model should be higher? I still have a error.
class Post(models.Model):
blog = models.ForeignKey(Blog)
class Blog(models.Model):
post = models.ManyToManyField(Post,blank=True,null=True)
Essentially, you don't need the foreign key from Post -> Blog. See the docs. ManyToMany give you the reverse direction as part of their default behaviour.
Edit (as per #Tony Blundell), you can specify models via a string for foreign keys in cases of order-of-definition issues. However, in this case this (I assume) this isn't what you are trying to do. In your case, scrap the ForeignKey under Post, and then you can make use of the reverse behaviour of M2M to represent that relationship.
Also I'd check out the docs, as they are really good for the Django project and cover all of the basics. The Tutorial, if you haven't done it yet, is very useful.

Differences between one-to-one and foreign key relationships?

Can someone explain the significance of specifying a relationship in a Django model as one-to-one as opposed to just a foreign key?
Specifically, I'm wondering what advantages you get from specifying a relationship as 1-1, if any.
Thanks so much.
The OneToOneField evolved in Django after 'ForeignKey'. Conceptually a ForeignKey with unique=True constraint is similar to OneToOneField.
So if you want to ensure that every picture has one user and vice-versa use a OneToOneField.
If you want one user to have any number of pictures use a ForeignKey.
The way things are selected are also different. In case of doing OneToOneField, you can do user.picture and get the picture directly. In case of ForeignKey you will do user.picture_set[0] to get the first picture or access all the pictures associated with that user.
MultiTableInheritance implicitly uses OneToOneField internally and you can see where the concept originated from.
The additional constraints of a 1-1 provide a tighter and richer conceptual model but can also provide insight that can allow for more intuitive retrieval. As a many to one represents a parent/collection relationship there is an unclear cost associated with the retrieval of any given collection for a particular entity. Since a 1-1 provides a flat mapping there is also a flat cost of retrieval. This would lead to things like preferring eager fetching when relevant, as the join will be be able to be easily optimized and the resultant data set will be a known size.
They are not the same; think about it:
If you have a one-to-one relationship between a User and a Picture, you are saying that a user can only have one picture (and a picture can only have one user). If you were to have a Picture with foreign key to User, then you are saying that a picture must have exactly one user, but a user may have 0, 1 or many pictures.
Django's Foreign Key is a many to one relationship. Now, the difference between them is the same as the difference between a One-To-One and Many-To-One relationship. For example, if you have User and Profile entities. You would like to add a constraint that each User could have one and only one Profile. Then, using a django's one to one field would create a restriction on the database level so, that you won't be able to relate User to multiple Profiles or vice-versa. Where as using Foreign Key wouldn't provide this constraint.