Django model filter elements - python

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

Related

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)"

django model reference to own attribute

When i create a Django model i want to set the primary_key/ID to a combination of 2 attributes of this Model.
Example model:
class Example(models.Model):
name = models.CharField(max_length=100)
date = models.DateTimeField(default=now)
id = models.CharField(max_length=100, default="{}-{}".format(name, date) primary_key=True)
But he is saving the Model and not the values:
field=models.CharField(default='<django.db.models.fields.related.ForeignKey>-<django.db.models.fields.DateTimeField>', max_length=100, primary_key=True, serialize=False),
I know that name and date are a model in this context, but "self." is not working and i can't find a Django function to get the actual values instead.
It should work like this:
Input:
testmodel = Example(name="foo", date=datetime.now())
testmodel.save()
testmodel-id should look something like this "foo-2020-12-11..."
I don't think you can do that. Because these values are initialized at the making of an object. What you can do is to make your own class method to initialize these values.
class Example(models.Model):
name = models.CharField(max_length=100)
date = models.DateTimeField(default=now)
id = models.CharField(max_length=100, primary_key=True)
# In User class declaration
#classmethod
def create(cls,name, date):
return cls(name=name, date=date, id="{}-{}".format(name,date))
And Use it like this outside the class
p = Example.create("Fred", "11-12-2020")

How to add conditional fields to ModelAdmin in Django?

I have model classes:
class Product(models.Model):
category = models.ForeignKey(Category)
name = models.CharField(max_length=90)
...
class Category(models.Model):
name = models.CharField(max_length=90)
description = models.CharField(max_length=2000)
properies = models.ManyToManyField(Property)
...
#property type, ex: 'weight', 'length'
class Property(models.Model):
...
#value for every product
class PropertyValue(models.Model):
product = models.ForeignKey(Product)
property = models.ForeignKey(Property)
...
and I need custom product/add/ page, having PropertyValue forms set depends on chosen category.
I've made a method getting PropertyValue list by category_id in ModelAdmin class, but how can I call it in runtime when chosen category changes? Is it possible in django?
What do you mean when you said in runtime. If those categories change, the new records will apear every time you load the add pages.
Did you do yor form class? Kind of:
class PropertyValueForm(forms.Form):
product = forms.ModelChoiceField(queryset=Product.objects.all())
property = forms.ModelChoiceField(queryset=Property.objects.all())
Or:
def getProduct():
# DO YOUR STUFF
return product_list
class PropertyValueForm(forms.Form):
product = forms.ChoiceField(choices=get_my_choices())

Queryset for ManyToMany relation in Django

I can't understand how I should get queryset for groups, that contains user, I've tried _set, prefetch_select, but still without result.
class User(AbstractUser):
...
class Group(models.Model):
...
Member_list = models.ManyToManyField(User, through='Member', related_name="Member_list")
class Member(models.Model):
group = models.ForeignKey(Group)
user = models.ForeignKey(User)
...
I need get all Groups associated with that user, like
Groups where Member.objects.filter(user==request.user)
Im trying:
user = request.user
groups = user.group_set.all() # empty list :(
member = user.member_set.all() # works currectly, returns my 1 test group
I just create your base. Create group, user and connect them:
u = User.objects.create(name='user')
g = Group.objects.create()
m = Member.objects.create(group=g, user=u)
After this i can get user groups like this:
u.Member_list.all()
# output: [<Group: Group object>]
My base:
class User(models.Model):
name = models.CharField(max_length=4)
class Group(models.Model):
Member_list = models.ManyToManyField(User, through='Member', related_name="Member_list")
class Member(models.Model):
group = models.ForeignKey(Group)
user = models.ForeignKey(User)

Include intermediary (through model) in responses in Django Rest Framework

I have a question about dealing with m2m / through models and their presentation in django rest framework. Let's take a classic example:
models.py:
from django.db import models
class Member(models.Model):
name = models.CharField(max_length = 20)
groups = models.ManyToManyField('Group', through = 'Membership')
class Group(models.Model):
name = models.CharField(max_length = 20)
class Membership(models.Model):
member = models.ForeignKey('Member')
group = models.ForeignKey('Group')
join_date = models.DateTimeField()
serializers.py:
imports...
class MemberSerializer(ModelSerializer):
class Meta:
model = Member
class GroupSerializer(ModelSerializer):
class Meta:
model = Group
views.py:
imports...
class MemberViewSet(ModelViewSet):
queryset = Member.objects.all()
serializer_class = MemberSerializer
class GroupViewSet(ModelViewSet):
queryset = Group.objects.all()
serializer_class = GroupSerializer
When GETing an instance of Member, I successfully receive all of the member's fields and also its groups - however I only get the groups' details, without extra details that comes from the Membership model.
In other words I expect to receive:
{
'id' : 2,
'name' : 'some member',
'groups' : [
{
'id' : 55,
'name' : 'group 1'
'join_date' : 34151564
},
{
'id' : 56,
'name' : 'group 2'
'join_date' : 11200299
}
]
}
Note the join_date.
I have tried oh so many solutions, including of course Django Rest-Framework official page about it and no one seems to give a proper plain answer about it - what do I need to do to include these extra fields? I found it more straight-forward with django-tastypie but had some other problems and prefer rest-framework.
How about.....
On your MemberSerializer, define a field on it like:
groups = MembershipSerializer(source='membership_set', many=True)
and then on your membership serializer you can create this:
class MembershipSerializer(serializers.HyperlinkedModelSerializer):
id = serializers.Field(source='group.id')
name = serializers.Field(source='group.name')
class Meta:
model = Membership
fields = ('id', 'name', 'join_date', )
That has the overall effect of creating a serialized value, groups, that has as its source the membership you want, and then it uses a custom serializer to pull out the bits you want to display.
EDIT: as commented by #bryanph, serializers.field was renamed to serializers.ReadOnlyField in DRF 3.0, so this should read:
class MembershipSerializer(serializers.HyperlinkedModelSerializer):
id = serializers.ReadOnlyField(source='group.id')
name = serializers.ReadOnlyField(source='group.name')
class Meta:
model = Membership
fields = ('id', 'name', 'join_date', )
for any modern implementations
I was facing this problem and my solution (using DRF 3.6) was to use SerializerMethodField on the object and explicitly query the Membership table like so:
class MembershipSerializer(serializers.ModelSerializer):
"""Used as a nested serializer by MemberSerializer"""
class Meta:
model = Membership
fields = ('id','group','join_date')
class MemberSerializer(serializers.ModelSerializer):
groups = serializers.SerializerMethodField()
class Meta:
model = Member
fields = ('id','name','groups')
def get_groups(self, obj):
"obj is a Member instance. Returns list of dicts"""
qset = Membership.objects.filter(member=obj)
return [MembershipSerializer(m).data for m in qset]
This will return a list of dicts for the groups key where each dict is serialized from the MembershipSerializer. To make it writable, you can define your own create/update method inside the MemberSerializer where you iterate over the input data and explicitly create or update Membership model instances.
I just had the same problem and I ended it up solving it with an annotation on the group queryset.
from django.db.models import F
class MemberSerializer(ModelSerializer):
groups = serializers.SerializerMethodField()
class Meta:
model = Member
def get_groups(self, instance):
groups = instance.groups.all().annotate(join_date=F(membership__join_date))
return GroupSerializer(groups, many=True).data
class GroupSerializer(ModelSerializer):
join_date = serializers.CharField(required=False) # so the serializer still works without annotation
class Meta:
model = Group
fields = ..., 'join_date']
NOTE: As a Software Engineer, I love to use Architectures and I have deeply worked on Layered Approach for Development so I am gonna be Answering it with Respect to Tiers.
As i understood the Issue, Here's the Solution
models.py
class Member(models.Model):
member_id = models.AutoField(primary_key=True)
member_name = models.CharField(max_length =
class Group(models.Model):
group_id = models.AutoField(primary_key=True)
group_name = models.CharField(max_length = 20)
fk_member_id = models.ForeignKey('Member', models.DO_NOTHING,
db_column='fk_member_id', blank=True, null=True)
class Membership(models.Model):
membershipid = models.AutoField(primary_key=True)
fk_group_id = models.ForeignKey('Group', models.DO_NOTHING,
db_column='fk_member_id', blank=True, null=True)
join_date = models.DateTimeField()
serializers.py
import serializer
class AllSerializer(serializer.Serializer):
group_id = serializer.IntegerField()
group_name = serializer.CharField(max_length = 20)
join_date = serializer.DateTimeField()
CustomModels.py
imports...
class AllDataModel():
group_id = ""
group_name = ""
join_date = ""
BusinessLogic.py
imports ....
class getdata(memberid):
alldataDict = {}
dto = []
Member = models.Members.objects.get(member_id=memberid) #or use filter for Name
alldataDict["MemberId"] = Member.member_id
alldataDict["MemberName"] = Member.member_name
Groups = models.Group.objects.filter(fk_member_id=Member)
for item in Groups:
Custommodel = CustomModels.AllDataModel()
Custommodel.group_id = item.group_id
Custommodel.group_name = item.group_name
Membership = models.Membership.objects.get(fk_group_id=item.group_id)
Custommodel.join_date = Membership.join_date
dto.append(Custommodel)
serializer = AllSerializer(dto,many=True)
alldataDict.update(serializer.data)
return alldataDict
You would technically, have to pass the Request to DataAccessLayer which would return the Filtered Objects from Data Access Layer but as I have to Answer the Question in a Fast Manner so i adjusted the Code in Business Logic Layer!

Categories