How to create separate form widgets for ModelMultipleChoiceField in Django - django

I have a ManyToMany relationship between two Django Models: Team and Member. A single Member can be part of multiple teams. I am able to successfully bind a Form class to a CreateView, and, using the standard ModelMultipleChoiceField,can successfully save the Form using the save_m2m method.
However, the default widget for the field is not suitable for my user experience. Instead of using a picklist, I would like to create a separate select box for each number of selectable Members per team. For example, if the Team can have 7 Members, I would like to show 7 select boxes, rather than one pick list that a user selects 7 different objects from.
I understand I may not get a complete answer, but would appreciate any pointers on if I should be looking into overriding the Field with a custom MultiWidget, or if using an inline formset might be a more appropriate route. Or, something else...

At the end of the day, I ultimately decided to stick with a single ModelForm for the Create Team form. Within this ModelForm, I dynamically create the number of fields I will need for the number of Member per team, and have created a function within the form that yields those fields.
I perform validation on those fields within the generic clean method of the ModelForm. I use the yield method within the Template to control displaying the individual fields.
I am sure it is not the most Django-y approach, as many people seem to use inlineformsets in theory, but this worked and the code does not seem overly hacky or unmaintainable.

Related

Django accessing fields which are NOT part of a form

I need some clarification as to what the best practice is regarding this. So, say you have a Django form which has many fields that the user can fill out. Say you also have corresponding fields in the models file, but the models file contains some extra fields that the user cannot modify, e.g. unique reference number. Say also, you want to access these hidden fields in the views so that you can present this reference number to the user.
What's the best way of accessing these "hidden" fields that are created when a valid form is submitted? I was thinking of grabbing the latest entry by date, though if there's concurrent requests at the same time, the wrong data may be pulled?
Try using Django's HiddenInput widget. This will allow you to associate data with a form without allowing the user to modify it.

implementing multiple profiles with django-all-auth

Django noob here - I was recently pointed to django-all-auth for registering/handling users, which I'm finding awesome in its near instant setup.
However I'm stumbling at trying to implement multiple user profile models. In reading other answers I've found this to be the closest answer thus far, but not really what I need.
When coding my own basic registration the user would select an account type (basic, pro, elite for example - each being their own profile model). Depending on the link selected the signup form would display both the generic User registration form as well as the profile form of the type chosen by the user.
I know I can go so far as to completely customize all-auth and make something like this work, but I'm hoping to be pointed in a direction that involves less wrecking of the original app. I've thought about having user redirected after signup to choose a profile type, but that seems to be a lot of extra steps.
Thanks for the help!
To extend the basic user class, just subclass AbstractUser. You can find that in the docs. With this you can add the fields your basic user is missing.
Now, you want several types of profiles with different fields, or perhaps the same fields but adding new fields every time.
You can create something like:
class ProfileBase(models.Model):
user=models.OneToOneField(User)
class ProfilePro(ProfileBase):
pro_field=models.SomeField(Foo)
#You can extend ProfilePro here if you want it to include the pro_field
class ProfileElite(ProfileBase):
elite_field=models.someField(Bar)
Once you have these models creating the forms should be easy.
Be aware, when you subclass this way django creates 1 table per model, including on the subclass table only the new fields. This makes necessary a join per level of inheritance so try not to abuse that.
There is a second way to use inheritance:
class ProfileBase(models.Model):
user=models.OneToOneField(User)
class Meta:
abstract=True
If you define the base class as abstract you won't have a table for it, so you can't create objects for that model, but each of your subclasses will be on it's own table. If you do it this way you may need extra logic to handle cases when user changes of type of profile (i.e. went from pro to elite).
To keep this separated from django-allauth, just finish the registration (create a form and in your settings define ACCOUNT_SIGNUP_FORM_CLASS to override all-auth default with your basic info + pick a profile type form) and once your user is logged in, redirect them to their profile to finish the process.

Implement a typeahead for manytomany field

I am looking for a robust solution to implement a typeahead (Twitter typeahead) for a manytomany field. Basically, something identical to the tag input field here in StackOverflow.
The default widget for manytomany is a multiselect. However, since I want the user to provide new values, I need to use a inputText widget. My question is, what would be the best way to implement this functionality so that I can later pass an array of models instances to a cleaning stage?
In my cleaning stage I plan on doing a loop through the elements to check if they exist in the db, create them if they don't and apply validators to each elements.
My initial intuition was to use a hidden field that would receive the actual fields from the typeahead via javascript manipulation. Thus the input field would not be part of the model, just serve as an input box for the user.
Why reinvent the wheel. You can simply use django-taggit together with selectize.js. By using both of them, you don't even need any customization.

Django Model field as formfield in templates

I guess this is a simple question, but I am not being able to find a definitive answer whether this is possible or not.
I have a Model object that is being passed to my template during rendering. While I use most of the Model fields to show their values, I came across a need to show a few of them as formfields (with their respective HTML element like rendered via ModelForms). Can ModelForm class usage be avoided here and simply use the Model's field to be rendered as formfield directly from template?
an example:
class MyModel(models.Model):
month = models.PositiveIntegerField(_('Month'), choices=MONTH_CHOICES)
year = models.PositiveIntegerField(_('Year'))
Now in template based on the above Model example I want to show the year as a value but month as a dropdown with selected current value?
Any pointer appreciated!
Use case:
Imagine a generic list_view like case where you are rendering a queryset. What you have there is object per iteration, however on the list view you want to allow your users to perform some quick editing of few object attributes to avoid forcing them to go to full edit mode (maybe via simple ajax).
No.
As canvassed in the comments, this is not possible. A model, and its fields do not know about forms - that is what forms, and modelforms are for.
The right way to do this is to wrap your model objects with a modelform, which you can adjust (using inheritance) to do whatever you want with the non-form fields, if you wish to make this more transparent.
Creating modelforms in the template means that you have nowhere to process the forms in django. Apparently you want to interface them with some kind of ajax interface, so perhaps this is not a problem for you, but in any case, I fail to see how it would be easier than simply creating the modelforms in the view.

How can I use django forms/models to represent choices between fields?

How can I use boolean choices in a model field to enable/disable other fields. If a boolean value is true/false I want it to enable/disable other model fields. Is there a way to natively express these relationships using django models/forms/widgets? I keep writing custom templates to model these relationships, but can't figure out a good way to represent them in django without a special template.
For example:
class PointInTime(models.Model):
is_absolute_time = models.BooleanField()
absolute_time = models.DateTimeField()
is_relative_time = models.BooleanField()
days_before = models.IntegerField()
So if the is_absolute_time is True, I want the absolute_time entry to be editable in the GUI and the days_before entry to be grayed out and not-editable. If the 'is_relative_time' flag is True, I want the absolute_time entry to be grayed out, and the days_before value to be editable. So is_absolute_time and is_relative_time would be radio buttons in the same Group in the GUI and their two corresponding fields would only be editable when their radio button is selected. This is easy to do in a customized template, but is there a way to use a model/form in django to natively show this relationship?
It would be helpful to clarify what you mean by "natively show this relationship," and think clearly about separation of concerns.
If all you want is to "gray out" or disable a certain field based on the value of another field, this is purely a presentation/UI issue, so the template (and/or Javascript) is the appropriate place to handle it.
If you want to validate that the submitted data is internally consistent (i.e. absolute_time is filled in if is_absolute_time is True, etc), that's a form-validation issue. The place for that logic is in the clean() method of your Form or ModelForm object.
If you want to ensure that no PointInTime model can ever be saved to the database without being internally consistent, that's a data-layer concern. The place for that is in a custom save() method on your model object (Django 1.2 will include a more extensive model validation system).
All of those options involve writing imperative code to do what you need with these specific fields. It may be that you're looking for a way to represent the situation declaratively in your model so that the code in all three of the above cases can be written generically instead of specifically. There's no built-in Django way to do this, but you could certainly do something like:
class PointInTime(models.Model):
field_dependencies = {'is_absolute_time': 'absolute_time',
'is_relative_time': 'days_before'}
... fields here ...
Then your model save() code (or your Form clean() code, or your template), could use this dictionary to determine which fields should be enabled/disabled depending on the value of which other one. This generalization is hardly worth the effort, though, unless you anticipate needing to do this same thing in a number of different models.
Lastly, a few schema design alternatives you may want to consider to get your data layer better normalized:
If there are only two valid states (absolute and relative), use a single boolean field instead of two. Then you avoid possible inconsistencies (what does it mean if both booleans are False? Or True?)
Or simplify further by eliminating the booleans entirely and just using Null values in one or the other of absolute_time/days_before.
If there might be more than two valid states, use a single IntegerField or CharField with choices instead of using two boolean fields. Same reason as above, but can accomodate more than two options.
Since a RelativeTime and an AbsoluteTime don't appear to share any data fields with each other, consider splitting them out into separate models entirely. If you have other models that need a ForeignKey to either one or the other, you could model that with inheritance (both RelativeTime and AbsoluteTime inherit from PointInTime, other models have ForeignKeys to PointInTime).
I'm not entirely sure what you're doing with these objects but whichever the user chooses, you're pointing to a single moment in time. "5 days ago" is "Thursday" and vice-versa.
So unless the dates roll with the site (eg the record with "5 days ago" will still mean Thursday, tomorrow, etc), surely this is only an interface problem? If that's the case, I'd stick with a single value for the date in your Model and let the form and view do all the work.
That solves the auto-generated Admin side of things as you'll just have one field to contend with but it won't natively give you the choice between the two unless you write your own form widget and override the ModelAdmin class for your Model.
If this isn't the case, please ignore this answer.