Django: how to write models.py
In application i have Post model. In admin panel i want to have only one entry - "Posts" with one link to add Post. In list of Posts in admin i want to see all of them.
All posts have it's title, content and other basic fields.
But:
Due to Post Source, posts may have different fields.
Sources:
--- First
--- Second
--- Third
--- ......
For example, Post with first Source must have Poll (but has no category). Post with second Source must belong to category in Category branch #1 (but has no Poll). Post with third source may have Image field (but no category and no poll) and so on.
Category branch #1
--- cb1_first
--- cb1_second
--- cb1_third
Category branch #....
--- cb2_first
--- cb2_second
--- cb2_third
So, in Post add-page i want to write title, content, other basic thin开发者_如何学Cgs, than i select Source and due to choice other fields appears (for first source it is Poll, for second - list of categories in Category branch #1 and so on).
If i make base class Post, and then extend it with other classes, i'll get extra tables in SQL and many items in application admin (i.e. add Basic Post, add Video Post, add Post with poll, add Post with category branch #2...)
Asking for advice, how to organize such application.
This is a reason why I'm a strong opponent to doing validation at the database level with things like null=False. Make a single Post
model with all the fields that any type of post can have, but don't enforce the requirements on the model (blank=True, null=True
).
Then, instead, validate that one field or another is required, etc. on your forms, specifically ModelForms when dealing with the Admin.
If a certain field is required in one instance, you can enforce that using:
class MyModelForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(MyModelForm, self).__init__(*args, **kwargs)
if self.instance.source == 'first':
self.fields['poll'].required = True
Then, for showing only the actual fields that should be shown based on the source, you can either work up a bit of JavaScript for that, or you can actually explicitly exclude them from the admin with ModelAdmin.get_fieldsets()
. Basically the process is thus:
class MyModelAdmin(admin.ModelAdmin):
...
fieldsets = (
(None, { 'fields': ('common_field_1', 'common_field_2', 'common_field_3',),
)
poll_fieldsets = (
(None, { 'fields': ('common_field_1', 'common_field_2', 'common_field_3', 'poll',),
)
def get_fieldsets(self, request, obj=None):
if obj and obj.source == 'first':
return self.poll_fieldsets
else:
return super(MyModelAdmin, self).get_fieldsets(request=request, obj=obj)
First create a model with whatever the basic fields you require for a post(say Post
model). Then you can create a model for sources - Source
model. Post
model should have a foreign key representing the source with which it was created. The Source
model should contain a field to store the name of a model to instantiate in order to store additional fields of the posts with the given source. Then create the all the models for each additional field sets you require, Each should have a foreign key field with the Post
model. For example you can create a Poll
model with a foreign key to Post
.
After modeling the data like this you can just refer to Source
model to resolve all the field types when creating posts as well as retrieving them.
精彩评论