I am working on a site, and I have both Followers and Following as two ReferenceFields attached to a User. Is this overkill? I felt like it might make the querying a little easier, but is this just asking for trouble in the long run?
Something like:
class User(Document):
name = StringField()
followers = ListField(ReferenceField('User'))
following = ListField(ReferenceField('User'))
I wasn't sure what best practice would be for this kind of relationship and if it's easier to just set one as a ReferenceField and filter when I query the database. This would prevent instances where the follower and following list did not match, but it also seemed like it would make database queries more complicated.
I see this article on the mongodb website, which is helpful but I don't feel it directly answers my question https://docs.mongodb.com/ecosystem/use-cases/storing-comments/.
Related
I have following models:
class Topic(models.Model):
...
class Article(models.Model):
...
class ArticleInTopic(models.Model):
topic = models.ForeignKey(Topic, on_delete=models.PROTECT)
article = models.ForeignKey(Article, on_delete=models.PROTECT)
depends_on = models.ForeignKey(ArticleInTopic, on_delete=models.PROTECT)
class Meta:
unique_together = ('topic', 'article', 'depends_on')
With this models set I'm trying to express the following situation: there are some studying topics, each consists of multiple articles. However, in order to learn a topic one should read the articles related to the topic but not in any order, rather in order defined by article dependencies. This means that in context of a topic an article may have another article which is required to be read before reading this article. It is guaranteed that the article on which the current article depends on comes from the same topic.
So, basically, this whole structure looks like an acyclic (it is guaranteed) graph with parent-child nodes relation. In the business logic of my app I'm going to sort the graph topologically so I can tell the user which Article to read 1st, 2nd, etc.
However, the problem is the way Django fetches ForeignKey's data from the database. AFAIK it uses N+1 request to fetch all foreign keys. There is a solution to it - using select_related but this only works when you can specify exact fields which need to be queried in the same request as the main info. In my case this is not possible, because I do not know in advance how many children each node has, so I cannot list them all in select_related.
Instead I was thinking about fetching all ArticleInTopic objects which have the same topic foreign key (topic name comes from user, so I know it by the time I need to show him Articles) and then topologically sort them in memory. But I am not sure whether Django will understand that it has fetched all the required object already when I will access one of objects depends_on field.
For example, I fetch 2 ArticleInTopic objects for topic 'Cars', lets say those objects are A and B. B depends on A. Django has queried them already and they are in memory. Now, what happens if I do B.depends_on? Will Django make another request to the DB in order to select B? Or is it smart enough to understand that B has already been fetched by the previous request? If it is not, is there any way to prevent extra DB queries?
I need to get all Comments for all Projects that includes a specific User. Meaning, all comments for all projects that a user is member of.
A user can belong to many Projects, and each Project has many Comments.
How should this be done right? So far I have solved it in my template by creating a nested for-loop, but that's not good since I need to sort the result.
I'm thinking something like:
projects = user.projects
comments = Comment
for p in projects:
for c in p.comments:
comments.append(c)
return comments
...does not seem to work.
Any clues?
I think this will do it:
query = Comment.objects.filter(project__user=person)
If the Comment model has a foreign key to project which has a foreign key to user. This will involve a SQL join statement in the database. It's better to do this on the the database because it's far more efficient. Databases are designed exactly to do this.
The problem: I wish to use Postgres Schemas to separate the tables of different parts of my django app at database level.
Aside
You can skip this section, but I think it's helpful to add context to these things. My app is working on a database of existing data (stored in the public schema, helpfully), which it's very important I don't modify. As such, I want to separate "my" data into a separate schema (to which django will be given read/write/play in the sand access), while restricting access to the public schema to read-only. I originally tried to solve this by separating my data out into a separate database and using database routing, but it turns out (if I'd only read the documentation) that django doesn't support cross database dependencies (which is fair enough I suppose), and my models have foreign keys into the read-only data.
The meat
There exists a workaround for Django's lack of schema support (which you can read about here) which is to specify the db_table attribute in your model's meta, like so:
class MyModel(models.Model):
attribute1 = models.CharField()
#Fool django into using the schema
class Meta:
db_table = 'schema_name\".\"table_name'
This is great, but I didn't really want to have to write this for every single model in my app - for a start, it doesn't seem pythonic, and also there's every chance of me forgetting when I have to add a new model.
My solution was the following snippet:
def SchemaBasedModel(cls):
class Meta:
db_table = '%s\".\"%s' % (schema_name, cls.__name__)
cls.Meta = Meta
return cls
#SchemaBasedModel
class MyModel(models.Model):
attribute1 = models.CharField()
...
When I then run python manage.py shell I get the following:
>>> from myapp import models
>>> myModel = models.MyModel
>>> myModel.Meta.db_table
'myschema"."mymodel'
>>>
"Looks good to me," I thought. I then ran: python manage.py sqlall myapp. Sadly, this yielded the original table names - that is, the table names as they were before I applied this meta info. When I went back and applied the meta info "by hand" (i.e. by adding Meta inner classes to all my models), things were as expected (new table names).
I was hoping somebody could enlighten me as to what was going on here? Or, more usefully, what's the "right" way to do this? I thought the decorator pattern I've talked about here would be just the ticket for this problem, but apparently it's a non-starter. How can I quickly and easily apply this meta info to all my models, without typing it out every single time?
Edit: Perhaps I was a little unclear when I asked this - I'm as interested in know what's "actually going on" (i.e. why things aren't working the way I thought they would - what did I misunderstand here?) as how to solve my problem (clear separation of "my" data from legacy data, preferably on a schema level - but it's not the end of the world if I have to dump everything into the public schema and manage permissions on a per-table basis).
Second Edit: The accepted answer doesn't necessarily tell me what I really want to know, but it is probably the right solution for the actual problem. Short answer: don't do this.
I didn't really want to have to write this for every single model in my app -
for a start, it doesn't seem pythonic,
That's false. Some things have to be written down explicitly. "Explicit is better than Implicit".
and also there's every chance of me forgetting when I have to add a new model
That's false, also.
You won't "forget".
Bottom Line: Don't mess with this kind of thing. Simply include the 2 lines of code explicitly where necessary.
You don't have that many tables.
You won't forget.
Also, be sure to use DB permissions. Grant SELECT permission only on your "legacy" tables (the tables you don't want to write to). Then you can't write to them.
I'm still not sure this is the correct way to go about this, maybe not, but I'll ask anyway. I'd like to re-write wordpress (justification: because I can) albeit more simply myself in Django and I'm looking to be able to configure elements in different ways on the page. So for example I might have:
Blog models
A site update message model
A latest comments model.
Now, for each page on the site I want the user to be able to choose the order of and any items that go on it. In my thought process, this would work something like:
class Page(models.Model)
Slug = models.CharField(max_length=100)
class PageItem(models.Model)
Page = models.ForeignKey(Page)
ItemType = models.CharField(max_length=100) # tells me which model to display
InstanceNum = models.IntegerField() # tells me which instance of which model...
Then, ideally, my template would loop through all the PageItems in a page which is easy enough to do.
But what if my page item is a site update as opposed to a blog post? Basically, I am thinking I'd like to pull different item types back in different orders and display them using the appropriate templates. Now, I thought one way to do this would be to, in views.py, to loop through all of the objects and call the appropriate view function, return a bit of html as a string and then pipe that into the resultant template.
My question is - is this the best way to go about doing things? If so, how do I do it? If not, which way should I be going? I'm pretty new to Django so I'm still learning what it can and can't do, so please bear with me. I've checked SO for dupes and don't think this has been asked before...
I've also looked at Django-cms to see if that helps, but I couldn't get to grips with it.
Any suggestions?
First, some puzzelement.
InstanceNum = models.IntegerField() # all models have primary keys.
In Django, all model are assigned an integer primary key.
The comment doesn't make sense, since you don't need to add a primary key like this. The PageItem already has a primary key.
Also, please use lower case letters for attributes. Only Use Upper Case for Class Names. Please.
"But what if my page item is a site update as opposed to a blog post? Basically, I am thinking I'd like to
pull different item types back in
different orders and display them
using the appropriate templates"
Different types usually means different models. Rather than a vague "PageItem", you probably want to have "Site Update" and "Blog Post" as separate models.
You can then iterate through these various objects and display them in the template.
You can easily have your various Models defined with a method to return HTML information. You don't (generally) want to return fully-baked HTML. But CSS ID or Class information is sometimes helpful.
class SiteUpdate( models.Model ):
page = models.ForeignKey(Page)
item_text = models.CharField(max_length=100)
item_css_class = models.CharField(max_length=64)
Now you can generate this into the template with a simple <div class="{{item.item_css_class}}">{{item.item_text}}</div> and use CSS to handle the formatting details that distinguish site update as opposed to a blog post.
The include template tag can take a variable containing the template to include, so you could loop through a sequence containing the various sub-templates and include them in turn, maybe using a dict to map friendly names to template filenames.
I have the concept of a team in my django app.
class Team(models.Model):
name = models.CharField(max_length=200)
#snip
team_members = models.ManyToManyField(User)
I would like to fetch all teams the currently logged in user is member of. Something along the lines of
Team.objects.all().filter(request.user.id__in = team_members.all())
This obvious doesn't work. Does anyone have some suggestions on how to do such query without going directly to sql? I did look at the django documentation of "in" queries, but I couldn't find my use case there.
Many thanks!
Nick.
You don't need in here, Django handles that automatically in a ManyToMany lookup.
Also, you need to understand that the database fields must always be on the left of the lookup, as they are actually handled as parameters to a function.
What you actually want is very simple:
Team.objects.filter(team_members=request.user)
or
request.user.team_set.all()