Django query using through model - django

a = models.ManyToManyField('self', through = 'x')
How to make a query on a by filtering through 'x'

You need to define symmetrical=False when creating the field. In Django 1.7 if you try your definition you will get an error similar to this:
CommandError: System check identified some issues:
ERRORS:
myapp.MyModel.a: (fields.E332) Many-to-many fields with intermediate tables must not be symmetrical.
so change the field to
a = models.ManyToManyField('self', through = 'x', symmetrical = False)
Now it all depends on your x class. It have to define two foreignKey fields back to yourModel:
class x(models.Model):
from_a = models.ForeignKey(myClass, related_name = 'from_a')
to_a = models.ForeignKey(myClass, related_name = 'to_a')
comment = models.CharField(max_length = 255)
Now you don't filter from x but from the reversed relations created by the FK's, i.e. something like this:
myClass.objects.filter(from_a__comment='something')
or from an instance perspective:
my_instance.a.filter(from_a__comments='something')
A great article about the topic can be found here: Self-referencing many-to-many through

Related

Django orm: order post queryset by greatest number of tags from search

I want to order posts by the greatest number of tags a post has
my models:
class post(models.Model):
description = models.Charfield(max_length = 2000)
class tag(models.Model):
t = models.Charfield(max_length = 100)
class tags(models.Model):
tag = models.ForeignKey(tag, ...)
post = models.ForeignKey(post,...)
I know django's orm supports many to many fields I have other reasons for doing it this way.
When inputs a search, example: purple mountain flowers
I want to query for posts that have any of the tags and order the query by the posts with the most matching tags. I'm new to using aggregation in django and have no idea how to structure this. Any recommendations?
here's what I've tried so far which doesn't work if my db has more than one match:
qs = post.objects.annotate(num_of_tags =
Count(Subquery(tags.objects.filter(post = OuterRef('pk'),
tag__body__in = search_list).only('pk')))).filter(num_of_tags__gt
= 0).order_by('num_of_tags')
when there's more than one instance in my db it returns this error:
django.db.utils.ProgrammingError: more than one row returned by a subquery used as an expression
Firstly you should follow some python/Django standards for naming. Model class should be Titleized (Post, Tag, PostTag) and singular
You can use the option through to define your own model for m2m:
class post(models.Model):
description = models.Charfield(max_length = 2000)
post_tags = models.ManyToManyField(tag, through=tags)
After that you can make use of django m2m to let you query easier:
from django.db.models import Q, Count
qs = post.objects.annotate(
num_of_tags=Count('post_tags', filter=Q(post_tags__body__in=search_list)))
).filter(num_of_tags__gt=0).order_by('num_of_tags')

how to apply the condition in django model

I have some model class like.
class user(models.Model):
Student = 's'
Hostel = 'h'
Pg = 'p'
type_of_user = (
(Student, 'Student'),
(Hostel, 'Hostel'),
(Pg, 'PG')
)
u_type = models.CharField(max_length=1, choices=type_of_user, default=Student)
and i have another class
class student(models.Model)
s_id = models.ForeignKey(user, on_delete=models.CASCADE)
but i apply the condition on s_id (show only that user where u_type=student)
what #dirkgroten just said is actually one of the possible solution to add condition but there is possible to add model field level validation. Django allow to add custome validation function in model field level link . And also if you are using serializer add custom validation there also another possible solution.

Django Relationship Name Collisions - Abstract Model has multiple relationships with another Model

My application consists of three Models: Users, Topics, and Responses.
Each Response may either be addressed at a Topic, or at another Response, but are largely identical. In the interest of not duplicating code, I thought it best to make an abstract model, Response, which ResponseResponse and TopicResponse inherit from.
from django.contrib.auth.models import User
from django.db.models import (CASCADE, CharField, DateTimeField,
ForeignKey, ManyToManyField, Model,
TextField)
class Topic(Model):
name = CharField(max_length = 100)
class Response(Model):
body = TextField()
topics = ManyToManyField(Topic)
agreers = ManyToManyField(User)
proposal = TextField()
affirms = ManyToManyField(User, related_name = 'affirmers')
rejects = ManyToManyField(User, related_name = 'rejectors')
class Meta:
abstract = True
class TopicResponse(Response):
responseTo = ForeignKey(Topic, on_delete = CASCADE)
class ResponseResponse(Response):
responseTo = ForeignKey(Response, on_delete = CASCADE)
The issue with this is that the User has two conflicting relationships called affirmers and two called rejectors.
If I don't give them related names, then instead TopicResponse and ResponseResponse each have three conflicting relationships, all of them called TopicResponse or ResponseResponse, respectively, (one for agreers, one for affirms, one for rejects).
An example error message is:
app.TopicResponse.rejects: (fields.E305) Reverse query name for 'TopicResponse.rejects' clashes with reverse query name for 'ResponseResponse.rejects'.
HINT: Add or change a related_name argument to the definition for 'TopicResponse.rejects' or 'ResponseResponse.rejects'.
If I leave off the related_name argument, I get error messages like this:
app.ResponseResponse.rejects: (fields.E304) Reverse accessor for 'ResponseResponse.rejects' clashes with reverse accessor for 'ResponseResponse.affirms'.
HINT: Add or change a related_name argument to the definition for 'ResponseResponse.rejects' or 'ResponseResponse.affirms'.
What can I do to fix all of these conflicts? I need to somehow have the related_name dynamically generated with the name of the of the concrete instance of the Model (like it is if you don't specify it) plus the name of the relationship.
You have to make the related name unique. As stated in the docs you can add %(class)s or %(app_label)s. These are then replaced by the child class values:
class Topic(Model):
name = CharField(max_length = 100)
class Response(Model):
body = TextField()
topics = ManyToManyField(Topic)
agreers = ManyToManyField(User)
proposal = TextField()
affirms = ManyToManyField(User, related_name = '%(app_label)s_%(class)saffirmers')
rejects = ManyToManyField(User, related_name = '%(app_label)s_%(class)srejectors')
class Meta:
abstract = True
class TopicResponse(Response):
responseTo = ForeignKey(Topic, on_delete = CASCADE)
class ResponseResponse(Response):
responseTo = ForeignKey(Response, on_delete = CASCADE)

Access foreign key fields from Admin Tabular Inline

I'm trying to access a field of a foreign key within a Tabular Inline in the Django Admin.
Despite my best efforts I can't seem to get it working. My current code is:
class RankingInline(admin.TabularInline):
model = BestBuy.products.through
fields = ('product', 'account_type', 'rank')
readonly_fields = ('product', 'rank')
ordering = ('rank',)
extra = 0
def account_type(self, obj):
return obj.products.account_type
Which results in:
'RankingInline.fields' refers to field 'account_type' that is missing from the form.
I have also tried using the model__field method, which I used as:
fields = ('product', 'product__account_type', 'rank')
Which results in:
'RankingInline.fields' refers to field 'product__account_type' that is missing from the form.
The models are defined as so:
class Product(BaseModel):
account_type = models.CharField(choices=ACCOUNT_TYPE_OPTIONS, verbose_name='Account Type', max_length=1, default='P')
class Ranking(models.Model):
product = models.ForeignKey(Product)
bestbuy = models.ForeignKey(BestBuy)
rank = models.IntegerField(null=True, blank = True)
class BestBuy(BaseModel):
products = models.ManyToManyField(Product, through='Ranking')
class BaseModel(models.Model):
title = models.CharField(max_length = TODO_LENGTH)
slug = models.CharField(max_length = TODO_LENGTH, help_text = """The slug is a url encoded version of your title and is used to create the web address""")
created_date = models.DateTimeField(auto_now_add = True)
last_updated = models.DateTimeField(auto_now = True)
What am I doing wrong?
I think what you are looking for is nested inlines since you want to expand "Product" as inline within RankingInline. At present Django does not have such feature built in. This question is relevant: Nested inlines in the Django admin?
You can also look at "Working with many-to-many intermediary models" section in Django DOC. That might be useful.
Actually Django will show you a small green '+' button besides the inline product field entry which you can use to create a new product to assign to your current entry for BestBuy. This might be an alternative for you to use.
You simply need to add the method-field to readonly_fields:
readonly_fields = ('product', 'rank', 'account_type')
Your new field account_type should be defined in ModelAdmin (i.e. RankingAdmin) not in TabularInline (i. e. RankingInline). It should be only accessed from TabularInline.

django model query back reference filter confusion

Given the following models
class Category(models.Model):
name = models.CharField(max_length=50)
class Business(models.Model):
name = models.CharField(max_length=50)
category = models.ForeignKey(Category, related_name="businesses")
class Package(models.Model):
business_id = models.ForeignKey(Business)
status = models.CharField(max_length=50)
I have 2 following queries get list of business and categories which the packages are live:
filter_businesses = Business.objects.filter(package__status = 'live')
filter_categories = Category.objects.filter(businesses__package__status = 'live')
Now the questions is, given the related name "businesses" should be equals to category.business_set, why shouldn't the filter in first query be package_set?
Suppose you have two related models: SomeModel and SomeOtherModel, and SomeOtherModel.somemodel is a ForeignKey to SomeModel.
Given any SomeModel instance, the someothermodel_set property is a manager for the related model already filtered. For example:
>>> your_some_model_instance = SomeModel.objects.all()[0]
In this case your_some_model_instance.shomeothermodel_set is equivalent to:
>>> SomeOtherModel.objects.filter(somemodel=your_some_model_instance)
[ update ]
sorry perhaps I didn't explain my questions more clearer, it's complicated to explain... I understand that XX_set and related_name refer to the manager, what I want to ask is in the first query why not use (package_set_status = 'live') given the second working query (businesses_package__status = 'live'), it's confusing because the second query references to the manager(by related_name), but the first query is not...
The filter interface uses the convention relatedmodelname__relatedmodelfield; In your example, related_name was used to give a fancier name to the backreference, but this is not its main purpose; the purpose of the related_name parameter in ForeignKey fields is solving the ambiguity in cases where relatedmodelname clashes with an already existing field at the ForeignKey.