ManyToMany Relation using Django - python

I have the following code on models.py
class Movie(models.Model):
mov = models.CharField(max_length = 500)
def __str__(self):
return self.mov
class Atrib(models.Model):
atrib = models.CharField(max_length = 500)
def __str__(self):
return self.atrib
class Dict(models.Model):
atrib = models.ForeignKey(Atrib)
dictionary = models.ManyToManyField(Movie, related_name = 'dictionary')
I want to load a defaultdict like this: {attribute1:[movie1, movie2, ...], atribute2:[movie2, movie3,...] ... } using Django.
First of all, I added all the attributes of the dictionary using the Atrib class.
Now I need to add, for every attribute, the related movies. I tried to do the following, considering only one attribute (just testing):
attribute1 = Atrib(atrib = atribs)
for m in dictionary[attribute]:
m = Movie(mov = m)
m.save()
attribute1.dictionary.add(m)
It shows me the following error:
AttributeError: 'Atrib' object has no attribute 'dictionary'.
Am I doing the models correctly for this type of dictionary? And why is this error occurring? I am new in Django and I am a little lost!
Thanks in advance!

First of all you need to save attribute1 = Atrib(atrib = atribs)
do attribute1.save()
Next, after Attribute object creation you don't have Dictionary object related to it.
You need to create it first, set it to this object and then you will have ability to operations you want.
Note: to access attribute.dict you need OneToOne relationship, not ForeignKey.

Related

Can you use a class object as property in Django?

I have three models in my Django application - simplified for demonstration. The first one is Base. The second one is Bill and has foreign key "base" to Base model. The third one is Point, and has a foreign key to Bill.
class Base(models.Model):
type = models.CharField()
desc = models.IntegerField()
class Bill(models.Model):
base = models.ForeignKey("Base", related_name="bills")
total_value = models.DecimalField()
class Point(models.Model):
bill = models.ForeignKey("Bill", related_name="points")
value = models.DecimalField()
My goal is to have a property for Base called def bill(self), that would sum up all "bill" objects fields and returned a bill-like instance. I would like to get a base object:
my_base = Base.objects.get()
bill = Base.bill <-- I can figure this out with #property
points = bill.points <-- this does not work through #property function.
My current solution is like this, to get the first part working:
class Base():
...
#property
def bill(self):
sums = self.bills.aggregate(total_value=Sum('total_value'))
return Bill(**sums)
The second part, that would sum up bill-related-points and return them in a my_base.bill.points, does not work. If I filter for points and try to assign them to Bill(**sums).points = filtered_points, I get an error: Direct assignment to the reverse side is prohibited, or Unsaved model instance cannot be used in an ORM query
Is there a more elegant solution to this? A good option would be to initate class as a #property like so:
class Base(model.Model):
...
class bill(...):
self.total_value = .
self.points = .
but I don't believe that is achievable.
Thank you

check related object or not

I need to check my object related or not ORM postgresql/
I have two object ItemVariationValue and ItemVariation i need to check
ItemVariationValue has relation with ItemVariation
models.py
class ItemVariation(models.Model):
item=models.ForeignKey(Item,on_delete=models.CASCADE)
price=models.IntegerField(blank=True,null=True,default=0)
item_code=models.CharField(max_length=500)
keywords= models.ManyToManyField(Keyword)
image=models.ImageField(upload_to='dishes/', blank=True, null=True)
def __str__(self):
return str(self.id)
class ItemVariationValue(models.Model):
item=models.ForeignKey(Item,on_delete=models.CASCADE)
item_variation=models.ForeignKey(ItemVariation,on_delete=models.CASCADE)
attribute=models.ForeignKey(Attribute,on_delete=models.CASCADE)
attribute_value=models.ForeignKey(AttributeValue,on_delete=models.CASCADE)
def __str__(self):
return str(self.id)
views.py
def get_items(request): # request= {"order_details": "varxxx:1"}
order=request.data['order_details']
items = order.split(',')
total = 0
for item in items:
od = item.split(':')
sku = str(od[0])
qty = int(od[1])
itemvariation=ItemVariation.objects.get(item_code=sku)
# if ItemVariationValue.item_variation has ForeignKey(ItemVariation):
Note (ForeignKey nomenclature): ForeignKeys should not have an _id suffix, since Django will automatically construct an extra field fieldname_id that contains the primary key. By writing an _id suffix, you will introduce extra attributes like item_variation_id_id. Although strictly speaking that is not a problem, it introduces a lot of confusion. For example my_itemvariationvalue.itemvariation_id will result in an ItemVariation object, etc.
If you fix the ForeignKey names, you can check this like:
# given the ForeignKey is named itemvariation, not itemvariation_id and use Comparison Operators
if my_itemvariationvalue.itemvariation_id == my_itemvariation.id:
# ... (objects are related)
else:
# ... (otherwise)
By using the itemvariation_id here, we avoid loading the related object, and thus potentially an extra database query.
As far as i know you have a ItemVariationValue object and you want to know if this object has ItemVariation. so you can easily do
#your code
itemvariation=ItemVariation.objects.get(item_code=sku)
check_relation_obj=itemvariation.item_variation
also if you think you may or may not have relation with ItemVariation
add blank=True,null=True with Foreign Key.

django-tables 2 M2M field not shown

I am trying to show a M2M field in a django-table2 as seen in Django-tables2: How to use accessor to bring in foreign columns? and Accessing related models with django-tables2
Using: foreigncolumn = tables.Column(accessor='foreignmodel.foreigncolumnname'), I only see a '--'...
# The models:
class Organism(models.Model):
species_name = models.CharField(max_length=200)
strain_name = models.CharField(max_length=200)
eukaryotic = models.BooleanField(default=True)
lipids = models.ManyToManyField('Lipid',blank=True)
class Lipid(models.Model):
lm_id = models.CharField(max_length=100)
common_name = models.CharField(max_length=100,blank=True)
category = models.CharField(max_length=100,blank=True)
#The tables
class OrganismTable(tables.Table):
name = tables.LinkColumn('catalog:organism-detail', text=lambda record: record.species_name, args=[A('pk')])
lp = tables.Column(accessor='Lipid.common_name')
class Meta:
model = Organism
sequence = ['name','lp']
exclude = ['id','species_name']
Any idea what I'm doing wrong?
This does not work so easily for ManyToManyFields because of the simple way Accessor works. You could display the repr of the related QuerySet via 'lipids.all' but that does not seem sufficient here. You can, however, add a property (or method) to your Organism model and use it in the accessor. This way, you can display any custom information related to the instance:
class Organism(models.Model):
# ...
#property
def lipid_names(self):
return ', '.join(l.common_name for l in self.lipids.all()) # or similar
class OrganismTable(tables.Table):
# ...
lp = tables.Column(accessor='lipid_names')
I would recommend then to add a prefetch_related('lipids') to the Organism QuerySet that you pass to the table for better performance.

How to get properties of a model attribute?

Let's say that I have a class such as :
class MyClass(models.Model):
attributeA = models.CharField(max_length=100)
attributeB = models.IntegerField()
attributeC = models.CharField(max_length = 150, blank=True, nullable = True)
attributeD = models.ForeignKey('ModelB',related_name='FK_modelB')
attributeE = models.ManyToManyField('ModelC')
What I want to do is to get the properties of every attribute, not just the name that I got with :
my_instance._meta.get_all_field_name()
(which gave me a list of attributes names). No, what I want is, for every attribute, know what is his type (CharField,IntegerField, ForeignKey, ManyToManyField...), who's related if it's a ForeignKey / ManyToManyField and all the meta data such as max_length and so on.
The aim of it is to serialize a class into a XML and the representation in the XML will be different if it's a ManyToManyField, a ForeignKey or a simple value.
By the way, If anyone know a great class serializer to XML, it would help me a lot !
Thanks for your responses !
Django models _meta.fields is fields list that you can access to get field attributes:
>>> from django.contrib.auth.models import User
>>> u = User.objects.all()[0]
>>> u._meta.fields[1].__class__.__name__
'CharField'
>>> u._meta.fields[1].name
'username'
>>> u._meta.fields[1].max_length
30
>>> u._meta.fields[1].blank
False
# ...
You can get attributes of a specific field by using get_field()
MyClass._meta.get_field('attributeA').max_length

How to assign items inside a Model object with Django?

Is it possible to override values inside a Model?
I am getting 'MyModel' object does not support item assignment.
my_model = MyModel.objects.get(id=1)
print my_model.title
if my_model.is_changed:
my_model['title'] = 'something' # 'MyModel' object does not support item assignment
params = {
'my_model': my_model,
...
}
return render(request, 'template.html', params)
Models are objects, not dictionaries. Set attributes on them directly:
if my_model.is_changed:
my_model.title = 'something'
Or, if the attribute name is dynamic, use setattr:
attr_name = 'title' # in practice this would be more complex
if my_model.is_changed:
setattr(my_model, attr_name, 'something')
This changes the in-memory copy of the model, but makes no database changes - for that your attribute would have to be a field and you'd have the call the save method on my_model. You don't need to do that if you just want to change what the template receives in its context, but just for completeness's sake:
if my_model.is_changed:
my_model.title = 'something'
my_model.save()
Dictionaries are mutable, if you actually have a dictionary:
mydict = {'title': 'foo'}
# legal
mydict['title'] = 'something'
But not everything is a dictionary.
Yes, you can change values, but this is not how its done. Django Models are Python classes that have models to represent fields. For example a CharField is for holding a string in a database. Let me demonstrate (code from django docs):
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
As you can see above the Python class is a custom Django model. It is linked to a databse, and when you run manage.py syncdb, it will interact with your database to create the tables and columns that you need it to.
Now, in your case:
if my_model.is_changed:
my_model.title = "Something"
my_model.save()
my_model is an object. So, try this:
if my_model.is_changed:
my_model.title = 'something'
my_model.save()
I was using inlineformset_factory, what I had to do was:
Instead of using my_model.title = 'something',
I had to use my_model.instance.title = 'something'
views.py
...
if request.method == "POST":
formset = modelName2(request.POST, instance=modelName1)
if formset.is_valid():
if changeInstance == True:
models = formset
# change the title if changeInstance is True
index = 0
model = models[index]
model.instance.title = "something else"
model.save()
...

Categories