django circular import solutions - python

Please help me. There is a Django project with circular import. Project's applications are connected only one side. But there are functions that use other models without params (for using in template) and that makes it impossible to move the function.
I have found two solutions:
First way is to import model inside function.
And another way it to move two models into one file.
Both solutions work without problem, but which one is better?
class InitialArticle(models.Model):
by = models.ForeignKey(get_user_model(), null=True, on_delete = models.SET_NULL)
category = models.ForeignKey(ArticleCategory, null=True, on_delete=models.CASCADE)
keywords = models.CharField(max_length = 110, unique = True)
def get_articles_of_initialarticle(self):
from article.models import Article
return Article.objects.filter(initial = self)
Please help me find a better way. Maybe there is another solution?

You can add related_name in Article.initial like so:
class Article(...):
initial = models.ForeignKey(to='InitialArticle', related_name='articles')
After that you can use it like so:
initial_article = InitialArticle.objects.filter(...).first()
initial_article.articles.all() # return all articles which have foreign key to this article
Also in models.ForeignKey you can use string instead of importing the model like I have written
Or you can do it without adding related_name.
Default related name will be like so: article_set
And if you do not set related_name you can write like so:
initial_article = InitialArticle.objects.filter(...).first()
initial_article.article_set.all() # return all articles which have foreign key to this article

Related

Limit prefetch_related to 1 by a certain criteria

So I have models like these
class Status(models.Mode):
name = models.CharField(max_length=255, choices=StatusName.choices, unique=True)
class Case(models.Model):
# has some fields
class CaseStatus(models.Model):
case = models.ForeignKey("cases.Case", on_delete=models.CASCADE, related_name="case_statuses")
status = models.ForeignKey("cases.Status", on_delete=models.CASCADE, related_name="case_statuses")
created = models.DateTimeField(auto_now_add=True)
I need to filter the cases on the basis of the status of their case-status but the catch is only the latest case-status should be taken into account.
To get Case objects based on all the case-statuses, this query works:
Case.objects.filter(case_statuses__status=status_name)
But I need to get the Case objects such that only their latest case_status object (descending created) is taken into account. Something like this is what I am looking for:
Case.objects.filter(case_statuses__order_by_created_first__status=status_name)
I have tried Prefetch as well but doesnt seem to work with my use-case
sub_query = CaseStatus.objects.filter(
id=CaseStatus.objects.select_related('case').order_by('-created').first().id)
Case.objects.prefetch_related(Prefetch('case_statuses', queryset=sub_query)).filter(
case_statuses__status=status_name)
This would be easy to solve in raw postgres by using limit 1. But not sure how can I make this work in Django ORM.
You can annotate your cases with their last status, and then filter on that status to be what you want.
from django.db.models import OuterRef
status_qs = CaseStatus.objects.filter(case=OuterRef('pk')).order_by('-created').values('status__name')[:1]
Case.objects.annotate(last_status=status_qs).filter(last_status=status_name)

Embedding Vs Linking in MongoDB.when to embed and when to link?

I read this page but didn't get when to use embedding feature and when to use linking.I have a project in django for which I am using MongoDB.In my models.py file I have following models:
class Projects(models.Model):
projectName =models.CharField(max_length = 100,unique=True,db_index=True)
projectManager = EmbeddedModelField('Users')
class Teams(models.Model):
teamType = models.CharField(max_length =100)
teamLeader = EmbeddedModelField('Users')
teamProject = EmbeddedModelField('Projects')
objects = MongoDBManager()
class Users(models.Model):
name = models.CharField(max_length = 100,unique=True)
designation = models.CharField(max_length =100 )
teams = ListField(EmbeddedModelField('Teams'))
class Tasks(models.Model):
title = models.CharField(max_length = 150)
description = models.CharField(max_length=1000)
priority = models.CharField(max_length=20)
Status = models.CharField(max_length=20)
assigned_to = EmbeddedModelField('Users')
assigned_by = EmbeddedModelField('Users')
child_tasks = ListField()
parent_task = models.CharField(max_length = 150)
My question is if we do embedding do we have to update the object in all models.Like if I want to update the name of a 'user' ,I would have to run update for models:Projects, Teams, Users and Tasks or linking would be better in my case?
In your example, yes, changing the name of a user implies that if you use embedding then you must update all other documents with an extra step. What is more appropriate in your situation is linking (referencing). This involves an extra step at query time, but because of your particular "business logic", it is better.
Generally, if a given document needs to be accessed from a number of different places then it makes sense to make it a reference rather than embedded. The same applies in situations when a document changes frequently.
First, conceptually, name your model classes as singular objects.
Users should be User, Teams should be Team...
Think of the model as the mold from which multiple objects will be made. User model will product Users and be stored in a table called Users where each document/row is a User object.
Now, regarding your question, hymloth is exactly right. The way to make it a reference to a document instead of an embedded one is to change those particular fields to reference the id of a user in the user's collection. That way you are just storing an id to lookup instead of a copy of the user document. When you change the reference document, it will be changed in all of the places it is referenced as well. (Typical relational association)
I didn't see a field for that in Django-mongoDB either but maybe you can use the traditional django ForeignKey field for this purpose. I don't know if you can mix and match so give it a shot.
for example, your Teams class would have a field like this:
teamLeader = ForeignKey(User)
Let me know if that works.

Generalized Model in Django

My first question helped me a LOT, so I figured I'd go ahead and ask a second one.
My current (practice) project is to create a generalized model. Here's what I've written so far:
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Block(models.Model):
title = models.CharField(man_length=50)
#Make sure child classes have content defined!
#content = models.BooleanField(default=False)
owner = models.ForeignKey('User')
access = models.ManytoManyField('User', null=True)
links = models.ManytoManyField('self', null=True)
class Meta:
abstract = True
def __unicode__(self):
return self.title
class Text(Block)
content = models.TextField(max_length=100)
class URL(Block)
content = models.URLField()
class Email(Block)
content = models.EmailField()
Please note I haven't actually tested this yet - I don't think my logic on this so far is going to work.
A few goals:
1) owner there points to the creator of the block. I think that should work.
2) access should point to Users (other than the owner) who can edit the block. I think this should work too. (with proper views of course)
3) links should allow linking between blocks - so I can retrieve a block and any related blocks (and so on up if need be)
4) content should of course be the content of the block(I have the three sample simple data types here), which ideally can be any number of things (implemented here via the abstract base class).
5) For the classes Email, URL, and Text, I'd like to be able to write a (generalized) view which from one url input, returns an appropriate block of any of the three types. I think this may require an autoincrementing field which guarantees a unique value between the three models. Honestly, I'm not sure how to do this at all.
6) Of course ideally this should be readily extensible if at all possible.
I'm of course very unsure if this is the best way to go about achieving what I'm trying to do. Any suggestions, help, tips, tricks, or bad jokes accepted!
Thank you very much for your help!
EDIT: relating to number 5, I have a rough view (with a syntax error) that I think might do the trick:
def getblock(request, block, no):
data = get_object_or_404(%s,%s) % (block,no)
return render_to_response('single.html',{'data':data})
Thoughts?
Your code seems correct to me. I also worked on a generic class for my project and it was similar to this one. One remark, when you get a block, you should do some type checking to retrieve the class data so, I recommend you to add a field to store its type. e.g:
class Block(models.Model):
title = models.CharField(max_length=50)
type = models.IntegerField()# 1 for text, 2 for email and 3 for url
#Make sure child classes have content defined!
#content = models.BooleanField(default=False)
owner = models.ForeignKey('User')
access = models.ManytoManyField('User', null=True)
links = models.ManytoManyField('self', null=True)
Then in your view:
def getblock(request, block, no):
if block.type == 1:
data = get_object_or_404(Block,id=no).text
elif block.type == 2:
data = get_object_or_404(Block,id=no).email
elif block.type == 3:
data = get_object_or_404(Block,id=no).url
return render_to_response('single.html',{'data':data})
You can access the subclasses with lower case representation of that child class. I think that will work nicely. Also I don't get the dictionary type arguments you wrote and that gave a syntax error when I executed. Anyway, I also corrected some of the syntax errors, too.

How to specify data in models.ManyToManyField(Foo,Bar)

I'm working on an application were I want the user roles to be entered into a table in the database.
class Role(models.Model):
name = models.CharField(max_length = 40)
details = models.TextField()
class Foo(models.Model):
name = models.CharField(max_length = 40)
details = models.TextField()
class Bar(models.Model):
name = models.CharField(max_length = 40)
detauls = models.TextField()
foos = models.ManyToMany(Foo,related_name="foo_binding_and_roles")
I want the schema of the table foo_binding_and_roles to resemble:
{|id|Foo_id|Bar_id|Role_id|}
I'm still scratching my head on this, wondering if it's even possible. I know if I write a custom manager I could pull it off but I want to avoid that.
The idea behind this scheme, is to assign users permissions on a relational basis when bar meets foo and foo meets bar.
I don't understand what exactly you are trying to do, but reading this line: {|id|Foo_id|Bar_id|Role_id|}
makes me think you could either define a model with those fields, or set up a through model with that extra field.
To simplify this so you can think of it more clearly, don't use many-to-many associations, and build your entire scheme using many-to-one associations. If I understood you right, I think what you're looking for is possible using a three-way association class.

Django filter many-to-many with contains

I am trying to filter a bunch of objects through a many-to-many relation. Because the trigger_roles field may contain multiple entries I tried the contains filter. But as that is designed to be used with strings I'm pretty much helpless how i should filter this relation (you can ignore the values_list() atm.).
This function is attached to the user profile:
def getVisiblePackages(self):
visiblePackages = {}
for product in self.products.all():
moduleDict = {}
for module in product.module_set.all():
pkgList = []
involvedStatus = module.workflow_set.filter(trigger_roles__contains=self.role.id,allowed=True).values_list('current_state', flat=True)
My workflow model looks like this (simplified):
class Workflow(models.Model):
module = models.ForeignKey(Module)
current_state = models.ForeignKey(Status)
next_state = models.ForeignKey(Status)
allowed = models.BooleanField(default=False)
involved_roles = models.ManyToManyField(Role, blank=True, null=True)
trigger_roles = models.ManyToManyField(Role, blank=True, null=True)
Though the solution might be quiet simple, my brain won't tell me.
Thanks for your help.
Have you tried something like this:
module.workflow_set.filter(trigger_roles__in=[self.role], allowed=True)
or just if self.role.id is not a list of pks:
module.workflow_set.filter(trigger_roles__id__exact=self.role.id, allowed=True)
The simplest approach to achieve this would be checking for equalty over the whole instance (instead of the id) in the ManyToManyField. That looks if the instance is inside the many to many relationship. Example:
module.workflow_set.filter(trigger_roles=self.role, allowed=True)
I know this is an old question, but it looks like the OP never quite got the answer he was looking for. If you have two sets of ManyToManyFields you want to compare, the trick is to use the __in operator, not contains. So for example if you have an "Event" model with a ManyToMany to "Group" on field eventgroups, and your User model (obviously) attaches to Group, you can query like this:
Event.objects.filter(eventgroups__in=u.groups.all())
singularity is almost right with the first example. You just need to make sure it's a list. The second example, checking the trigger_roles__id__exact is a better solution though.
module.workflow_set.filter(trigger_roles__in=[self.role.id],allowed=True)

Categories

Resources