I have two Models, one of them has a ForeignKey to the other, the idea is to save them inside a transaction but it gives me an error.
These are my models:
class Parent(models.Model):
name = models.CharField(...)
...
class Child(models.Model):
parent = models.ForeignKey(Parent)
...
this is my view
#transaction.atomic()
def save_parent(request):
try:
parent = Parent(name=request.POST.get('name'),other_fields).save()
child = Child(parent=parent,other_fields).save()
...
except:
pass
I have looked for transaction savepoints but I dont understand them.
My main goal is to save both or don't save anything
Any Ideas?
You are not saving the objects correctly. Try this
parent = Parent(name=request.POST.get('name'),other_fields)
parent.save()
child = Child(parent=parent,other_fields)
child.save()
Or use the create method inside the manager.
parent = Parent.objects.create(name=request.POST.get('name'),other_fields)
child = Child.objects.create(parent=parent,other_fields)
Related
models.py
class Parent (models.Model):
id = ......
name = ...
address = ...
class Child (models.Model):
id= ...
parent = models.ForeignField(Parent)
Here in this schema, is it possible to bring Parent form inside Child schema to make editable by admin.Tabularline ? I know it is possible to bring Child Schema into parents schema and make editable. But I am looking for vice versa. Is it possible?
I'm not sure this is what you want. But I hope it will help you.
class ChildInline(admin.TabularInline):
model = Child
#admin.register(Parent)
class ParentAdmin(admin.ModelAdmin):
list_display = ['name']
inlines = [ChildInline]
I couldnt find way to inline parent under child model. So, I made custom form where I define fields = 'all' and then it kind of worked for me.
In admin.py
class ChildForm(forms.ModelForm):
class Meta:
model = Child
fields = '__all__'
class ChildAdmin(admin.ModelAdmin):
form = ChildForm
admin.site.register(Child, ChildAdmin)
I have a parent class:
class Parent(models.Model):
field1 = model.CharField()
field2 = model.CharField()
And a child:
class Child1(Parent):
pass
Is there a possible way to create a child object whenever a perent is saved?
The child inherits all the fields from the parent, but, regardless if filled or not, I would need to create a new child object whenever a parent is saved.
Any ideas?
You can use signals or you can override save method of Parent model to do that.
#receiver(models.signals.post_save, sender=Parent)
def post_parent_save(sender, instance, created, *args, **kwargs):
# Create child here
Or,
class Parent(models.Model):
def save(self, *args, **kwargs):
super(Parent, self).save(*args, **kwargs)
# Create child here
In both options, if you want to create a child only when a parent is created (not updated), you need to add extra login. For signals, you can use the created parameter, for overriding save method, you need to check if the model instance has an id field before calling super save method.
I'm wondering if something like this would work for you:
class Child1(Parent):
class Meta:
db_table = 'whateverappparentisin_parent'
managed = False
I'm not sure what Django would do with this, but the idea is that you get a model with the exact same fields, backed by the same database table (so everything else e.g. deletes on Parent would also immediately be "visible" on Child1), without Django wanting to make migrations for it.
But I don't know if it's allowed.
Example situation as follows:
# models.py
class Form(models.Model):
name = models.CharField()
class A(models.Model):
form = models.ForeignKey(Form)
class B(A):
name = models.CharField()
# view.py
form = Form.objects.get(id=1)
form.a_set.all() # works
form.b_set.all() # doesn't work
I would like to access all the related B Objects via the parent class A foreign key but I can't seem to do this. And if I access them via A then I just get the generic parent class query set. Thank you.
When you inherit from a concrete model, there will be two tables (unlike inheriting from an abstract model) for Parent and Child models.
Django will implicitly create a OneToOneField from Child to Parent model named parent_ptr, thus:
B.objects.filter(a_ptr__form=form)
# B.objects.filter(a_ptr__form_id=1)
will give you the desired QuerySet.
This issue was raised several times, though I guess I'm getting it from a different reason, or at least I can't tell how it's related.
Django: 1.10.5, Python: 3.5.2, Postgres: 9.5
So, I have such models (simplified):
class Parent(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
date_created = models.DateTimeField(auto_now=True)
class Child(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
date_created = models.DateTimeField(auto_now=True)
parent = models.ForeignKey(Parent)
def __init__(self, parent, *args, **kwargs):
super(Child, self).__init__(*args, **kwargs)
self.parent = parent
I have a custom queryset:
class ChildQuerySet(models.query.QuerySet):
def find_recent(self):
return self.order_by('-date_created')
Child.objects = ChildQuerySet.as_manager()
Then, I'm trying to test some custom queryset method for child:
class ChildQuerysetDatabaseIntegrationTest(TestCase): # from django.test
default_parent = Parent()
def setUp(self):
super(ChildQuerysetDatabaseIntegrationTest, self).setUp()
self.default_parent.save()
def test_find_recent(self):
# given
for _ in range(1, 10):
child = Child(self.default_parent)
child.save()
# when
recent = Child.objects.find_recent()
ordered = Child.objects.order_by('-date_created')
# then
self.assertEqual(list(ordered), list(recent))
This produces following error on the last line of test (fetching all entities):
ValueError: Cannot assign "UUID('...')": "Child.parent" must be a "Parent" instance.
Usually, when there's some mapping error, the error is thrown during entity saving, but here everything seems to persist successfully, but then fails on retrieval.
The UUID object that is tried to be assigned to parent instance, is actually child's id object, which makes me even more confused.
I tried changing object creation to Parent.objects.create(), but the result didn't change. Calling any function that retrieves a Child object, like ordered.first(), also fails, so I have no clue what's happening.
The problem is your custom constructor for Child. When the ORM is trying to retrieve results, the overridden constructor prevents the ORM from passing in the column values to instantiate the instance properly. In other words, the ORM is trying to pass in the values in the column-specified order, e.g.,
Child(id, date_created, parent)
while the custom constructor expects values to be passed in the following order:
Child(parent, . . .)
To resolve this issue, remove your custom constructor and use
instance = Child(parent=parent)
whenever you want to initialize a child with a parent.
Lets look at the first app (is quite simple)
app name = family; models:
class Parent(models.Model):
name = models.CharFiled(max_length="30")
title = models.CharField(max_length="30")
work_title = models.CharField(max_length="30")
class Child(models.Model):
name = models.CharField(max_length="30")
school_year = models.IntegerField(max_length="30")
Then I have another app that needs to have a foregin key to the 2 classes in family app depending on the user choice, lets look at the next example:
app name=persons, models:
class Info(models.Model):
code = models.CharField(max_length="30")
family_member = models.CharField(max_length="1", choices=(('1', 'Parent'),('2', 'Child'),))
person = models.ForeignKey('family.???') #here is where I have the issue
how can I build the ForeignKey depending on the user choice in family_member? so if the user selects Parent (1) then the ForeignKey should point to Parrent class but if the user selects Child(2) then the foreignKey should point to Child
I'd like to search for solutions in models.py and not fix the issue in views - if possible.
You might want to use GenericForeignKey for that task. See the docs.
You can inherit Parent and Child from one class and make foreign key point to it:
class Person(models.Model):
name = models.CharField(max_length="30")
class Parent(Person):
title = models.CharField(max_length="30")
work_title = models.CharField(max_length="30")
class Child(Person):
school_year = models.IntegerField(max_length="30")
and in persons:
class Info(models.Model):
code = models.CharField(max_length="30")
family_member = models.CharField(max_length="1", choices=(('1', 'Parent'),('2', 'Child'),))
person = models.ForeignKey('family.Person')
Although in this case user will be able to select child or parent independently from family_member choice, unless you filter choices for user by, for example, giving him only Child model objects to choice if he choose family_member 'Child' and vice versa.