How extract individual values from POST request in Django Model Form? - django

Would like to be able to access data in a post request directly as well as processing it in the normal way. First created form:
class TransactionForm(ModelForm):
class Meta:
model = Transaction
fields = ['dish', 'customer', 'grams', 'amount_payable']
('customer' is the pk of another model, Customer.)
Then process form:
#csrf_exempt
def create_transaction(request):
print(request.POST)
user_input = TransactionForm(request.POST)
print (user_input)
if user_input.is_valid():
user_input.save()
#customerobject = Customer.objects.get(pk= PK-TAKEN FROM POST)
#customerobject.account_balance -= (amount_payable TAKEN FROM POST)
#customerobject.save()
return HttpResponse('AOK~')
else:
return HttpResponse(user_input) #'ERROR: transaction not valid~')
Am struggling to correctly formulate the commented lines above. (The rest works fine.)
Would like to be able to extract the value 'customer' from the POST in order to find the customer. Then to extract the value 'amount_payable' from the POST in order to deduct it from the customer's balance.

Eventually stumbled upon the relevant command:
cust = user_input.cleaned_data.get('customer')
customerobject = Customer.objects.get(pk=cust.id)
customerobject.account_balance -= user_input.cleaned_data.get('amount_payable')
customerobject.save()
Low-level languages are easier for sieve-heads like me.

Related

Django query to return percentage of a users with a post

Two models Users (built-in) and Posts:
class Post(models.Model):
post_date = models.DateTimeField(default=timezone.now)
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, related_name='user_post')
post = models.CharField(max_length=100)
I want to have an API endpoint that returns the percentage of users that have posted. Basically I want SUM(unique users who have posted) / total_users
I have been trying to play around with annotate and aggregate, but I am getting the sum of posts for each users, or the sum of users per post (which is one...). How can I get the sum of posts returned with unique users, divide that by user.count and return?
I feel like I am missing something silly but my brain has gone to mush staring at this.
class PostParticipationAPIView(generics.ListAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer
def get_queryset(self):
start_date = self.request.query_params.get('start_date')
end_date = self.request.query_params.get('end_date')
# How can I take something like this, divide it by User.objects.all().count() * 100, and assign it to something to return as the queryset?
queryset = Post.objects.filter(post_date__gte=start_date, post_date__lte=end_date).distinct('user').count()
return queryset
My goal is to end up with the endpoint like:
{
total_participation: 97.3
}
Thanks for any guidance.
BCBB
EDIT
OK, I am still struggling a bit. I tried to create a serializer that just had a decimal field for participation_percentage like:
percentage_participation = serializers.DecimalField(max_digits=5, decimal_places=2, max_value=100, min_value=0)
Then I calculate in the view, but I get an error:
Got AttributeError when attempting to get a value for field percentage_participation on serializer ParticipationSerializer.
The serializer field might be named incorrectly and not match any attribute or key on the str instance.
Original exception text was: 'str' object has no attribute 'percentage_participation'.
Error was the same if I made it a CharField (in case there was some string coercion?).
So then I tried to move it to a Serializer Method and put all the calculation logic in there. This calculated fine, but if I had to provide a query_set in the view. If provided a model object, it just returned the percentage as many times as the query (say Posts.objects.all() had a total of 100 posts, it returned the percentage 100 times).
So then I tried to override the get_queryset in the view, but I HAVE to return something. If I just return { "meh", "hello" } then I return the percentage from the SerializerMethodField one time and the end result is exactly what I want.
I just have no idea as to WHY or how to do this correctly.
Thanks for your help.
EDIT #2
OK so I realized why I was only getting one, it was iterating over the string I returned, which was one character. When I returned "meh" it gave me three of the percentage, iterating over each character in the string...
I am not understanding from playing around, reading the docs, or using GoogleFu how to do this properly. I just want to be able to perform some kind of summary logic on records from the DB - how can I do this properly?!?!
Thank you for all your time.
BCBB
something like this should work
# get total user count
total_users = User.objects.count()
# get unique set of users with post
total_users_who_posted = Post.objects.filter(...).distinct("user").count()
# calculate_percentage
percentage = {
"total_participation": (total_users_who_posted*100)/ total_users
}
# take caution of divion by zero
I don't think it is possible to use djangos orm to do this completely but you can use the orm to get the user counts (with posts and total):
from django.db.models import BooleanField, Case, Count, When, Value
counts = (User
.objects
.annotate(posted=Case(When(user_post__isnull=False,
then=Value(True)),
default=Value(False),
output_field=BooleanField()))
.values('posted')
.aggregate(posted_users=Count('pk', filter=Q(posted=True)),
total_users=Count('pk', filter=Q(posted__isnull=False)))
# This will result in a dict containing the following:
# counts = {'posted_users': ...,
# 'total_users': ....}

Validation of the reference field in mongoengine serializer

I'm using django with mongoengine and mongoengine-rest-framework.
As shown in this article, specifying related_model_validations field in Meta class of a Serializer
class Comment(Document):
post = ReferenceField(Post)
owner = ReferenceField(User)
text = StringField(max_length=140)
isApproved = BooleanField(default=False)
from rest_framework_mongoengine import mongoengine_serializer
class CommentSerializer(MongoEngineModelSerializer):
class Meta:
model = Comment
depth = 1
related_model_validations = {'owner': User, 'post': Post}
exclude = ('isApproved',)
can help to achieve the following result if the document referenced by the ReferenceField is missing:
{
"owner":["User with PK ... does not exist."]
}
So instead of raising a validation exception, json is modified.
However, this article is written for the old version of mongoengine-rest-framework and in the current version there is no field related_model_validations in Serializer Meta class.
So how to achieve the similar result in the current version of the mongoengine-rest-framework?
Sorry for late response, Aleksei.
Currently, if you want to PUT or POST a comment JSON, you just pass existing owner and post as their ids like:
{
post: 2,
user: aleksei.rozhnov#stackoverflow.com,
text: "Contrary to the popular belief, Karl Marx and Friedrich Engels are not a couple, but four different people"
}
So, if you want to update Comment, Post and Author at the same time, I'm afraid, that's not possible.
In GET requests you can get related fields as nested sub-JSONs with non-zero depth argument to Serializer, as you did it in your example.

Multiple Form with Single Submit Button

I'm currently working with django project. I had to filter the data store on the database based on the user input on form (at template) as looked below.
On form user either enter value or leave it blank. So what I have to do is first find the (valid) user input and then fire appropriate query to display data as user input in the form. So final result should be displayed on table at template.
As I'm new to django, how should I have to pass the data and fire query to represent data at multiple field. As help or link related to these type problem are expected. ( I just able to filter from the database with only one form and had no concept to solve this.)
Model of my temp project is as below.
class exReporter(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
email = models.EmailField()
gender = models.CharField(max_length=1)
age = models.IntegerField()
label = models.IntegerField()
There are a number of approaches you can take, but here is one solution you can use that involves chaining together the appropriate filters based on the form's posted data:
*Note: To conform to Python's naming convention, rename exReporter class to ExReporter.
# views.py
def process_ex_reporter_form(request):
if request.method == "POST":
# ExReporterForm implementation details not included.
ex_reporter_form = ExReporterForm(request.POST)
if ex_reporter_form.is_valid():
# If form field has no data, cleaned data should be None.
gender = ex_reporter_form.cleaned_data['gender']
age_start = ex_reporter_form.cleaned_data['age_start']
age_end = ex_reporter_form.cleaned_data['age_end']
aggregation_group = ex_reporter_form.cleaned_data['aggregation_group']
aggregation_id = ex_reporter_form.cleaned_data['aggregation_id']
ex_reporters = ExReporter.objects.get_ex_reporters(gender, age_start,
age_end, aggregation_group, aggregation_id)
else:
# Pass back form for correction.
pass
else:
# Pass new form to user.
pass
# models.py
class ExReporterManager(models.Manager):
def get_ex_reporters(self, gender, age_start, age_end, aggregation_group,
aggregation_id):
ex_reporters = super(ExReporterManager, self).get_query_set().all()
# Even though the filters are being applied in separate statements,
# database will only be hit once.
if ex_reporters:
if gender:
ex_reporters = ex_reporters.filter(gender=gender)
if age_start:
ex_reporters = ex_reporters.filter(age__gt=age_start)
if age_end:
ex_reporters = ex_reporters.filter(age__lt=age_end)
# Apply further filter logic for aggregation types supported.
return ex_reporters

django nested foreignkey set query

I wanted to filter on the _set of an item, however in the problem below while i was doing this, it wasn't on the field i thought it was. I needed to use rating__rating to get the rating column of the rating table in the post table.
in django, i have this:
class Story(models.Model):
user = models.ForeignKey(User)
...
class Post(models.Model):
post = models.TextField(max_length=345)
story = models.ForeignKey(Story)
...
class Rating(models.Model)
rating = models.IntegerField()
post = models.ForeignKey(Post)
and then i can find all the ratings for a given post that are have a set value:
def getPostsForStory(id):
return arrangeCountOfRatings(Post.objects.filter(story=id))
def arrangeCountOfRatings(postList):
for post in postList:
post.rateA = post.rating_set.filter(rating=rateA).count()
return postList
but how do i do this from a given story? That is, say i wanted to apply the above process of getting the counts for each post, but given a Story object?
def getStoryItemsForUser(request):
return arrangeCountOfItems(Story.objects.filter(user=request.user.id)
def arrangeCountOfItems(storyList):
for story in storyList:
story.rateA = story.post_set.filter(rating=rateA).count()
return storyList
doesn't get me what i want (the counts are all wrong - either zero of, if there are posts with ratings, 1
EDIT:
ah. The problem is thus:
story.rateA = story.post_set.filter(rating=rateA).count()
does not search for what i wanted - it is searching effectively on rating__id instead of rating__rating
so i just changed it to read rating__rating, simple.
What about:
story.rateA = Rating.objects.filter(rating=ratingA, post__story=story).count()
EDIT: The same is valid for post ratings(and equivalent to your code):
post.rateA = Rating.objects.filter(rating=ratingA, post=post).count()
Counting ratings for the specified post/story.

Django select choices with optgroup fails to validate

I have a a form in Django with two inline forms. One of them is giving me grief.
My model is like so.
class BookingActivity(models.Model):
booking = models.ForeignKey('Booking')
program = models.ForeignKey(Program)
activity = models.ForeignKey(Activity, choices=programs_as_optgroups())
the activity ForeignKey choices are generated via this method:
def programs_as_optgroups():
activities = []
programs = []
for program in Program.objects.all():
new_program = []
new_activities = []
for activity in Activity.objects.filter(program=program):
new_activities.append([activity.id, activity.name])
new_program = [program.name, new_activities]
activities.append(new_program)
return activities
I'm trying to add <optgroup> tags to my ForeignKey select which is working. But when I submit the form I get an error: Cannot assign "u'3'": "BookingActivity.activity" must be a "Activity" instance.
This makes some sense - sort of. But if I check the request data sent from the form post. With choices either setup or not I get the same values, i.e.
activity = models.ForeignKey(Activity, choices=programs_as_optgroups())
and
activity = models.ForeignKey(Activity)
both return the a u'3' from the form. But I can't figure out why I get an error only when I'm using the optgroups.
I'm guessing you're trying
http://dealingit.wordpress.com/2009/10/26/django-tip-showing-optgroup-in-a-modelform/
in the blog
sub_categories.append([sub_category.id, sub_category.name])
you have
new_activities.append([activity.id, activity])
I think you're assuming you will get an object when it actually is a string you're getting back.