So I have two models:
class UserData(models.Model):
""" Holds basic user data. """
id = models.IntegerField(primary_key=True, editable=False) # id is taken from data.
class ConsumptionTimePoint(models.Model):
""" Individual consumption time points with a One-to-Many relationship with UserData """
user_data = models.ForeignKey(UserData, on_delete=models.CASCADE)
And when I try and test them by creating them both, and their relationship in a test:
def test_basic_model_creation(self):
user_data_object = UserData.objects.create(id=1)
user_data_object.save()
consumption_time_point_object = ConsumptionTimePoint.objects.create(user_data=user_data_object)
consumption_time_point_object.save()
self.assertIsNotNone(consumption_time_point_object.user_data)
self.assertEquals(1, len(user_data_object.consumption_time_point_set.all()))
I get the following error:
AttributeError: 'UserData' object has no attribute 'consumption_time_point_set'
But from my understanding that's the correct way to get the set. Have I misnamed something? Or is this a testing issue?
To get the related queryset the class name is lowercased and _set is appended. Try consumptiontimepoint_set
You can also set the reverse relation name manually by using the related_name parameter.
Related
I am building a simple class group app in which I am trying to add particular users from another model's ManyToFieldField to a new model's ManyToFieldField.
class ClassGroup(models.Model):
admins = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='admins')
members = models.ManyToManyField(settings.AITH_USER_MODEL)
title = models.CharField(max_length=9999, default='')
class ClassGroupInvite(models.Model):
class_group = models.ForeignKey(ClassGroup, on_delete=models.CASCADE)
invite_receiver = models.ManyToManyField(class_group.admins.all())
invite_sender = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
As you can see that I am filtering (send request only to class group admins) in ClassGroupInvite with setting ManyToManyField with ClassGroup.admins
But when I try this then it is showing
ManyToManyField(<django.db.models.fields.related_descriptors.ManyToManyDescriptor object at 0x000001CE78793280>) is invalid. First parameter to ManyToManyField must be either a model, a model name, or the string 'self'
I also read the documentation about it, But I didn't find anything about defining it.
then I tried using ClassGroup.admins.all then it showed
AttributeError: 'ManyToManyDescriptor' object has no attribute 'all'
I have tried many times but it is still not working, Any help would be much Appreciated. Thank You in Advance.
I am attempting to reference the ManyToMany connection between Units and Add-Ons in my code to enable a method that provides the price, but I seem to be unable to reference the relationship in a Model method, can somebody point me in the right direction?
class Unit(models.Model):
class Meta:
permissions = (
('generate_unit_csv', 'can generate unit csv'),
)
unique_together = ['building', 'unit_number', 'property']
add_ons = models.ManyToManyField(
'properties.RentalAddOns', related_name='add_on_units')
...
def get_add_on_price(self):
total_price = 0
# there is no self.add_on_units or self.add_ons
for add_on in self.add_on_units:
total_price += add_on.price
return total_price
When I call the method I get an Attribute Error:
'Unit' object has no attribute 'add_on_units'
When I simple use self.add_ons I get:
'ManyRelatedManager' object is not iterable
As you've defined the field in this model, you need to refer to it as such. Also, you need to use the all() method on the resulting manager object to get all the related objects so that you can iterate over them:
self.add_ons.all()
And from the RentalAddOns model instance, you can refer all the Unit model instances as:
self.add_on_units.all()
The following sample database stores posts of news and relevant information for each piece of news. I'm interested in retrieving the topics associated with each news. The problem is, they are stored in different tables with complex relationships.
Each news is assigned with a newsid in the table NewsFeed:
class NewsFeed(models.Model):
newsid= models.OneToOneField('NewsSub',
on_delete=models.CASCADE, db_column='newsid',
primary_key=True)
def __str__(self):
return str(self.newsid)
An one-to-one relationship is defined between the field newsid in the class NewsFeed and the model NewsSub:
class NewsSub(models.Model):
newsid = models.BigIntegerField(primary_key=True)
In another class NewsTopic, a foreignKey relationship is defined between the field newsid with the model NewsSub:
class NewsTopic(models.Model):
newsid = models.ForeignKey(NewsSub, on_delete=models.DO_NOTHING,
db_column='newsid')
topicid = models.ForeignKey(NewsLabel, on_delete=models.DO_NOTHING,
db_column='topicid', related_name = 'topic')
In the NewsTopic db table, each newsid may correspond to more than one topicid. Finally, the field topicid of the class NewsTopic is related to the model NewsLabel:
class NewsLabel(models.Model):
topicid = models.BigIntegerField(primary_key=True)
topiclabel = models.CharField(max_length=100)
def __str__(self):
return self.topiclabel
In the NewsLabel db table, each toicid corresponds to a unique topiclabel.
My goal is to retrieve the topiclabel(s) associated with each NewsFeed object, by querying the newsid. Suppose result represents one such object, I'm wondering is it possible to do something like result.newsid.topicid.topiclabel?
Thanks and sorry for the long descriptions!!
#EvelynZ
You can use the prefech_related to fetch the values of the related object, please check the https://docs.djangoproject.com/en/2.1/ref/models/querysets/#prefetch-related
Looking at graphene_django, I see they have a bunch of resolvers picking up django model fields mapping them to graphene types.
I have a subclass of JSONField I'd also like to be picked up.
:
# models
class Recipe(models.Model):
name = models.CharField(max_length=100)
instructions = models.TextField()
ingredients = models.ManyToManyField(
Ingredient, related_name='recipes'
)
custom_field = JSONFieldSubclass(....)
# schema
class RecipeType(DjangoObjectType):
class Meta:
model = Recipe
custom_field = ???
I know I could write a separate field and resolver pair for a Query, but I'd prefer it to be available as part of the schema for that model.
What I realize I could do:
class RecipeQuery:
custom_field = graphene.JSONString(id=graphene.ID(required=True))
def resolve_custom_field(self, info, **kwargs):
id = kwargs.get('id')
instance = get_item_by_id(id)
return instance.custom_field.to_json()
But -- this means a separate round trip, to get the id then get the custom_field for that item, right?
Is there a way I could have it seen as part of the RecipeType schema?
Ok, I can get it working by using:
# schema
class RecipeType(DjangoObjectType):
class Meta:
model = Recipe
custom_field = graphene.JSONString(resolver=lambda my_obj, resolve_obj: my_obj.custom_field.to_json())
(the custom_field has a to_json method)
I figured it out without deeply figuring out what is happening in this map between graphene types and the django model field types.
It's based on this:
https://docs.graphene-python.org/en/latest/types/objecttypes/#resolvers
Same function name, but parameterized differently.
(Apologies if I'm missing some critical info to help diagnose this -- I'm new to Python and Django.)
Django complains when I try to use a string in my ManyToManyField through attribute:
File "/vagrant/flamingo_env/lib/python3.4/site-packages/django/db/models/fields/related.py", line 1366, in _check_relationship_model
for f in through._meta.fields:
AttributeError: 'str' object has no attribute '_meta'
Usage:
class Voter(models.Model):
# ...
addresses = models.ManyToManyField(Address, through='voter_addresses', through_fields=('voter_id', 'address_id'))
The error goes away if I create a Through model:
class VoterAddress(models.Model):
voter_id = models.ForeignKey(Voter)
address_id = models.ForeignKey(Address)
class Meta:
db_table = 'voter_addresses'
But of course then it complains that Voter hasn't been defined--and I can't simply change the order, or else VoterAddress won't have been defined either.
And in every single example I have seen the basic string version used. What's going on?
You need to fix the name passed to your through
addresses = models.ManyToManyField(Address, through='VoterAddress')
It has to be the exact name of the custom throughmodel
You will not be required to create a throughmodel if you do not pass the through argument. Django will create and manage one for you
To fix your ordering issue you can give a string value to the ForeignKey class.
class VoterAddress(models.Model):
voter_id = models.ForeignKey("Voter")
address_id = models.ForeignKey("Address")
class Meta:
db_table = 'voter_addresses'
This is a way to define foreignkeys to Models that haven't been defined in the file yet.
If you change this Django won't complain that Voter hasn't been defined.