I just need a little help thinking through this, if someone could be so kind.
class object_a(models.Model):
foo = models.blah
bar = models.blah
class object_b(models.Model):
foop = models.blah
barp = models.blah
In another model I have a class that I want to have a single relationship with both fields. For example, in the admin I want a list of both object_a and object_b objects selectable in some sort of relationship.
I know a generic relationship of some sort can do this, I just can't quite get to the end of the though. all help is appreciated.
Thanks.
Use the contenttypes framework provided by Django:
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
class Other(models.Model):
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
Then you can create some of your main objects:
>>> from myapp.models import object_a, object_b, Other
>>> a = object_a()
>>> a.foo = 'test'
>>> a.bar = 'value'
>>> a.save()
>>> b = object_b()
>>> b.foop = 'random'
>>> b.barp = 'values'
>>> b.save()
And then save references to them in Other objects:
>>> o1 = Other()
>>> o1.content_object = a
>>> o1.save()
>>> o2 = Other()
>>> o2.content_object = b
>>> o2.save()
Now if we ask for all the Other objects and inspect them:
>>> all = Other.objects.all()
>>> all[0].content_object
<object_a: object_a object>
>>> all[0].content_object.foo
u'test'
>>> all[1].content_object
<object_b: object_b object>
>>> all[1].content_object.foop
u'random'
By looking at the fields on the Other object, we can see how Django stores the generic relations:
>>> all[0].content_type
<ContentType: object_a>
>>> all[0].object_id
1
When you run the syncdb command to install your models, Django creates a unique ContentType object for each model. When you use generic relations, you store a foreign key to this content type entry (identifying what type of object is at the other end of the relation), and the unique ID of the model instance. The generic.GenericForeignKey field is not stored in the database, but is a wrapper which takes the content type and object ID and retrieves the actual object for you.
Related
I am trying to store a dictionary in my Django project as a model. The model is present but it wont update the values. any ideas?
model.py:
class MyModel(models.Model):
jsonM = JSONField()
Main.py:
myList = [1,2,3,4,5,6,7,8,9]
print("this is my model")
MyModel.objects.all().update(jsonM=myList)
When i do:
print(MyModel.objects.all())
print(type(MyModel.objects.all()))
I get the following:
<QuerySet []>
<class 'django.db.models.query.QuerySet'>
Try this:
newObject = MyModel(jsonM = mylist)
newObject.save()
I wanted to create a follower system, and I get a "ValueError: instance is not saved." Use bulk = False or save the object first. " .Please how to solve this problem, sorry for my bad writing!!
#my models.py
from django.db import models
from django.contrib.auth import get_user_model
User = get_user_model()
class Follower(models.Model):
follower = models.ForeignKey(User, related_name='following', on_delete=None)
following = models.ForeignKey(User, related_name='followers', on_delete=None)
class Meta:
unique_together = ('follower', 'following')
def __unicode__(self):
return u'%s follows %s' % (self.follower, self.following)
#in the interpreter
>>> from followers.models import *
>>> john = User.objects.create_user('john', 'lennon#thebeatles.com', 'password')
>>> paul = User.objects.create_user('paul', 'mccartney#thebeatles.com', 'password')
>>> george = User.objects.create_user('george', 'harrison#thebeatles.com', 'password')
>>> ringo = User.objects.create_user('ringo', 'starr#thebeatles.com', 'password')
#the mistake comes from here
>>> john.following.add(Follower(following=paul))
and I get
in add "the object first." % obj
ValueError: instance isn't saved. Use bulk=False or save the object first.`
You should create a Follower object like:
Follower.objects.create(follower=john, following=paul)
You can not add unsaved objects to a one-to-many or many-to-many relation, since at that moment they do not have a primary key yet. Since here your ForeignKeys are non-nullable, you can not first save the Follower object with one of the two relations filled in, and then use .add(..) to add the other end, but that would be more expensive anyway, since it results in two queries.
You can also make Follower objects in bulk like:
Follower.objects.bulk_create([
Follower(follower=john, following=paul),
Follower(follower=john, following=ringo),
Follower(follower=ringo, following=paul),
Follower(follower=george, following=ringo)
])
My scenario is this:
class Partnership(models.Model):
partner_a = models.ForeignKey(
"Person",
on_delete=models.CASCADE,
related_name='%(class)s_partner_a',
)
partner_b = models.ForeignKey(
"Person",
on_delete=models.CASCADE,
related_name='%(class)s_partner_b',
)
class Meta:
unique_together = (partner_a, partner_b)
This works just fine at refusing a duplicate partnership if a=a and b=b:
Ex:
>>> a = Person('a')
>>> b = Person('b')
>>> Partnership.objects.create(person_a=a, person_b=b)
>>> Partnership.objects.create(person_a=a, person_b=b) # IntegretyError as expected
However, it does not correctly refuse the following
>>> a = Person('a')
>>> b = Person('b')
>>> Partnership.objects.create(person_a=a, person_b=b)
>>> Partnership.objects.create(person_a=b, person_b=a) # Allowed
Is there some class Meta I am missing? Or is there another way to ensure this? (I know I can override the save class, but I'm asking if there is a way to do this without doing that).
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
I'm trying to create a recipe/ingredient model in Django
In my models.py I got
class Ingredient(models.Model):
name = models.CharField(max_length=20)
class Recipe(models.Model):
name = models.CharField(max_length=50)
ingredients = models.ManyToManyField(Ingredient, blank=True)
But when I create a Recipe or Ingredient in my admin, I get :
IntegrityError at /admin/menuview/ingredient/add/
menuview_ingredient.recipe_id may not be NULL
What am I doing wrong here?
I think you have to give relationship a null=True parameter too.
ingredients = models.ManyToManyField(Ingredients, blank=True, null=True,)
Your problem is similar to this one: Foreign keys and IntegrityError: id may not be NULL
To fix it, you will do something similar to this when saving:
>>> s = Recipe()
>>> s.name = 'Blah'
>>> obj = Ingredient(...)
>>> obj.save()
>>> s.ingredients = obj
>>> s.save()
The Django Doc has more examples for ManyToManyField. For example, for your case:
>>> i = Ingredient.objects.get(id=1)
>>> e = i.recipe_set.create(
... name ='strawberry pancake',
... )
# No need to call e.save() at this point -- it's already been saved.
This is equivalent to (but much simpler than):
>>> i = Ingredient.objects.get(id=1)
>>> e = Recipe(
... ingredients=i,
... name='strawberry pancacke',
... )
>>> e.save(force_insert=True)