Editing of django form with primary key fields - django

I have a django model form for which I allowed partial form save since its a long form. Now I want the user to come back and complete the form later.
There is one hindrance however that my database cannot accept duplicate entries with same primary key. So should I remove primary key in my database to solve this or is there another way to make it possible? Suggestions please.

Why not keep only one row per user for that form? Just add one boolean field to check whether the form is submitted or is a draft. Something like is_submitted=models.Boolean(default=False). Keep updating the row with the new values on each partial save (a separate button for Save or an AJAX call for auto save).
When the form is submitted, just mark the field is_submitted = True and perform whatever actions you want after that.

Related

django view filter ManyToMany field to guard view

I have a tag model, with ManyToMany field "parents" to tag model, to itself. There is also "allowed_users" field.
I need to guard a view in such a way, that the user won't see any tags in parents field, to which he is not allowed.
I try to modify queryset, removing the corresponding tags from parents. But when I change the instance, tag_instance.parents.set(my_new_list) it gets saved automatically so I'm altering the database and changing the real value of the instance.
So the general question is "how to guard my view in such a way, that object's ManyToMany field is filtered by custom logic".
Another question is "how to set manytomany field without altering database", as this would be a solution to the former one.
yes I use DRF
You can use the Prefetch object to filter related table when SQL queries are executed.
For instance:
Tag.objects.preftech_related(Prefetch("parents", queryset=Tag.objects.filter(allowed_users=current_user).distinct()))
This will prefetch "parents" (meaning no additionnal sql query will run when accessing my_tag.parent.all()) and filter parents to keep only those with the current user in allowed_user
Note: Tag.objects.filter(allowed_users=current_user) will duplicate tag entries for each user in allowed_user, ence the .distinct() to keep one of each

Django: order formset without form change

I have a form with only one field (name of family members).
class FamilyMemeberItem(forms.Form):
name= forms.CharField(label=_('name'), max_length=20)
Now I want my form be sorted (arbitrary order) defined by the user. For example in a family, I want to show A first, then B and then C, while the creation sequence may be C, B and A. Is there anyway to do that?
I searched and realized I should add an order field to my form and override the __iter__() method. Is that the only way? If there is no way to do that without change in form?
And could anyone please tell me about the field can_order of formset_factory? When I add it, an extra filed is loaded next to my form, and that's and integer presenting the number of that field. Can I change and save that so that the order changes?
I answered a similar question you posted.
I'll just repeat the last part here:
If you want to store the order in the database, you need to define a new field in you model and store the order in that. The order of formsets is only present inside a single request/response, after that its gone.

Change one django form field value relative to another

Let say I have two fields in a django form country and state.I want the values of state to relatively change with the values of country.i.e. I want the state field to list out the states of the country that user has selected. Also the state field should be empty during form initiation.I know that this can be done using java script and other scripts.But,I would like to know if there are any conventional methods exists in django to do the same.???
Sounds like you need to create a model for Country and State.
State model should have a foreign key linking to Country. This means many states can be related to one country. Then, populate the tables with all countries and states you want.
In your form, you can override the 'init' method with custom behavior. So, if you have declared a field 'state' then you can do something like self.fields['state'].choices = State.object.filter(country_id=some_country_id). This assumes you have some_country_id already and you can pass this through as a kwarg during instantiation.

django form with multiple choice field with potentially infinite choices

I have a model with a many-to-many field that will expand as the user adds more entries for the model. In the form template if I use the conventional {{ form.field }} I get a multiple choice select as is expected, but the problem that will quickly become apparent is when there are 10, 100, 1000 or more choices. What I'd like to provide in the form is a search field where the user can search through all available entries and via AJAX return entries matching their search criteria where they can then select the individual entry choices to be saved in the database.
I'm assuming I will have to manually render the multiple choice form field, but after hours of research I cannot find an example of this anywhere online. Is there an example that exists and I just haven't been able to find? How is one supposed to manually create a form with a multiple choice field in Django? Or am I going about this all wrong?

Django formset - show extra fields only when no initial data set?

I have a page that displays multiple Formsets, each of which has a prefix. The formsets are created using formset_factory the default options, including extra=1. Rows can be added or deleted with JavaScript.
If the user is adding new data, one blank row shows up. Perfect.
If the user has added data but form validation failed, in which case the formset is populated with POST data using MyFormset(data, prefix='o1-formsetname') etc., only the data that they have entered shows up. Again, perfect. (the o1 etc. are dynamically generated, each o corresponds to an "option", and each "option" may have multiple formsets).
However if the user is editing existing data, in which case the view populates the formset using MyFormset(initial=somedata, prefix='o1-formsetname') where somedata is a list of dicts of data that came from a model in the database, an extra blank row is inserted after this data. I don't want a blank row to appear unless the user explicitly adds one using the JavaScript.
Is there any simple way to prevent the formset from showing an extra row if the initial data is set? The reason I'm using initial in the third example is that if I just passed the data in using MyFormset(somedata, prefix='o1-formsetname') I'd have to do an extra step of reformatting all the data into a POSTdata style dict including prefixes for each field, for example o1-formsetname-1-price: x etc., as well as calculating the management form data, which adds a whole load of complication.
One solution could be to intercept the formset before it's sent to the template and manually remove the row, but the extra_forms attribute doesn't seem to be writeable and setting extra to 0 doesn't make any difference. I could also have the JavaScript detect this case and remove the row. However I can't help but think I'm missing something obvious since the behaviour I want is what would seem to be sensible expected behaviour to me.
Thanks.
Use the max_num keyword argument to formset_factory:
MyFormset = formset_factory([...], extra=1, max_num=1)
For more details, check out limiting the maximum number of forms.
One hitch: presumably you want to be able to process more than one blank form. This isn't too hard; just make sure that you don't use the max_num keyword argument in the POST processing side.
I've come up with a solution that works with Django 1.1. I created a subclass of BaseFormSet that overrides the total_form_count method such that, if initial forms exist, the total does not include extra forms. Bit of a hack perhaps, and maybe there's a better solution that I couldn't find, but it works.
class SensibleFormset(BaseFormSet):
def total_form_count(self):
"""Returns the total number of forms in this FormSet."""
if self.data or self.files:
return self.management_form.cleaned_data[TOTAL_FORM_COUNT]
else:
if self.initial_form_count() > 0:
total_forms = self.initial_form_count()
else:
total_forms = self.initial_form_count() + self.extra
if total_forms > self.max_num > 0:
total_forms = self.max_num
return total_forms