As I've understood the deal, the standard way of extending the User Django model is by implementing profiles.
This suits me wonderfully, since I have 3 types of profiles (3 different Model subclasses) all based upon the User model for uniqueness and authentication.
I'm having trouble deciding, however, on the best way of implementing a user creation form. Should I...
Use mixins: inherit a ModelForm with model=User and one with model=Profile, manually overriding save() and clean() to call the bases' methods and perform the foreign key assignment.
Use composition: inherit Form and manually instantiate and manage two ModelForms.
Instantiate the forms separately, and save() them in a manually ordered fashion.
The Best Way I Didn't Think Of.
I would appreciate a (however minimal) implementation so I can be sure I'm making the right calls.
Thanks in advance.
You can write a single form that acts as a combined ModelForm for both your Profile model and the contrib User model. To accomplish this, a little manipulation of the forms kwargs on init is required. See this snippet: http://djangosnippets.org/snippets/2081/
Related
I've been searching a way to reproduce admin-actions behavior on my own tables using django-tables2. I haven't found any module to introduce this functionality to a ListView to derive from it and looking at ModelAdmin I see there are many methods implied on this.
Of course, I can add a form around my table to get the checkboxes and a submit button pointing to a view that works with the ids but I'm looging to get a combo to choose among different actions as in django-admin but also to have that 'actions' meta option to list some methods as the possible actions to perform.
I found django-actions which is still very young but also it introduces it's own page for operations and I just need to integrate functionality on my own model so I can connect some input type=select with the model actions.
Any comment is appreciated :)
There is no built-in solution for it. You have to implement your actions in your views and the functionality to your templates.
Add, edit and delete operations are very easy to implement in your views.py. This depends on your models, but you can trigger database manipulations from within your templates and keep the logic in your views.py.
You can also easily add a form to your templates as it is described in the docs:
# forms.py
from django.forms import ModelForm
from myapp.models import Article
# Create the form class.
class ArticleForm(ModelForm):
class Meta:
model = Article
fields = ['pub_date', 'headline', 'content', 'reporter']
model := Choose your model which you want to modify / add
fields := Select some fields from your model, which you want to show up in your form
This defines a form corresponding to your model, which can be used in your templates to modify or add an entity to your database.
I have several models with one-to-one relation. For example
class Task(models.Model):
initial_comment = models.OneToOneField('Comment')
# A pack of other fields
class Comment(models.Model)
body = RichTextField()
# A pack of other fields
I want to create "create view" based on form, that gives user ability to create task and initial comment there.
I can't use CreateView because it is based on only one model
I can't use ModelForm because it is based on only one model
I can create several forms, but I can't join them into one formset (forms are different)
I feel "inlineformset_factory" (InlineFormSet) should be used here, but I am not sure it suits best. Is there any 3rd party Django app to do that?
Sure I can create form myself, but I do not want to copy/paste all fields, their types, localized labels, validations and so on. I just want to list their names (like fields attibute).
I can also have 2 forms and support them everywhere and track dependencies manually (save comments first), like in How can create a model form in django with a one-to-one relation with another model , but I hope there has to be better solution.
If you wonder why do I need one-to-one: Comments are used heavily in other places and have different relations with different models.
The inline_formset factory is correct. There are no standard generic views for this, but there is a third party package with generic views to do what you are wanting. Its in the standard Django way of doing things.
https://github.com/AndrewIngram/django-extra-views
You probably want to use the CreateWithInlinesView for that.
Well, I found solution.
CreateWithInlinesView works perfectly with OneToOneField (after all, 1-to-1 is just a foreign key with constraint), but my main model here is Comment, not Task. So I should set Comment as model field in this view and Task as inline. It looks silly. I will create custom form or review my model structure.
I know how to make custom user models, my question is about style and best practices.
What are the consequences of custom user model in Django? Is it really better to use auxiliary one-to-one model?
And for example if I have a UserProfile models which is one-to-one to User, should I create friends relationship (which would be only specific to my app) between UserProfile or between User?
Also all 3rd-party packages rely on get_user_model(), so looks like if I don't use custom user model, all your relations should go to User, right? But I still can't add methods to User, so if User has friends relation, and I want to add recent_friends method, I should add this method to UserProfile. This looks a bit inconsistent for me.
I'd be glad if someone experienced in Django could give a clear insight.
Also all 3rd-party packages rely on get_user_model(), so looks like if I don't use custom user model, all your relations should go to User, right? But I still can't add methods to User, so if User has friends relation, and I want to add recent_friends method, I should add this method to UserProfile.
I have gone down the "one-to-one" route in the past and I ended up not liking the design of my app at all, it seems to me that it forces you away from SOLID. So if I was you I would rather subclass AbstractBaseUser or AbstractUser.
With AbstractBaseUser you are provided just the core implementation of User and then you can extend the model according to your requirements.
Depending on what sort of 3rd-party packages you are using you might need more than just the core implementation: if that's the case just extend AbstractUser which lets you extend the complete implementation of User.
I would definitely recommend using a custom user model - even if you use a one-to-one with a profile. It is incredibly hard to migrate to a custom user model if you've committed to the default user model, and there's almost always a point where you want to add at least some custom logic to the user model.
Whether you use a profile or further extend the user model should then be based on all considerations that usually apply to your database structure. The rightâ„¢ decision depends on the exact details of your profile, which only you know.
For example, I want a page, which will let user add data for different categories of goods.
Like:
Model: Category is foreign key of item
Category1(detail url):
Item 1(detail url):
Date(textbox), Amount(textbox), Price(textbox)
Item 2:
...
Category2:
...
Save button, add more button, etc...
Since this is an example, I what those thing all display in a page.
I don't mind hard writing them with normal functions, but I wonder if I can utilize the views, since if they are so heavily introduced and developed, they might be powerful. So why not utilize it?
Can anyone tell me tricks about how to use them or we shouldn't use them if we want more functionality?
Django's generic views cover a lot of common use cases. For example:
CreateView - a view for creating an instance of a model
UpdateView - a view for updating an existing instance of a model
DeleteView - a view for deleting an existing instance of a model
DetailView - a view for displaying the details of an exsting instance of a model
ListView - a view for displaying a list of instances of a model
There are more around if you need them, and they cover the majority of views you are likely to need. You can also extend them to meet your needs quite easily. As a general rule of thumb, they make such a huge difference to how quickly you can get something built that I would recommend using them by default, and only switching over to writing your own views when absolutely necessary. If you haven't yet learned them, I think doing so will be a very good investment of your time - you will make up the time spent very quickly. For a lot of view types, it's just a case of specifying the model, setting up the URLs and the template, and you're done.
If you need to pass through additional data, then you can extend the generic view in question and override the get_context_data() method. If the same needs to be applied to several different generic views, you can create a mixin that includes that method and include it in that generic view.
For views that include forms, like the CreateView and UpdateView, as Drewness said, you can pass through a ModelForm instance to tell it what form to use, and that form can itself be overriden, so you still have a lot of control over what the form will do. For instance, you might define the following form:
from django.forms import ModelForm
class CategoryForm(ModelForm):
exclude = ['date_created']
And the following view
from django.views.generic.edit import CreateView
class CategoryCreateView(CreateView):
model = Category
form_class = CategoryForm
The Django tutorial covers generic views pretty well.
You can use Django's ModelForm with a FormView.
Then all of the fields in your model will be available in your form and in your form view. You should also look at mixins. Mixins allow you to use combinations of class-based views.
Finally, if you want to use more than one form (model) in a view you can use a FormSet.
I am trying to understand why, when adding a custom Admin site for a django app, one needs to add both the model and the admin function. Say, you have an application called Story, and thus the admin site will be called StoryAdmin. When registering this on the django administration interface, you need to add this line:
# Registering all the changes to admin.site
admin.site.register(Story, StoryAdmin)
My question is, is there a way to just do this:
admin.site.register(StoryAdmin)
Adding only one thing, not two, because this makes things simpler, and there is a smaller chance for an error, and the code just looks less redundant. It would make things look much better, because in the end, you could have a clean list of all the admin panels:
admin.site.register(
StoryAdmin,
SomeAdmin,
FooAdmin,
)
That's not how admin.site.register is built. It expects a Model and then optionally the ModelAdmin with which to display that Model:
def register(self, model_or_iterable, admin_class=None, **options):
"""
Registers the given model(s) with the given admin class.
The model(s) should be Model classes, not instances.
If an admin class isn't given, it will use ModelAdmin (the default
admin options). If keyword arguments are given -- e.g., list_display --
they'll be applied as options to the admin class.
If a model is already registered, this will raise AlreadyRegistered.
If a model is abstract, this will raise ImproperlyConfigured.
"""
This allows you to use the same ModelAdmin on multiple Models (which can be desirable when, for example, you subclass a model off the same abstract Model).
It doesn't suit your style but it's just one of those things you just have to accept and get on with.
That's a good question, it could have been designed that way, but that's not the case.
I asume the main reason is to allow the admin class to be optional and use the default base ModelAdmin class for simple cases and to allow to use the same ModelAdmin subclass with many models, see implementation at: https://github.com/django/django/blob/master/django/contrib/admin/sites.py#L52-101
Also you don't need to define the class yourself if you need to customize a ModelAdmin, you can just pass kwargs to the register function:
admin.site.register(Story, list_display=['field1', 'field2'])
So that's my bet, they try to minimize the boilerplate when registering a model and allow it to be more flexible.