django - initialize model fields including manytomanyfields - django

All,
I have a set related models:
class Foo(models.Model):
fooName = models.CharField()
bars = models.ManyToManyField("Bar")
class Bar(models.Model):
barName = models.CharField()
When I create a new one, I would like for it to have a default set of data. This is pretty easy to do for normal fields. But I'm not sure what to do for relationship fields. Let's pretend that I want every foo to be initialized with the name "I am a foo" and a set of three bars, each with specific names (say, "I am bar one," "I am bar two," and "I am bar three.").
def Initialize(self)
self.fooName = "I am a foo"
self.bars = ?!?
I'm just not sure how to go about this. Any suggestions?

You may not use a many to many relation on a model instance that doesn't have a primary key.
Save the model, to enable m2m relations
Save your other model, to enable m2m relations on the other side as well
Use .add(), for example yourmodel.bars.add(othermodel)
If you want to set default, initial data, you should use fixtures.

You can do this using django's signals. Every time an instance of your Foo model is created, also create the other information you require:
class Foo(models.Model):
...
from django.db.models.signals import post_save
from signals import create_initial_data
post_save.connect(create_initial_data, sender=Foo)
and in a file called signals.py:
from models import Bar
def create_initial_data(sender, instance, created, raw):
if created and sender == 'Foo':
bar_1 = Bar(...)
bar_2 = Bar(...)
...
bar_1.save()
bar_2.save()
...
instance.bars.add(bar_1, bar_2, ...)
instance.save()

Related

django models to model 'has-a' and 'contains' relationships

I have the following entities:
from django.db import models
class Foo(models.Model):
pass
class Bar(models.Model):
pass
class FooBar(models.Model):
pwned_foo = # Foobar contains one Foo object
bars = # Collection of Bar objects
How do I express the relation between Foo, Bar and FooBar in the FooBar class?
I think you want a OneToOneField and a ForeignKey like this:
from django.db import models
class Foo(models.Model):
pass
class Bar(models.Model):
foobar = models.ForeignKey(FooBar, related_name='bars')
class FooBar(models.Model):
pwned_foo = models.OneToOneField(Foo)
bars = # Collection of Bar objects
# you can access bars via the reverse relationship like
# myfoobar.bars
This assumes you want a 1-N relation with bars. If you want an N-N relation, then use a ManyToManyField.
If you really need to keep Bar clean of any relationship (can you explain why?) you could try something like ArrayField with the caveats that this only works on postgresql, and you would need to reimplement relationships in querysets, etc... And I suspect performance would suffer too...
from django.db import models
class Foo(models.Model):
pass
class Bar(models.Model):
pass
class FooBar(models.Model):
pwned_foo = models.OneToOneField(Foo, on_delete=models.CASCADE)
bars = models.ForeignKey(Bar, on_delete=models.CASCADE)

Django filter across many to many field

This is a simplified version of my models:
class User(models.Model):
pass
class Foo(models.Model):
owners = models.ManyToManyField(User)
bar = models.ForeignKey(Bar)
class Bar(models.Mode)
pass
I have a user instance and I would like to compute a queryset for all Bar instances associated with that user. Going from user to Bar consists of getting all Foo objects that have user as owner and then getting all bar instances associated with each Foo.
How can I express this most efficiently using django queries?
Add related names to your model Foo. This will facilitate the writing of queries.
class Foo(models.Model):
owners = models.ManyToManyField('User', related_name='foo')
bar = models.ForeignKey('Bar', related_name='foo')
Now assuming that you have a single user instance as you mentioned, you could make a query like this:
user = User.objects.get(pk=1)
qs = Bar.objects.filter(foo__owners=user)
If you by most efficient mean the performance and not the expression, then you should take a look at prefetch_related and select_related methods of QuerySet.

Django InlineAdmin for ManyToMany field which doesn't have an explicitly named through

I have two models, with ManyToMany relationships:
App1:
class Foo:
fld = models.CharField(null=True, blank=True)
App2:
class Bar:
foos = models.ManyToManyField(Foo, blank=True)
Now, on the admin view of Bar, I'd like to present foos. I cannot simply list foos as a ManyToMany field, I get an error message.
So I try to do:
class BarFooInline(admin.TabularInline):
model = Bar_foos
class BarAdmin(admin.ModelAdmin):
model = Bar
inlines = [BarFooInline, ]
admin.site.register(Bar, BarAdmin)
I got the name Bar_foos by look into the Meta of Bar. Bar.foos.through yields that as a proper models.Bar_foos. But since I didn't explicitly name the through, it's not really in the models.py, so I cannot import that. What should I do?
I don't want to create a through now, because I already have a whole bunch of association information in the table, and I have a feeling that wouldn't be magically data migrated into the newly named association entity's table (https://mounirmesselmeni.github.io/2013/07/28/migrate-django-manytomany-field-to-manytomany-through-with-south/).
Also, I cannot move the ManyToMany field from App2 to App1.
class BarFooInline(admin.TabularInine):
models = Bar.foos.through
class BarAdmin(admin.ModelAdmin):
model = Bar
inlines = [BarFooInline]
exclude = ['foos']
Working with many-to-many models.

many to many field omitted in database table when running syncdn

I have a field with M2M relationship.when running syncdb,the field with M2M field does not form on the database.
here is the model
class Eventgroups(models.Model):
event=models.ManyToManyField(Event)
group_name=models.CharField(max_length=100)
def __unicode__(self):
return "%s, %s" \
% (self.group_name, self.event)
class Meta:
db_table= 'eventgroup'
verbose_name_plural='eventgroups'
events field is not created on database
I would appreciate an insight to this problem please
Regards,
Joshua
Everything is ok. You just don't understand how ManyToMany is realized on the SQL level. Simply speaking, this
class Foo(models.Model):
#...
class Bar(models.Model):
foo = models.ManyToManyField(Foo)
is technically the same as this:
class Foo(models.Model):
#...
class Bar(models.Model):
#...
class BarFoo(models.Model):
foo = models.ForeignKey(Foo)
bar = models.ForeignKey(Bar)
And if you'll check your database - you will find a table called EventgroupsEvent or something like that which contains the actual fields. It's just the ORM that lets you connect the models directly. Please read my answer here for a detailed explanation on how ManyToMany works in the background
It wont create a field named event instead, it will create a new table Eventgroups_event

Django: making relationships in memory without saving to DB

I have some models with relationships like this:
class Item(model.Model):
name = models.CharField()
class Group(models.Model):
item = models.ManyToManyField(Item)
class Serie(models.Model):
name = models.CharField()
chart = models.ForeignKey(Chart)
group = models.ForeignKey(Group)
class Chart(models.Model):
name = models.CharField()
I need to create a Chart object on the fly, without saving to the DB. But I can't do it because Django tries to use the objects primary keys when assigning the relationships.
I just want Group.add(Item()) to work without having to save the objects to the DB.
Is there any simple way around this?
Reviving here for the sake of future readers:
I've gotten around this use case by defining a private attribute that represents the relationship inside the classes and a property to inspect wether the object can be retrieved from the DB or resides in memory.
Here is a simple example:
class Parent(models.Model):
_children = []
name = models.CharField(max_length=100)
#property
def children(self):
if _children:
return self._children
else:
return self.children_set.all()
def set_virtual_children(self, value): # could use a setter for children
self._children = value # Expose _children to modification
def some_on_the_fly_operation(self):
print(','.join([c.name for c in self.children]))
class Children(models.Model):
parent = models.ForeignKey(Parent)
name = models.CharField(max_length=100)
This way, I can set the "virtual children" and use all the defined methods "on the fly"
EDIT: It seems that approach described here isn't enough for django to allow adding to the ManyToMany relationship.
Have you tried to add primary_key=True and unique=True to the name attribute of the Item model. Then doing Group.add(Item("item_name_here")) should work if you have the possibility to create the name on the fly.
I didn't test it, but I think your way failed because add() wants to use the primary-key which by default is the autoincrementing id that is assigned when it is saved to the database.