Showing inline admin form for GenericForeignKey relationships in django - django

my models.py
class PagePlaceholder(models.Model):
content_type = models.ForeignKey()
object_id = models.PositiveIntegerField()
display_content = generic.GenericForeignKey('content_type', 'object_id')
class Page(models.Model):
page_name = models.CharField(max_length=1000,default="sample_page")
placeholder = models.ManyToManyField('PagePlaceholder')
the placeholder can refer to any of 4 classes by the generic foreign key relationship.
page has a many2many relationship to placeholder to say that a page can contains a bunch of different models.
and my admin.py for the same.
class PagePlaceholderAdmin(admin.ModelAdmin):
pass
class PageInline(GenericStackedInline):
model = PagePlaceholder
class PageAdmin(admin.ModelAdmin):
inlines = [PageInline,]
now what i want is in the page admin view, to show the form for editing the pageplaceholder's display content object. trying to get that inline gives me an error saying that object is not a class.
is there a decent solution for this with the admin.py or is it necessary for me to create a new form and view to display these model forms properly?

Related

How to avoid fields that has null values automatically when rendering html

I want to not to display the null value fields in template.So How can i achieve this in django?Is there any functions available to do this.
In you used Django ModeForm then do this
class ProductForm(forms.ModelForm):
class Meta:
model = ProductModel
exclude = ('selling_price','discounted_price') # this is exclude fields not render in html template
NOTE:- pass null=True, blank=True in Model
If what you are saying is that you do not want a field that has been set to null = True in your models.py to be rendered in your html template, you can use django inbulit form class to render the form and exclude whatever field is null
Here is an example of what i am saying.
class Userdetail(forms.ModelForm):
class Meta:
model = User_detail
exclude = ("name_of_null_field",) #This field won't be rendered in your html template because it is excluded.
You can read more on Django forms here Working with forms

Customizing Django GenericRelation content_type values in Admin add/change view

My models are using GenericForeignKey and GenericRelations. For simplification my models structure is following:
class BaseModel(models.Model):
name = models.CharField(max_length=100)
model_labels = models.GenericRelation('ModelLabel', related_query_name='%(class)s')
model_types = models.GenericRelation('ModelType'), related_query_name='%(class)s')
class Meta:
abstract = True
class ModelA(BaseModel):
fieldA = models.CharField(max_length = 50)
class ModelB(BaseModel):
fieldB = models.CharField(max_length = 50)
class ModelLabel(models.Model);
label = models.CharField(max_length = 50)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
model_object = GenericForeignKey('content_type', 'object_id')
class ModelType(models.Model):
type = models.CharField(max_length = 50)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
model_object = GenericForeignKey('content_type', 'object_id')
class Unrelated(models.Model):
name = models.CharField(max_lenght = 50)
The problem I am facing is in admin view for ModelLabel and ModelType. Right now, out-of-the-box I am getting 3 fields: Label or Type, Content type and Object id. Yes, this is correct according to the model.
But in Content type I am getting not only ModelA and ModelB as an options. I'm also getting Unrelated and most of the individual fields of different models. According to documentation:
Instances of ContentType represent and store information about the
models installed in your project, and new instances of ContentType are
automatically created whenever new models are installed.
According to this Unrelated can appear in the values, but models' fields shouldn't. So why they appear?
However, this is not the main problem I am struggling with. I'd like to narrow the list of options to choose from in Content type just to ModelA and ModelB. From what I gathered since this is ForeignKey under the hood I should be able to go with ModelChoiceField, but I would need to make it use some hardcoded QuerySet but I cannot find how to make it e.g. from dictionary. Similar goes with Object id, where I'd like to be able to select what value I want to use based on available numbers.
So far I realized that most likely I need to extend admin.ModelAdmin view and most likely also create custom form (extend forms.ModelForm). This is also theory because so far I couldn't figure a way to get mentioned custom QuerySet or Object id. Also there is some drawback of this approach, because if I'll choose to go with this, I'll need to have custom form for every model (ModelLabel, ModelType) - is this really necessary?
I know of a way to add GenericInlineModelAdmin class, but this view allows to add object of type ModelLabel together with ModelB. This doesn't cover case where object of type ModelB already exists.
To summarize what are main goals I want to achieve:
Fix Admin view to create ModelLabel and ModelType
Narrow list of options for Content type field to ModelA and ModelB
Allow user to choose only existing IDs for Object id field

Django inline formset multiple models

TL;DR: I need a some kind of formset for formsets.
I have two different models related to one buisness-entity, and I need to make a form to edit both models like a one form. And I need to create a lot of such forms on the one page like Django inline formset does.
Now I have the following thing:
class Parent(models.Model):
name = models.Charfield()
class FirstChild(models.Model):
name = models.Charfield()
e_id = models.IntegerField()
parent = models.ForeignKey(Parent)
class FirstChildForm(django.forms.ModelForm):
class Meta:
model = Child
fields = ('name', 'e_id', 'parent')
widgets = {'parent': forms.TextInput}
And I render a lot of them using inline formsets:
formset_class = inlineformset_factory(Parent, FirstChild,
form=FirstChildForm, extra=1)
But now I have to add second child model and a form for it, and still render it like an one inline form, but make it form actually edit two models. Like this:
class SecondChild(models.Model):
name = models.Charfield()
e_id = models.IntegerField()
parent = models.ForeignKey(Parent)
class SecondChildForm(django.forms.ModelForm):
class Meta:
model = Child
fields = ('name', 'e_id', 'parent')
widgets = {'parent': forms.TextInput}
formset_class = inlineformset_factory(models=[Parent, FirstChild],
forms=[FirstChildForm, SecondChildForm],
extra=1)
As far as I understand, Django formsets cannot work with multiple models right now.
So which way should I choose to implement this behaviour and do not broke all django conceptions?, I cannot use some extra libraries so I have to implement everything by myself and I use django 1.6 if it is important.
So, finally I used this approach as a base: https://micropyramid.com/blog/how-to-use-nested-formsets-in-django/

How to add\get data in admin via reversed relation using GenericTabularInline?

I can add Criterias to a place. How can I add Places to a criteria?
Models:
class Criterias(models.Model):
name = ...
class Places(models.Model):
name = ...
class PlacesToCriterias(models.Model):
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey()
criteria_group = models.ForeignKey(Criterias)
Admin - PLACES part:
class PlaceCriteriasInlineAdmin(GenericTabularInline):
model = PlacesToCriterias
class PlacesAdmin(admin.ModelAdmin):
inlines = [PlaceCriteriasInlineAdmin]
admin.site.register(Places, PlacesAdmin)
In this case, when I open Places admin change page, I can add Criterias items to my 'place'.
Admin - CRITERIAS part:
class CriteriaPlacesInlineAdmin(GenericTabularInline):
model = PlacesToCriterias
class CriteriasAdmin(admin.ModelAdmin):
inlines = [CriteriaPlacesInlineAdmin]
admin.site.register(Criterias, CriteriasAdmin)
In this case, when I open Criterias admin change page, I CAN NOT add Places item to my 'criteria', because instead of possible places I see criterias.
How to get Places items at Criterias admin page?
It was quite easy. GenericTabularInline must be changed to admin.TabularInline
class CriteriaPlacesInlineAdmin(admin.TabularInline):
model = PlacesToCriterias
class CriteriasAdmin(admin.ModelAdmin):
inlines = [CriteriaPlacesInlineAdmin]
admin.site.register(Criterias, CriteriasAdmin)
If anyone needs to get dropdown list with selected object, instead of content_type and object_id fields, the solution is here.

Howto define a formset in django (like multiple inline)

For couple days I am trying to do multiple inline models in django. (inline inside inline)
But I couldnt. Then I decided to define a formset while editing base model (Page in example below), So one can also add new link when adding a new page(in admin page).
Like page->linksection->link. Here is the model.
#model.py
class Page(models.Model):
title = models.CharField(max_length=255)
class LinkSection(models.Model):
page = models.ForeignKey(Page)
title = models.CharField(max_length=255)
class Link(models.Model):
linksection = models.ForeignKey(LinkSection)
text = models.CharField(max_length=255)
url = models.URLField()
#admin.py
class LinkSectionInline(admin.TabularInline):
form = LinkSectionForm + LinkForm
Can you please show me how to define a formset for this model?
Thank you very much.