Setting up a weird model in django? - django

This may be difficult to explain.
I'm a little new to django and the whole idea of models.
Let's say I'm making an article app, where each article has a creator, but other users can edit the article at will. I'm having a little difficult on how to create the models for this.
Firstly,
I extend the user profile with the following:
class UserProfile(models.Model):
#Required field:
user = models.OneToOneField(User)
#Other Fields:
headline = models.CharField()
industry = models.CharField()
article= models.ForeignKey(articleModel.article)
Here is the first place I'm getting confused, do I put the foreignkey field in the user model? My reasoning for it being placed here is because each article can have many editors.
Now here is my article model:
class article(models.Model):
#primary key is already true
creator = models.ForeignKey(userModel.UserProfile)
title = models.CharField()
text = models.TextField()
Over here, I put the ForeignKey field so it would relate back to the creator, because every article has a single creator. (As a side note, I do want to make it so an article can have multiple creators, but I don't know what to do in this scenario).
I'm finding it a bit odd that the UserProfile model is referencing the article model, and the article is referencing it back. Can someone please help me unjumble my brain?
Thank you.
:)

As simple as possible
from django.db.models import *
from django.contrib.admin.models import User
# UserProfile should be provided by django-profiles
class UserProfile(User): # Subclassing user creates an automatic 1-1 called user
headline = CharField()
industry = CharField()
class Article(Model):
# ALWAYS primary key to User, not UserProfile
creator = ForeignKey(User, related_name='articles_created')
contributors = ManyToManyField(User, related_name='articles_edited')
created = DateTime(auto_now_add=True)
modified = DateTimeField(auto_now=True)
title = CharField()
text = TextField()
class Meta:
order = ['created', 'title']
fun stuff:
creator = Article.objects.all()[:1][0].creator.getUserProfile().headline
considder using django-versions if you want to keep track of edits.
class Article(VersionedModel)
EDIT: actually subclasses user

Nothing "weird" here. This is no such a django problem than a database structure problem. You need to read about 1 to 1, 1 to n and n to n relationships between tables.
Do you really need to record all editors of an article ? An article has many editors, and a user can edit many articles, so this is a many to many relationship. Here's how do do it in django.

Perhaps another field in your article model for last editor would provide you with the information you need.
lastEditor = models.ForeignKey(userModel.UserProfile)
If you really want to keep all editors you will need to implement another model which records something like: article_id, editor and edit time (maybe even the article text if you are interested in changes). You could then query this medel based on the current article to obtain a list of all editors.
you could do the same with: article_id and creator to obtain a list of creators of an article (this would replace the article field in your UserProfile class)

Related

django share document with user

I have a my django site where admin user will have to share documents with other user type called accountant.for example admin has something called documents in the sidebar when clicked it shows the list of documents related to the admin beside every document we will have a button share when clicked it shows the list of accountants when selected and shared the documents will be listed on the accountant's documents list page.there are two different login interfaces.how can i achieve this i have model called Document and the user type model Accountant.how should the relations should be and what should be the logic in views.
class Document(models.Model):
name = models.Charfield()
file = model.Filefield()
class Accountant(models.Model):
name = models.Charfield()
your question is general you have to ask more specifically where exactly your problem is.
I guess you dint know how the relationship between models is going.
you can use many-to-many relationships to solve your problem.
something like this:
class Document(models.Model):
name = models.Charfield()
file = model.Filefield()
has_access_to = models.ManyToManyField(Accountant)
add like this:
# document_instance is a document object and accountant instace is the same
document_instance.has_access_to.add(accountant_instance)
for showing use this :
accountant_instance.document.all()
I hope this helps you.

How to display manytomany field in django admin with a related model in a user-friendly way?

I'm struggling to display a manytomany field in the admin with the related model in a user-friendly manner. The project is already up and running so adding a through table is not preferred.
The set-up is something along these lines;
class User(AbstractUser):
is_member_of_organization = models.ManyToManyField(Organization, blank=True, verbose_name=_("is member of organization(s)"), related_name='orgmembers')
class Organization(models.Model):
name = models.CharField(max_length=60, verbose_name=_("organization name"))
the only reasonable way I manage to display the related users with organization admin is via a TabularInline
admin.py
class UserOrgAdminInLine(admin.TabularInline):
model = User.is_admin_for_organization.through
extra = 0
#admin.register(Organization)
class OrganizationAdmin(admin.ModelAdmin):
inlines = (UserOrgAdminInLine,)
However, looking up users is not convenient as soon as their number increases. I would like something similar to filer_horizontal but I am not sure how to include it directly in the OrganizationAdmin admin class. Furthermore, I am using fieldsets (which I believe should have no special rules or syntax to it compared to ordinary fields = .
One little subquestion - in the tabular inline, when I use only model = User django throws an error that there is no foreign key to it, but when I use the additional .is_admin_for_organization.through it works, but there is no through table and I though that this work just in that case. Why is that?
Any help would be much appreciated.
Try adding
class UserOrgAdminInLine
raw_id_fields = ("is_member_of_organization",)

On two related models, which one should contain the definition of the relationship?

First of all, yes: I've read Django's foreign key and many-to-many documentation, but I'm still not 100% clear on how to implement relationships on a practical level, especially regarding the hierarchy of the relationships.
One-to-one
I am aware of how to form one-to-one relationships. However, on a more conceptual level, which model should contain that reference to the other one? Let's say I have a Citizen, and a Passport. Now, it's obvious that one Citizen can only have a single Passport and viceversa, but, ideally, should the Citizen contain a field referencing to his Passport, or should the Passport model contain a reference to the Citizen it belongs to?
Many-to-many
For the sake of simplicity, let's say I have a Person model and a Trip model (Trip as in going out on a trip somewhere). Many Persons can participate in a single Trip. Or in other words: a Person can participate in many Trips and in any single Trip, a lot of Persons can participate. This looks like a many-to-many relationship, but, again, ideally, which model should contain the definition for the relationship, the Person with a trips field or the Trip with a participants field? And why? Does it even make any practical difference?
Thank you.
This depends on your business logic. As a rule of thumb I'd suggest to think about the admin app. How would you like to add new objects?
When adding new objects, how would you like to add related objects?
Let's say you have these models:
Citizen(models.Model):
name = models.CharField()
Passport(models.Model):
number = models.CharField()
citizen = models.OneToOneField('Citizen', related_name='passport')
When adding new passport object, you have the possibility to add new citizen, if it doesn't yet exist. Since this doesn't look very logical to me, I'd change the relation as:
Citizen(models.Model):
# other fields
passport = models.OneToOneField('Passport', related_name='citizen')
Now we can add a new citizen object in the admin and add the related passport object within the same page.
If you use the admin app, this should lead you to more ergonomical design.
EDIT: expand with many-to-many example
Better example for a m2m relation would be StackOverflow - there are questions and tags. A question has many tags, and a tag has many questions. Let's say the models look like this:
Question(models.Model):
title = models.CharField()
body = models.TextField()
author = models.CharField()
tags = models.ManyToManyField('Tag', related_name='questions')
Tag(models.Model):
name = models.CharField()
Why do we put the relation in Question? This should be very logical - when creating a new question you'd like to set the tags for it. When creating a new tag you don't care about any questions associated with it. You can create a tag and later when creating questions, associate them with the tag.
If a tag doesn't exist yet you can add it from the admin, when adding a new question.
I hope this second example is more palpable.
The theory behind this is called database normalization which is a ladder of best practices you should look up if you want to know more about how to structure your data.
The third form tells us that:
"[Every] non-key [attribute] must provide a fact about the key, the whole key, and nothing but the key."
So in the case of ForeignKey fields it should be on the Child model, because it doesn't tell us anything about the parent, but it does tells us what parent the child belongs to.
The mental model that you should have is Parent and Child. Every relationship has two models. So think of one as the Parent model or the Primary model and think of the other one as the Child model or the Secondary model.
NOTE: Always put your relationship field in the CHILD model.
Here is how I would solve your problems:
For the first one, I will have a mental model that Citizen is the Parent and Passport is the child.
class Citizen(models.Model):
name = models.CharField(max_length=255)
info = models.TextField()
class Passport(models.Model):
owner = models.OneToOneField(Citizen)
unique_no = models.CharField(max_length=30, unique=True)
For the second problem, do the same. I would choose Person as the parent model and Trip as the child model.
class Person(models.Model):
name = models.CharField(max_length=255)
info = models.TextField()
class Trip(models.Model):
person = models.ManyToManyField(Person)
info = models.TextField()
If you have sqlitebrowser, you can use that to open your database and check what tables were created according to your models. Then, you will have a clearer idea as to how Django sees your models.

How to link a Django model field to an instance of the same model

I'm trying to design a Django model for articles with attributes like title, publication date, etc. One of the attributes is other article(s) that the article in question is commenting on. I'm not sure how to code this since there is no foreign key involved - I just want a reference to other instances of the Article model (i.e. one or more other articles). This is what I have so far:
class Article(models.Model):
title = models.CharField(max_length=400)
publication_date = date_published = models.DateField()
comment_on = ?????????????
Any suggestions would be much appreciated. Thank you!
I think you should user ForeignKey
comment_on = models.ForeignKey('self',null=True,blank=True)
To create a recursive relationship -- an object that has a many-to-one
relationship with itself -- use models.ForeignKey('self').
Django foreign key docs
you can use ManyToManyField
comment_on = models.ManyToManyField('self',null=True,blank=True)
refer to DOCUMENTATION for further symmetric use.

Django Models and Admin interface question

I am preparing a Examination website for my students. Simple website, with use of Django's admin interface to create the Question paper.
I have following models:
class Paper(models.Model):
name = models.CharField(max_length=2000, unique=False)
short_desc = models.TextField(unique=False)
class Question(models.Model):
text = models.TextField(unique=False)
order = models.IntegerField(unique=True)
paper = models.ForeignKey(Paper, unique=False)
While adding questions to the paper, I want that I should be able to add the question from the Paper's admin interface itself, by clicking a "+" sign or some kind of "add more questions" etc.
In my current setup, I have to first create the paper and then go into Question interface and add them one by one (and heaven's forbid) if I lose their order number.
Remember, each Question belongs to a Paper and it is not a ManyToMany thing here.
Do I have to modify the admin in any way or am I doing it wrong?
Thanks.
The admin interface has the ability to
edit models on the same page as a
parent model. These are called
inlines. See InlineModelAdmin
Create a QuestionInline:
class QuestionInline(admin.TabularInline):
model = Question
and in PaperAdmin add:
class PaperAdmin(admin.ModelAdmin):
...
inlines = [
QuestionInline,
]
InlineModelAdmin is what you're after. See http://docs.djangoproject.com/en/dev/ref/contrib/admin/#inlinemodeladmin-objects for the details