I have a base model and 2 child models inheriting from base model
class Module(models.Model):
name = models.CharField(max_length=200, null=False)
def __str__(self):
return self.name
class A(Module):
title = models.CharField(max_length=300, null=False, verbose_name='Title')
image = models.FileField(upload_to='uploads/', null=True)
class B(Module):
title = models.CharField(max_length=300, null=False, verbose_name='Title')
sub_title = models.CharField(max_length=300, null=False, verbose_name='Title')
image = models.FileField(upload_to='uploads/', null=True)
This is working fine, Django creates table inside child model table that references to parent.
Now, where I struggle is that there is an additional app with its own model that needs to query related parent model with its all child models. Lets assume this is my app referencing to module class
class Page(models.Model):
title = models.CharField(max_length=300, null=False)
slug = models.SlugField(max_length=300, null=False, db_index = True)
modules = models.ManyToManyField('modules.module')
By this current setup, Django stores parent model id in child model table, I'm not using django on client side hence in my sql query I'd like to get the child module attached to parent, by having a reference to what child model is referencing to. Please have in mind, Parent is linked to only one model.
I've looked at abstract, proxy models as well as model_utils.managers InheritenceManager but none stored child model information in parent.
How do I achieve that?
Thanks
The relationship is already defined by the ManyToManyField. Being able to display it is perhaps the question you're getting at.
You can reference the "through" model and register it in Admin like so:
from django.contrib import admin
# https://docs.djangoproject.com/en/3.0/ref/contrib/admin/#inlinemodeladmin-objects
#
# You can use TabularInline, or StackedInline --- whichever meets your style preferences
#
class PageModuleInline(admin.TabularInline):
model = Page.modules.through # the implicit "join table" model
class PageAdmin(admin.ModelAdmin):
inlines = [
PageModuleInline,
]
class ModuleAdmin(admin.ModelAdmin):
inlines = [
PageModuleInline,
]
see: https://docs.djangoproject.com/en/3.0/ref/contrib/admin/#working-with-many-to-many-models
Related
I have a model with an attribute that is connected to another model as follow:
class Book(models.Model):
synced = models.OneToOneField('SyncedBook'
related_name='internal',
on_delete=models.CASCADE)
# some more attributes here...
#property
def book_address(self)
return self.synced.book_address
However, the book_address is a also a FK in the SyncedBook table as follow:
book_address = models.ForeignKey('Address', db_index=True, null=True, blank=True,
related_name='address_book', on_delete=models.PROTECT)
I don't know and understand how to be able to edit the book_address through the Django admin page in class BookingAdmin(admin.ModelAdmin), even though I have read over the documentation. At first I have the attribute as readonly, but now I want to be able to edit it and save the new address from the Address table. Is there a way to make it happen through the class BookingAdmin(admin.ModelAdmin) and how? Any example and solution would be appreciate
Model properties are typically used for presenting logically defined data for a particular model instance and not necessarily storing data on the model instance itself.
An example of when to use a model property is as follows:
# Defines a product instance
class Product(model.Models):
name = models.CharField(max_length=100)
description = models.TextField()
active = models.BooleanField(default=True)
cost = models.DecimalField(max_digits=5, decimal_places=2)
price = models.DecimalField(max_digits=5, decimal_places=2)
# calculate profits on product
#property
def profit(self)
p = self.price - self.cost
return p
In your case, you are trying to actually be able to modify data against a related model instance within the django admin. To me this sounds like more specifically an Inline (click here for documentation)
So in your case, you would need to create something like the following to your admin.py file:
class SyncedBookInline(admin.TabularInline):
model = BookInline
#admin.Register(Book)
class BookAdmin(admin.ModelAdmin):
# all your model admin settings
inlines = [SyncedBookInline]
Additional Info:
The Inline solution should still work for you. Please see the working code listed below:
models.py:
from django.db import models
class Hero(models.Model):
name = models.CharField(max_length=50)
class HeroAcquaintance(models.Model):
name = models.CharField(max_length=50)
hero = models.OneToOneField(Hero, on_delete=models.CASCADE)
admin.py:
from django.contrib import admin
from .models import *
class HeroAcquaintanceInline(admin.TabularInline):
model = HeroAcquaintance
#admin.register(Hero)
class HeroAdmin(admin.ModelAdmin):
list_display = (
'name',
)
inlines = [HeroAcquaintanceInline]
#admin.register(HeroAcquaintance)
class HeroAcquaintanceAdmin(admin.ModelAdmin):
list_display = (
'name',
)
Screenshot:
How to get fields from child model in views.py? For example, I've parent model BasicOrder and child model (who extends BasicOrder) TouristVisa.
I'm using Django 2.0.2 and Python 3.6.1. My models.py is:
class BasicOrder(models.Model):
user = models.ForeignKey(User, verbose_name=_('User'), on_delete=models.CASCADE)
status = models.PositiveIntegerField(_('Status'), choices=ORDER_STATUS, default=0)
def __str__(self):
return 'Order #{}'.format(self.id)
class TouristVisa(BasicOrder, models.Model):
citizenship = models.ForeignKey(
Citizenship, verbose_name=_('Citizenship'), on_delete=models.PROTECT
)
invitation_entry = models.PositiveSmallIntegerField(
_('Invitation entry'), choices=INVITATION_ENTRY
)
class Meta:
ordering = ['id']
Would be great to have access to field invitation_entry from child model (TouristVisa). I try this way in views.py:
order = BasicOrder.objects.get(user=request.user.id)
print(order.invitation_entry)
But it's show error:
AttributeError: 'BasicOrder' object has no attribute 'invitation_entry'
It's wrong, when TouristVisa inherits from BasicOrder it means it gets the fields user ans status as well, not the other way around. So, you can access the invitation_entry field but calling TouristVisa also because it's the only model where it exists.
Now, access to it like this:
order = BasicOrder.objects.get(user=request.user.id)
print(order.touristvisa.invitation_entry)
I have an abstract model that all my other models inherit from, it looks like this.
class SupremeModel(models.Model):
creator = models.ForeignKey(User, related_name="%(class)s_creator")
created = models.DateTimeField(null=True, blank=True)
deleted = models.BooleanField(default=False)
modified = models.DateTimeField(null=True,blank=True)
class Meta:
abstract = True
I then have a bunch of other models that inherit from this model, with something along these lines...
class ExampleModel(SupremeModel):
name = models.TextField(null=False, blank=False)
description = models.TextField(null=False, blank=False)
class AnotherModel(SupremeModel):
title = models.TextField(null=False, blank=False)
location = models.TextField(null=False, blank=False)
I want to create a Django model form for nearly all of my custom models that look similar to ExampleModel, but I always want the fields in SupremeModel to be excluded in the form...
How can I create a ModelForm that can be used to inherit the exclude parameters that will hide creator,created,deleted, and modified but show all of the other fields (in this case name and description or title and location).
you may try this
class ExcludedModelForm(ModelForm):
class Meta:
exclude = ['creator', 'created', 'deleted', 'modified']
class ExampleModelForm(ExcludedModelForm):
class Meta(ExcludedModelForm.Meta):
model = ExampleModel
I am trying to create the following models. There is a ManyToMany relation from Entry to AUTH_USER_MODEL via the EntryLike intermediate model.
class BaseType(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
creation_time = models.DateTimeField(auto_now_add=True)
last_update_time = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
class Title(BaseType):
text = models.CharField(max_length=100)
description = models.TextField()
class EntryLike(BaseType):
entry = models.ForeignKey(Entry)
user = models.ForeignKey(settings.AUTH_USER_MODEL)
class Entry(BaseType):
title = models.ForeignKey(Title, on_delete=models.PROTECT)
text = models.TextField()
user = models.ForeignKey(settings.AUTH_USER_MODEL)
liked_by_users = models.ManyToManyField(settings.AUTH_USER_MODEL, through='EntryLike', through_fields=('entry', 'user'))
Running migrations on the above model scheme throws the error: AttributeError:'str' object has no attribute 'meta'.
Any help in resolving this error would be highly appreciated. Am new to Django & Python, but not to Web Development.
The issue is that settings.AUTH_USER_MODEL is almost certainly not a model instance. It's probably a string that constrains the choices another model can make - settings would be a strange place to leave a model definition.
To do a MTM between the user model and your field above you need need to do:
from django.contrib.auth.models import User
class Entry(BaseType):
title = models.ForeignKey(Title, on_delete=models.PROTECT)
text = models.TextField()
user = models.ForeignKey(User)
def __str__(self):
return self.title
I've added the str function so that it gives a more sensible return when you're manipulating it in admin/shell.
I'd also question whether you need the second set of fields (removed here), as you can use select related between the Entry and EntryLike join table, without any duplication of the fields - you can probably go that way, it's just a bit unnecessary.
Lastly, I'd note that the way I'm using it above just uses the default User object that comes with Django - you may wish to customise it. or extend the base class as you've done here with your own models' base class.
(All of this is predicated on AUTH_USER_MODEL not being a model instance - if it is, can you post the model definition from settings.py? )
I'm having trouble overriding the formset on a TabularInline inline of a ModelAdmin object in my admin site. I know you're supposed to have a model associated with a TabularInline object, but I'm not sure how to specify this on the form object used to generate the formset. With the code below, I'm getting "'AppAssetInline.formset' does not inherit from BaseModelFormSet."
class AppAssetForm(forms.ModelForm):
model = App.assets.through
primary = forms.BooleanField()
uuid = forms.CharField()
class AppAssetInline(admin.TabularInline):
model = App.assets.through
AssetFormset = formset_factory(AppAssetForm)
formset = AssetFormset
class AppAdmin(admin.ModelAdmin):
inlines = [AppAssetInline,]
The answer to my question didn't have to do with how I was structuring my forms, but rather how I was joining fields on my models. I had the following structure in my models:
class App(models.Model):
package = models.FileField(upload_to=settings.APP_PACKAGE_ROOT)
assets = models.ManyToManyField('AppAsset', blank=True, null=True)
download_count = models.IntegerField(default=0)
class AppAsset(models.Model):
def __unicode__(self):
return self.asset_file.name
notes = models.CharField(max_length=255, null=True, blank=True)
type = models.CharField(max_length=255, null=True, blank=True)
asset_file = models.FileField(upload_to=settings.APP_PACKAGE_ROOT)
What I did was change the structure such that AppAsset now has a foreign key on App for its assets. After that, I could use the TabularInline on the AppAsset model with no problems. Here are the latest source files:
https://github.com/ridecharge/spout/blob/master/Spout/AppDistribution/models.py
https://github.com/ridecharge/spout/blob/master/Spout/AppDistribution/admin.py
You should use django.forms.models.inlineformset_factory instead of formset_factory