This problem almost drives me crazy :(
I was trying to use the StackedInline in admin interface.
The code below is in django documentation.
model.py
class Person(models.Model):
name = models.CharField(max_length=128)
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
class Membership(models.Model):
person = models.ForeignKey(Person)
group = models.ForeignKey(Group)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
admin.py
class MembershipInline(admin.StackedInline):
model = Membership
extra = 1
class PersonAdmin(admin.ModelAdmin):
inlines = (MembershipInline,)
class GroupAdmin(admin.ModelAdmin):
inlines = (MembershipInline,)
But if the Group is an abstract base class and PublicGroup is subclass that inherits from Group. Membership is used to relate PublicGroup and Person.
class Person(models.Model):
name = models.CharField(max_length=128)
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='%(class)s_Membership')
class Meta:
abstract = True
class PublicGroup(Group):
pass
class Membership(models.Model):
person = models.ForeignKey(Person)
group = models.ForeignKey(Group)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
after running the command
python manage.py sql test
I got error "AssertionError: ForeignKey cannot define a relation with abstract class Group".
After searching for solution, I know foreign key cannot point to a abstract class. Some solutions recommended to use generic relation. So I change the code again.
class Person(models.Model):
name = models.CharField(max_length=128)
class Group(models.Model):
name = models.CharField(max_length=128)
members = generic.GenericRelation('Membership')
class Meta:
abstract = True
class PublicGroup(Group):
pass
class Membership(models.Model):
person = models.ForeignKey(Person)
content_type = models.ForieignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey()
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
This time the command
python manage.py sql test
returns no error. But I got error when I try to add data on admin interface. The error says Membership is not a foreign key of PublicGroup. StackedInline still doesn't work.
Now I really don't know what to do. Does anyone know how to achieve this function.
Thanks for reading!
Is there any good reason why you use this?
class Meta:
abstract = True
If possible, drop it, and then rebuild your database.
It might be interesting for you to read the answers to this stackoverflow question about the difference between abstract models and regular inheritance.
Your model structure is terrible: a M2M relationship will build a relationship table for both Models you try to connect, just like "Through keyword" in M2M field
As I can see, you just want to build a M2M relation between Person and Model based on Group.
class Person(models.Model):
name = models.CharField(max_length=128)
class Group(models.Model):
name = models.CharField(max_length=128)
type = models.CharField(max_lenght=32) # The Type of Group (Public/Private/etc..)
members = models.ManyToManyField(Person, through='Membership')
class Membership(models.Model):
person = models.ForeignKey(Person)
group = models.ForeignKey(Group)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
Related
I have a Django model used extensively in my app. I'd like to create another model that inherits from that one so I can continue using the original model throughout the code, but move a field to the new model
I have:
class MyModel(models.Model):
field1 =...
field2=...
field3=...
I want to move field3 to a new model:
class MyModel2(MyModel):
field3=...
Then I'd like MyModel instances where field3 is not null to become MyModel2 instances.
The code would continue to refer to MyModel, but in some special cases, I'd use MyModel2 instead. Is this possible? Advisable? Is there a better way? I considered making a base abstract model that both could inherit from, but then you can't use the abstract model in forms and things.
Actual model:
class Unit(models.Model):
address = models.ForeignKey(Address)
name = models.CharField(max_length=500, verbose_name="Unit Name")
payments = GenericRelation("Payment", content_type_field='content_type', object_id_field='object_pk')
permissions = GenericRelation("CustomPermission", content_type_field='content_type', object_id_field='object_pk')
association = models.ForeignKey(Association, blank=True, null=True)
def __unicode__(self):
return self.name
"association" is the field I want to move to another model.
I guess you should use abstract = True https://docs.djangoproject.com/en/1.10/topics/db/models/#abstract-base-classes
class MyModel(models.Model):
field1 =...
field2=...
field3=...
class Meta:
abstract = True
class MyModel2(MyModel):
field4=...
class AssociationBase(models.Model):
association = models.ForeignKey(Association, blank=True, null=True)
class Meta:
abstract = True
class Unit(AssociationBase):
address = models.ForeignKey(Address)
name = models.CharField(max_length=500, verbose_name="Unit Name")
payments = GenericRelation("Payment", content_type_field='content_type', object_id_field='object_pk')
permissions = GenericRelation("CustomPermission", content_type_field='content_type', object_id_field='object_pk')
def __unicode__(self):
return self.name
I tried to create a model with a many to many self relation, i put this in my code:
class Person(models.Model):
name = models.CharField(max_length=50)
shape_clm = models.ManyToManyField("self", through='Friend', symmetrical=False)
def __str__(self):
return self.name
class Friend(models.Model):
pers_one = models.ForeignKey(Person)
pers_two = models.ForeignKey(Person)
type = models.CharField(max_length=150)
But when i tried to migrate the model to the DB the following error is raised:
Friend.pers_one: reverse accessor for Friend.pers_one clashes with reverse accessor for Friend.pers_two
I'm using Postgres as DB server, how i can make this m2m relation?
You need to add the related_name keyword argument, otherwise the ORM can't tell how will you refer to either of the fields.
class Friend(models.Model):
pers_one = models.ForeignKey(Person, related_name='pers_ones')
pers_two = models.ForeignKey(Person, related_name='pers_twos')
Add related_name arguments to your ForeignKeys in the Friend ModelClass:
class Friend(models.Model):
pers_one = models.ForeignKey(Person, related_name="friends_one")
pers_two = models.ForeignKey(Person, related_name="friends_two")
type = models.CharField(max_length=150)
For more information about related_name take a look at the docs.
I'm trying to filter many-to-many relationship by some through Class field.
Quoting the Django documentation, i will explain my goal
class Person(models.Model):
name = models.CharField(max_length=128)
def __unicode__(self):
return self.name
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
def __unicode__(self):
return self.name
class Membership(models.Model):
person = models.ForeignKey(Person)
group = models.ForeignKey(Group)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
In this example my goal sould be filter many to many relationship and obtain only the Person who has joined some Group starting from certain date (date_joined field).
Is it possible?
You can query across relationships with the django ORM (or in this case the reverse relationship):
person = Person.objects.filter(
membership__group=example_group,
membership__date_joined__gte=example_date
)
You can also do this:
person = example_group.members.filter(
membership__date_joined__gte=example_date
)
I have the following models, with publication needing a m2m with authors via the join table specified, I have done this but keep getting the error:
Error: One or more models did not validate:
publications.workshop: 'staff' is a manually-defined m2m relation through model AuthorsJoinTable, which does not have foreign keys to Staff and Workshop
publications.technicalreport: 'staff' is a manually-defined m2m relation through model AuthorsJoinTable, which does not have foreign keys to Staff and TechnicalReport
publications.authorsjointable: 'publication' has a relation with model Publication, which has either not been installed or is abstract.
publications.authorsjointable: "unique_together" refers to staff, a field that doesn't exist. Check your syntax.
My models look like:
class Publication(models.Model):
title = models.CharField(max_length=500)
staff = models.ManyToManyField("personnel.Staff", related_name='%(app_label)s_%(class)s_related', through='AuthorsJoinTable')
tag = models.ManyToManyField("Tag", related_name='%(app_label)s_%(class)s_related')
class Meta:
abstract = True
class Workshop(Publication):
location = models.CharField(max_length=100)
workshop_title = models.CharField(max_length=100)
start_date = models.DateField()
end_date = models.DateField()
def __unicode__(self):
return u'%s - %s' % (self.title, self.workshoptitle)
class TechnicalReport(Publication):
published_date = models.DateField()
class AuthorsJoinTable(models.Model):
author = models.ForeignKey("Author", related_name='%(app_label)s_%(class)s_from')
publication = models.ForeignKey("Publication", related_name='%(app_label)s_%(class)s_to')
order = models.IntegerField()
class Meta:
unique_together = ('staff', 'publication')
class Tag(models.Model):
tag_name = models.CharField(max_length=100, primary_key=True)
class Author(models.Model):
name = models.CharField(max_length=100)
biography = models.TextField()
So how can I resolve this problem?
publications.authorsjointable: "unique_together" refers to staff, a field that doesn't exist. Check your syntax.
You can't create a ForeignKey on absract model because that model does not have a table in DB and therefore does not have primary key to reference. So you should make your Publication non-abstract or reference Workshop instead. Other error lines should also be gone after that.
I have an unusual problem. Let's consider such models (taken from django docs):
class Person(models.Model):
name = models.CharField(max_length=128)
def __unicode__(self):
return self.name
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
def __unicode__(self):
return self.name
class Membership(models.Model):
person = models.ForeignKey(Person)
group = models.ForeignKey(Group)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
Now, let's say we've got 2 Beatles members in out Beatles band (following the example in django docs for intermediate models):
>>> beatles.members.all()
[<Person: Ringo Starr>, <Person: Paul McCartney>]
The above code will return members sorted by default ordering for Person model. If I specify:
>>> beatles.members.all().order_by('membership__date_joined')
the members, are sorted via the date joined. Can I somehow set this as default behavior for this ManyToMany field? That is to set default order of related items by field in the intermediate model? The ManyRelatedManager seems to have an init argument core_filters, but I have no vague idea how to access it withous subclassing the whole m2m field in django. Any creative ideas? :)
Thanks in advance :)
I've opened a ticket in django trac.
Here is a dirty-hack method to achieve this (look at Group model):
class Person(models.Model):
name = models.CharField(max_length=128)
def __unicode__(self):
return self.name
class Group(models.Model):
name = models.CharField(max_length=128)
_members = models.ManyToManyField(Person, through='Membership')
#property
def members(self):
return self._members.order_by('membership__date_joined')
def __unicode__(self):
return self.name
class Membership(models.Model):
person = models.ForeignKey(Person)
group = models.ForeignKey(Group)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
Didn't bother to create a set property decorator, but it should be quite easy to mimic the setting of original field. Ugly workaround, but seems to do the trick.
I think this should work:
class Membership(models.Model):
...
class Meta:
ordering = ['date_joined']