The model has two many-to-many relations through the intermediate model - python

I have a model that has 2 separate ManyToManyField relations back to itself
class Company(models.Model):
parent = models.ManyToManyField("self", through='CompanyParent', through_fields=('company_child', 'company_parent'), related_name='+')
child = models.ManyToManyField("self", through='CompanyParent', through_fields=('company_parent', 'company_child'), related_name='+')
The above works fine on my localhost Django v3.0.2/ SQLite 3.8.7.2
To actually publish it, I have had to use Django v2.1.15/ SQLite 3.7.17, but with the published version it is chucking out the following errors
companies.Company.child: (fields.E332) Many-to-many fields with
intermediate tables must not be symmetrical.
companies.Company.parent: (fields.E332) Many-to-many fields with
intermediate tables must not be symmetrical.
companies.Company: (models.E003) The model has two many-to-many
relations through the intermediate model 'companies.CompanyParent'.
What's going on here? Solved the first 2 issues by adding symmetrical=False to each model, but no idea how to solve the final error?

You can check this answer to set up two many-to-many relations.
An example from the mentioned answer:
class Person(models.Model):
name = models.CharField(max_length=127, blank=False)
to_users = models.ManyToManyField(
'self',
symmetrical=False,
related_name='from_users',
through='Event',
through_fields=('from_user', 'to_user'),
)
class Event(models.Model):
item = models.ForeignKey(Item, related_name='events')
from_user = models.ForeignKey(Person, related_name='events_as_giver')
to_user = models.ForeignKey(Person, related_name='events_as_receiver')

In the event anyone happens across the same issue; the above is the answer but thought I would expand slightly after making the necessary changes to my own project
If you are looking to have numerous many-to-many within the same model and if you are on a version of Django after 2.2a1, then the best method is the one detailed in my question; two different models which you can easily call on views or templates; for example -
> data.manytomany1
> data.manytomany2
However, before 2.2a1 you will have issues. For me, this is because on cPanel, I have to use Django v2.1.15 due to the older SQLite 3.7.17 utilised. This means that you can only have one ManyToManyField (see above) and use a filter to get your 2nd manytomany > you will only be able to do this in the views.py
Hope that makes sense

Related

filter django queryset by onetoone model field property

i have two model classes and they are related by OneToOneField like here
class Book(models.Model):
is_user_ok = models.BooleanFiled()
class Mybook(models.Model):
book = models.OneToOneField( Book, related_name="Book", null=True, blank=True, on_delete=models.SET_NULL)
now i want make a queryset filter by book field property. but here book.is_user_ok
cannot be used. how can i make this queryset filter?
queryset = Mybook.objects.filter(book.is_user_ok=True)
You are looking a common problem, what you really want to do is related_name__column_name in filter, in your case you can try
queryset = Mybook.objects.filter(book__is_user_ok=True=True)
Reference from official docs:
https://docs.djangoproject.com/en/4.0/topics/db/queries/
double underscore is used for joins as you have already set the relationship in model variety of joins work here, it is used as per the model relation.
You are using a wrong syntax. Replace (book.is_user_ok=True) with (book__is_user_ok=True) The problem is, using '.' instead of '__'. Thats the correct syntax when dealing with another model class

Django many to many relation, include all IDs in queryset in both directions

I have 2 models connected via M2M relation
class Paper(models.Model):
title = models.CharField(max_length=70)
authors = models.ManyToManyField(B, related_name='papers')
class Author():
name = models.CharField(max_length=70)
Is there a way to include authors as all related authors' IDs (and maybe name somehow)?
Is there a way to include papers IDs as reverse relation (and maybe title as well)?
Author.objects.all().annotate(related_papers=F('papers'))
this only adds id of one paper, first one it finds I think.
Furthermore, changing related_papers to papers gives an error:
ValueError: The annotation ‘papers’ conflicts with a field on the
model.
From what I understand in your comments, you're using DRF. I will give you 2 answers.
1) If you're talking about model serializer, you can use PrimaryKeyRelatedField :
class AuthorSerializer(serializers.ModelSerializer):
papers=serializers.PrimaryKeyRelatedField(many=True, read_only=True)
class Meta:
model = Author
fields = ['name', 'papers']
class PaperSerializer(serializers.ModelSerializer):
class Meta:
model = Paper
fields = '__all__'
This will return the IDs for the other side of the relationship whether you're on Paper or Author side. That will return the primary keys, not a representation of the object itself.
2) Now you're also talking about performance (e.g. database hit at each iteration).
Django (not DRF-specific) has a queryset method to handle preloading related objects. It's called prefetch_related.
For example, if you know you're going to need the relation object attributes and want to avoid re-querying the database, do as follow:
Author.objects.all().prefetch_related('papers')
# papers will be already loaded, thus won't need another database hit if you iterate over them.
Actually, it has already been implemented for you. You should include a Many-to-Many relationship to author in your Paper model like this:
class Paper(models.Model):
title = models.CharField(max_length=70)
authors = models.ManyToManyField(Author, related_name='papers')
That gives you the opportunity to add Author objects to a related set using
p.authors.add(u), assuming that p is the object of Paper model, and a is an object of Author model.
You can access all related authors of a Paper instance using p.authors.all().
You can access all related papers of an Author instance using u.papers.all().
This will return an instance of QuerySet that you can operate on.
See this documentation page to learn more.

Django GenericForeignKey using related_name

I'm trying to refactor my schema so that a field that is currently a simple ForeignKey becomes a GenericForeignKey. So, in my model, this:
ref_track = models.ForeignKey(Track, unique=False, related_name='posts_by_ref')
...becomes this:
ref_content_type = models.ForeignKey(ContentType)
ref_id = models.PositiveIntegerField()
ref_object = generic.GenericForeignKey('ref_content_type', 'ref_id')
Previously I was using posts_by_ref in a number of database queries, for example checking the submission status of the posts attached to a track (the post object is where the above fields are). However, I understand that related_name is not supported when using a GenericForeignKey, so is there another way to replicate this behaviour?
You could have a look at Reverse generic relations

Django Model Mixins - Fields Ordering

I'm currently experimenting with model mixins, the idea being to build a small library of small abstract mixin classes defining commonly needed fields.
Here's what i'm currently playing with:
class HtmlAttrsMixin(models.Model):
css_classes = models.CharField(
max_length=256,
verbose_name=_('CSS Classes'),
blank=True,
)
class Meta:
abstract = True
class LinkHtmlAttrsMixin(HtmlAttrsMixin):
target_blank = models.BooleanField(
default=False,
verbose_name=_('Open in a new window /tab'),
)
title = models.CharField(
max_length=512,
verbose_name=_('Title'),
blank=True,
)
class Meta:
abstract = True
class URLMixin(models.Model):
label = models.CharField(
max_length=256,
verbose_name=_('Name'),
blank=True,
)
url = models.CharField(
max_length=4000,
verbose_name=_('URL'),
blank=True,
)
class Meta:
abstract = True
# Concrete model implementing the above mixins:
class TagLine(URLMixin, LinkHtmlAttrsMixin):
enabled = models.BooleanField(_("enabled"), default=True)
def __unicode__(self):
return self.label
This is working fine so far, but there's a little something i don't quite understand.
I'd like to be able to kind of decide of the inherited fields' ordering by simply declaring the mixins in a different order. As far as i know, the default field ordering is based on the order in which those were declared on the model class, and python will resolve attribute names by going through the base classes in the order in which they were listed, so in the above example, i'd expect the css_classes, target_blank & title fields to be listed AFTER label & url in the admin site, and vice versa if i invert the order of the two mixins in the declaration.
But no matter how i list the mixins, the "html_attrs" fields keep appearing first. They are grouped together (which seems logical, since they belong to the same class), but i just can't seem to force the ordering in that way.
I know this is a trivial question - I can just fix that with an admin fieldset, which will prove much more flexible anyway. It just seemed like a convenient trick which i expected to work, so i'm simply interested in understanding why it doesn't.
(Also, if anyone has any advice about model mixins in general, i'm all ears - I've found some info, but not much, and google for django models mixins tends to return lots of results about CBV mixins, which is not what i'm interested in at the moment).
Thanks to anyone who'll care to answer!
This doesn't answer your question, but I do think the approach is really nice.
Reordering fields in Django model
For forms:
How does Django Know the Order to Render Form Fields?
Instead of using a fields attribute in your form to be edited every time you add a new field to your Model class, make a logic to add the exception where you want it.
Another approach: you can use from django.forms import fields_for_model, and create a function to populate your fields attribute using this function. Check the documentation for this method, is really nice!

django model help involving m2m and foreignkey

Ok so this may be really easy for someone else to solve but i'm really confused on how to go about solving this.
So to start, i have a model A that has multiple fields that have many-to-many relationships to specific tables. So for example
class A(models.Model):
field1 = models.ManyToMany('field1Collection')
field2 = models.ManyToMany(field2Collection')
class field1Collection(models.Model):
description = models.TextField()
class field2Collection(models.Model):
description = models.TextFIeld()
Anyway this is what i'm trying to accomplish. I need to write another model that can hold a ranking system. So for example, i want to create a record where i can define
I have x number of ranks (3 for example):
field1Collection Object 3
field2Collection Object 6
field1Collection Object 2
So i basically want to be able to select objects from my field1Collection and field2Collection tables and assign them ranks. I tried thinking up schemes using foreignkeys and m2m fields but they all go wrong because the model needs to know "ahead" of time which collection set i need to reference. Does this many sense? can anyone help?
You can solve this using GenericForeignKey relationship
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
class RankItem(models.Model):
rank = models.IntegerField()
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
def __unicode__(self):
return self.rank
A normal ForeignKey can only "point to" one other model, which means that if the RankItem model used a ForeignKey it would have to choose one and only one model to store tags for. The contenttypes application provides a special field type which works around this and allows the relationship to be with any model
You need that field1Collection and filed2Collection have a common ancestor class which you can refer with a foreignKey. See django documentation on inheritance.

Categories

Resources