Django extract queryset from ManyToMany with through field - python

Say we have those models:
class A(models.Model):
field = models.ManyToManyField(B, through="C")
class B(models.Model):
value = models.CharField()
class C(models.Model):
a = models.ForeignKey(A)
b = models.ForeignKey(B)
order = models.IntegerField()
Is there an option to extract queryset of B's, but taking into consideration order field?
Doing a a.c_set.all() returns queryset for C class (but it's ordered).
Doing a a.fields.all() works, but the queryset is unordered.
I need a queryset for initializing the formset.
I hope it's understandable - it's quite late and i can't think clearly already... I'll try to clear it out if anyone has any questions.
Thanks in advance

If you put a an ordering on model C, all queryset on C would obey that order:
class C(models.Model):
class Meta:
ordering = ('order', )
Now if you want B objects related to A, you could sort the Bs based on C's ordering:
b_results = a.fields.order_by('c')
Or if the order_by('c') is not clear enough, you could change your model to be:
class C(models.Model):
a = models.ForeignKey(A, related_name='a_relationship')
b = models.ForeignKey(B)
order = models.IntegerField()
class Meta:
ordering = ('order', )
Then you could do:
b_results = a.fields.order_by('a_relationship')

Use the C model reverse relations to do the order, e.g.
a.fields.order_by(c__order)

Related

Django model filter elements

I have four models as follows:
class modelA(models.Model):
name = models.CharField(...)
class modelB(models.Model):
date = models.DateTimeField(...)
A = models.ForeignKey(modelA, ...)
class modelC(models.Model):
email = models.CharField(...)
B = models.ForeignKey(modelB, ...)
class modelD(models.Model):
uid = models.CharField(...)
C = models.ForeignKey(modelC)
Given modelA element id, I have to filter modelD elements based on that id. But I am not sure about how to do that.
I appreciate any ideas!
modalD.objects.filter(C__B__A__name ='name')
when you use double underscore you filter the related Inheritance modal

How can I display all fields from a Many-to-Many Model in Django Admin

I have the following Models:
class ModelA(models.Model):
some_field_A = models.CharField()
some_other_field_A = models.CharField()
class ModelB(models.Model):
some_field_B = models.CharField()
many_to_many_relation = models.ManyToManyField(ModelA)
In admin.py I am using filter_horizontal to edit the ManyToManyField:
class ModelB(admin.ModelAdmin):
model = ModelB
filter_horizontal = ('many_to_many_relation',)
but it shows only some_field_A and I want it to show both fields from ModelA, because the entries in ModelA are unique depending on both fields and as you can see from the picture there are multiple entries with the same value (i.e. some_field_A = EUV) but they have different values for some_other_field_A:
It displays the result of the __str__(…) method you defined in your ModelA, so if you return the value of some_field in the __str__(…) method, then it will return only the data of some_field.
You thus can alter this method and return both fields:
class ModelA(models.Model):
some_field_A = models.CharField()
some_other_field_A = models.CharField()
def __str__(self):
return f'{self.some_field_A} {self.some_other_field_A}'
I'm not sure if this exactly the solution you are looking for but you could override the __str__ method of ModelA to return the information in a single line.
So for example:
class ModelA(models.Model):
first_field = models.CharField(max_length=16)
second_field = models.CharField(max_length=16)
def __str__(self):
return f"{self.first_field} ({self.second_field'})"
Your admin view should then show each object as "foo (bar)"

Differences in using a "through" table without or with a related name for many-to-many relationship

When it comes to Many-To-Many fields in Django, what is the difference between using a "through" table like the following...
class A(models.Model):
things = models.ManyToManyField("B", through=ThroughModel)
...
class B(models.Model):
text = models.TextField()
...
class ThroughModel(models.Model):
a = models.ForeignKey(A)
b = models.ForeignKey(B)
compared to just specifying a related name in the intermediary table like so?
class A(models.Model):
...
class B(models.Model):
text = models.TextField()
...
class ThroughModel(models.Model):
a = models.ForeignKey(A, related_name="things")
b = models.ForeignKey(B)
Either way you should be able to reference the relationship like
a_instance.things
right? Is there some behind the scenes difference between how this is implemented in the database?
The difference lies in how you reference a_instance from b_instance:
b_instance.a_set
in the first case and
b_instance.things
in the second case

Django model unique together both ways

Many questions already on this topic, but not what i'm searching for.
I have this Model:
class Options(TimeStampedModel)
option_1 = models.CharField(max_length=64)
option_2 = models.CharField(max_length=64)
class Meta:
unique_together = ('option_1', 'option_2')
Now I have a unique constraint on the fields.
Is there a way to also define this the other way around so that it doesn't matter what was option_1 and what was option_2
As example:
Options.create('spam', 'eggs') # Allowed
Options.create('spam', 'eggs') # Not allowed
Options.create('eggs', 'spam') # Is allowed but should not be
Thanks in advance!
I think a ManyToMany relation with a custom through table and an unique_together constraint on that table should do what you want.
Example code:
from django.db.models import Model, ForeignKey, ManyToManyField, CharField
class Option(Model):
name = CharField()
class Thing(TimeStampedModel):
options = ManyToManyField("Option", through="ThingOption")
class ThingOption(Model):
thing = ForeignKey(Thing)
option = ForeignKey(Option)
value = CharField()
class Meta:
unique_together = ('thing', 'option')
For Django 2.2+ it is recommended to use UniqueConstraint. In the docs there is a note stating unique_together may be deprecated in the future. See this post for its usage.
You can override create method, do something like
from django.db import models
class MyModelManager(models.Manager):
def create(self, *obj_data):
# Do some extra stuff here on the submitted data before saving...
# Ex- If obj_data[0]=="eggs" and obj_data[1]=="spam" is True don't allow it for your blah reason
# Call the super method which does the actual creation
return super().create(*obj_data) # Python 3 syntax!!
class MyModel(models.model):
option_1 = models.CharField(max_length=64)
option_2 = models.CharField(max_length=64)
objects = MyModelManager()

How do you get a field related by OneToOneField and ManyToManyField in Django?

How do you get a field related by OneToOneField and ManyToManyField in Django?
For example,
class A(models.Model):
myfield = models.CharField()
as = models.ManyToManyField('self')
class B(models.Model):
a = models.OneToOneField(A)
If I want to get a 'myfield' and all associated 'as' using class B, given a 'myfield' equal to a string like 'example', how is it done?
Models.py
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
def __str__(self): # __unicode__ on Python 2
return "%s the place" % self.name
class Restaurant(models.Model):
place = models.OneToOneField(
Place,
on_delete=models.CASCADE,
primary_key=True,
)
serves_hot_dogs = models.BooleanField(default=False)
serves_pizza = models.BooleanField(default=False)
def __str__(self): # __unicode__ on Python 2
return "%s the restaurant" % self.place.name
Let create a place instance.
p1 = Place.objects.create(name='Demon Dogs', address='944 W. Fullerton')
Then create a restaurant object.
r = Restaurant.objects.create(place=p1, serves_hot_dogs=True, serves_pizza=False)
Now, to access place from Restaurant:
>>> r.place
<Place: Demon Dogs the place>
vice-versa to access Restaurant from place
>>> p1.restaurant
<Restaurant: Demon Dogs the restaurant>
I did not understand the many-to-many field part can you please elaborate?
First you get an instance of B say b and you can easily access myfield and as through the a attribute of b
b.a.myfield
b.a.as.all()
Furthermore, CharField requires a max_length attribute as follows:
class A(models.Model):
myfield = models.CharField(max_length=128)
as = models.ManyToManyField('self')
class B(models.Model):
a = models.OneToOneField(A)
A general point, give more descriptive names to your models and their attributes, or at the very least, add comments explaining what these models represent

Categories