Creating a form inheriting the "forms.ModelForm" class:
number = forms.ModelChoiceField(queryset=Number.objects.order_by('?')[:6], empty_label=None)
The result is a Choice form is created, and random numbers limited to 6 entries will appear. But data indicating the limit is not accepted.
if you make the code like this without a limit:
number = forms.ModelChoiceField(queryset=Number.objects.order_by('?'), empty_label=None)
Then all records appear in the form, and the form is validated everything is fine.
P.S
SELECT "number"."number" FROM "number" ORDER BY RAND() ASC LIMIT 6
When requesting a limit, the log shows that it works perfectly with LIMIT
I need help please
For some reason, the form makes 2 requests to the database, and validation fails because the server has a set of the 1st request and the client is rendered from the 2nd request.
Solved the issue by using the object call function.
Related
#action(detail=False, methods=["get"])
def home_list(self, request):
data = extra_models.objects.order_by("?")
print(data)
paginator = self.paginator
results = paginator.paginate_queryset(data, request)
serializer = self.get_serializer(results, many=True)
return self.get_paginated_response(serializer.data)
What I want to do is, I want the data of extra_models (objects) to come out randomly without duplication every time the home_list API is called.
However, I want to come out randomly but cut it out in 10 units. (settings.py pagination option applied)
The current problem is that the first 10 appear randomly, but when the next 10 appear, the first ones are also mixed.
In other words, data is being duplicated.
Duplicates do not occur within the same page.
If you move to the next page, data from the previous page is mixed.
Even if you try print(data) or print(serializer.data) in the middle, duplicate data is not delivered.
However, data duplication occurs from /home_list?page=2 when calling the actual API.
Which part should I check?
You should expect this behaviour when you're dealing with .order_by("?").
Whenever a request hits in server's end, Django shuffles the objects and also Django doesn't preserve the previous request or page
You are doing nothing wrong here, The only reason why this is happening is because of order_by("?"). The API is stateless which means on the second API call when you call for Page=2 then it does not know which data is sent for page=1 and returns random data for page=2.
The only solution is to order your data by ASC or DESC
I'm working with a survey app, so I need to save all the answers a user gives in the database. The way I'm doing it is this:
for key, value in request.POST.items():
if key != 'csrfmiddlewaretoken': # I don't want to save the token info
item = Item.objects.get(pk=key) # I get the question(item) I want to save
if item == None:
return render(request, "survey/error.html")
Answer.objects.create(item= item, answer=value, user = request.user)
Taking into account that django by default closes connections to the database (i.e. does not use persistent connections). My question is:
In case the dictionary has for example the answer to 60 questions (so it will iterate 60 times), would it open and close the connections 60 times, or does it only do it once?
Is there a better way to save POST information manually? (without using django forms, since for various reasons I currently need to do it manually)
This definitely is not a good way to store Answers in bulk, since:
you each time fetch the Item object for every single question;
your code does not handle the case correctly where an item is missing: in that case it will raise an exception, and the Django middleware will (likely) render a 500 page; and
it will make several calls to create all these objects.
We can create objects in bulk to reduce the number of queries. Typically we will create all elements with a single query, although depending on the database and the amount of data, it might take a limited number of queries.
We furtermore do not need to fetch the related Item objects, at all, we can just set the item_id field instead, the "twin" of the item ForeignKey field, like:
from django.db import IntegrityError
try:
answers = [
Answer(item_id=key, answer=value, user=request.user)
for key, value in request.POST.items()
if key != 'csrfmiddlewaretoken'
]
Answer.objects.bulk_create(answers)
except IntegrityError:
return render(request, 'survey/error.html')
The bulk_create will thus insert all the objects in a small number of queries and thus significantly reduce the time of the request.
Note however that bulk_create has some limitations (listed on the documentation page). It might be useful to read those carefully and take them into account. Although I think in the given case, these are not relevant, it is always better to know the limitations of the tools you are using.
I have Two views--one part of the admin site, and the other a publicly accessible view.
They both perform the same set of queries--literally copy and pasted code.
masterQuery = myObject.objects.filter(is_public=True)
newQuery = queriedForms.filter(ref_to_parent_form__record_reference__form_name__icontains=term['TVAL'], ref_to_parent_form__record_reference_type__pk=rtypePK)
newQuery = newQuery.filter(flagged_for_deletion=False)
term['count'] = newQuery.count()
masterQuery = (newQuery & masterQuery)
singleQueryStats['intersections'] = masterQuery.count()
Each view has this exact same code--it's not the prettiest query--but regardless: On the admin view--this runs in less than like a 1/4 second. On the public Views.py view--it takes 8 minutes. I cannot figure out why. The queryset.query output is the same. The variables(admin submitted through POST/Public submitted through GET) also match.
EDITS: I tried simplifying things further to no avail:
SELECT `maqluengine_form`.`id`, `maqluengine_form`.`form_name`, `maqluengine_form`.`form_number`, `maqluengine_form`.`form_geojson_string`, `maqluengine_form`.`hierarchy_parent_id`, `maqluengine_form`.`is_public`, `maqluengine_form`.`project_id`, `maqluengine_form`.`date_created`, `maqluengine_form`.`created_by_id`, `maqluengine_form`.`date_last_modified`, `maqluengine_form`.`modified_by_id`, `maqluengine_form`.`sort_index`, `maqluengine_form`.`form_type_id`, `maqluengine_form`.`flagged_for_deletion` FROM `maqluengine_form` WHERE (`maqluengine_form`.`form_type_id` = 319 AND `maqluengine_form`.`flagged_for_deletion` = False)
this is the query output on both views--the admin view takes <1/4 second and the public view takes about 4-8 minutes depending to perform a count() operation on this queryset
There is no logic that could be changing the time--the timer server error log prints match up until the count is performed.
Neither queryset is evaluated before the count--just built. Still at an utter loss here.
I was being an idiot--the two querysets weren't the same--there was an additional booleanfield being hit, and I was reading the logs wrong--The answer is that the querysets WERE NOT the same--so that answers this.
I submitted a new question to figure out the drastic speed difference between the two.
I have the model stock.production.lot. I added to this model two one2many fields, incoming_moves and outgoing_moves, both of them pointing to model stock.move. I have also added a float field named qty on stock.move.
And I added two computed fields in stock.production.lot which calculate the incoming and the outgoing quantity.
Now, I want to forbid lots whose outgoing quantity is higher than the incoming one. For this, I have made a constraint in stock.move. I know the most reasonable option would be make this constraint in stock.production.lot, but the problem I see is that in #api.constrains decorator I cannot use dot notation, so I can only write #api.constrains('incoming_moves', 'outgoing_moves'), and this means that if I modify the quantity of a move, this constraint is not even being executed.
So my constraint in stock.move is:
#api.one
#api.constrains('qty', 'restrict_lot_id')
def _check_qties(self):
if (self.in_vqty - self.out_vqty) < 0:
raise ValidationError(
_('The incoming quantity (Kg) of the lot is lower than '
'the outgoing one.')
)
It seems to work great in any case, except for the following one: if I modify the quantity of several moves of the same lot at the same time (from the one2many field of the lot form), the ORM write method behaviour makes the constraint raise the error inspite of the quantities are OK.
Example
I have a lot which an incoming move (InM1) of 8 and three outgoing
moves (OutM1, OutM2, OutM3) of 1, 3 and 4 (lot quantity => 8 - (1+3+4) = 0, it is OK). I go to the form of this
lot and edit the one2many of outgoing_moves. From there, I set OutM1
to 2 and OutM3 to 3, so the total quantity of the lot will be 8 -
(2+3+3), which is 0 and is OK too. But, when I click on Save button, the
constraint raises the error. Why?
This is what is happening: after clicking on Save, ORM write
method of stock.move is called. First time, it wants to update
OutM1, and it does it, but just after that, the constraint is checked
and as OutM3 has not been updated yet, it receives 8 - (2+3+4), and
that is the reason of the error raising.
So I tried to remove the constraint and do the check inside ORM write method, but I face the same problem. I put my checks after the super, but the ORM write method is called twice, the first time to update OutM1 and the second one to update OutM3. Between those actions the exception is raised too, due to the same reason I explained above.
How could I solve this?
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