I would like to get num of habitlog by owner. so, coding api
this is my models.py
#Models.py
class MakingHabit(SoftDeleteModelMixin, TimestampMixin):
owner = models.ForeignKey(
User, on_delete=models.CASCADE, related_name="making_habits"
)
title = models.CharField(_("title"), max_length=255)
method = models.CharField(_("method for recording"), max_length=255)
class HabitLog(SoftDeleteModelMixin, TimestampMixin):
habit = models.ForeignKey(
MakingHabit, on_delete=models.CASCADE, related_name="logs"
)
date = models.DateField(default=date.today)
image = models.FileField(_("evidence image"), null=True, blank=True)
this is viewsets.py
#action(methods=["GET"], detail=False, url_path="habitrank", url_name="habitrank")
def habitrank(self, request, *args, **kwargs):
logs = HabitLog.objects.values('habit__owner').annotate(habit_count=Count('date'))
for log in logs:
print(log)
this print
enter image description here
it's not working what i want.
so, I coding different
#action(methods=["GET"], detail=False, url_path="habitrank", url_name="habitrank")
def habitrank(self, request, *args, **kwargs):
logs = HabitLog.objects.values('date').annotate(habit_count=Count('habit__owner'))
for log in logs:
print(log)
it work what i want
this print
enter image description here
why the first query not working?
Related
I have an exam model that whenever an instance is created, instances of the Question model to the number that is specified in the Exam are created(using post_save signal). Also, I have a Go code that whenever a request is sent, fills out 3 fields of the Question model. My problem is how can I send this request in the signal part.
The codes are as followed:
models.py:
class Exam(models.Model):
title = models.CharField(max_length=255)
subject = models.CharField(max_length=255, default='')
organizer = models.CharField(max_length=255, default='...')
description = models.TextField(max_length=1000)
created_at = models.DateTimeField(auto_now_add=True)
duration = models.DurationField()
number_of_questions = models.PositiveSmallIntegerField()
order = models.IntegerField(default=0)
def __str__(self):
return self.title
class ExamQuestion(models.Model):
exam = models.ForeignKey('ExamApply', on_delete=models.CASCADE)
question_template = models.ForeignKey(QuestionTemplate, on_delete=models.CASCADE)
text = models.TextField(max_length=5000, null=True, blank=True)
question_params = models.JSONField(null=True, blank=True)
answer_choices = models.JSONField(null=True, blank=True)
answer_given = models.JSONField(default=dict, null=True, blank=True)
correct_answer = models.JSONField(null=True, blank=True)
data = models.JSONField(null=True, blank=True)
is_correct = models.BooleanField(null=True)
order = models.IntegerField(null=True, blank=True)
def __str__(self):
return str(self.id)
class ExamApply(models.Model):
class Status(models.TextChoices):
CREATED = 'CR', 'Created'
STARTED = 'ST', 'Started'
FINISHED = 'FN', 'Finished'
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
exam = models.ForeignKey(Exam, on_delete=models.CASCADE)
start_date = models.DateTimeField()
end_date = models.DateTimeField()
status = models.CharField(max_length=2, choices=Status.choices, default=Status.CREATED)
def get_score(self):
score = ExamQuestion.objects.filter(exam=self, answer_given=F('correct_answer')).count()
return score
signals.py:
#receiver(post_save, sender=ExamApply)
def create_examapply_examquestion(sender, instance, created, **kwargs):
if created:
for _ in range(instance.exam.number_of_questions):
ExamQuestion.objects.create(exam=instance)
id = ExamQuestion.objects.all().last().id
return redirect('/question/' + str(id) + '/') #doesnt work
#receiver(post_save, sender=ExamApply)
def save_examapply_examquestion(sender, instance, created, **kwargs):
instance.exam.save()
urls.py related to the part I want:
urlpatterns = [
path('questions/<int:pk>/', UpdateQuestionAPI.as_view()),
]
views.py:
class UpdateQuestionAPI(generics.RetrieveUpdateDestroyAPIView):
queryset = ExamQuestion.objects.all()
serializer_class = IntegrateQuestionSerializer
lookup_field = 'pk'
def get(self, request, *args, **kwargs):
question = ExamQuestion.objects.filter(pk=kwargs['pk'])
serializer = ExamQuestionSerializer(question, many=True)
return Response(serializer.data)
def update(self, request, *args, **kwargs):
instance = self.get_object()
serializer = self.get_serializer(instance, data=request.data, partial=True)
if serializer.is_valid():
serializer.save()
return Response({"message": "updated successfully"})
else:
return Response({"message": "failed", "details": serializer.errors})
serializers.py:
class IntegrateQuestionSerializer(serializers.ModelSerializer):
class Meta:
model = ExamQuestion
fields = ['question_params', 'answer_choices', 'correct_answer',]
class ExamQuestionSerializer(serializers.ModelSerializer):
title = serializers.SerializerMethodField()
class Meta:
model = ExamQuestion
fields = ['title']
def get_title(self, obj):
return obj.exam.exam.title
I had the idea of using redirect(to the update view), but it doesn't work.
First of all, it makes no sense to use request in the signal part.
This code is related to the model and the orm and is not responsible of the request part. That's the view work.
The signal you are using is related to the creation of the ExamApply model. The view you posted doesn't create a ExamApply so it will not get called at all.
Just so you know, usually signals are avoided because they lead to complicated code. To quote the documentation “Signals give the appearance of loose coupling, but they can quickly lead to code that is hard to understand, adjust and debug. Where possible you should opt for directly calling the handling code, rather than dispatching via a signal.”
Here you have multiple issues in your signals, you have a return in a loop, that will stop the loop after the first iteration. Then you return an HttpResponse (in the form of redirect) but you are not in a view so it doesn't make sense.
It's not clear what you want to do because the view and the serializer you posted are not related to the creation of ExamApply as I understand it what you could do (one of):
Override the save method of ExamApply to create the questions.
Or handle the creation of questions in the view that create the ExamApply
For example:
def save(self, *args, **kwargs):
if not self.pk:
# not self.pk means a creation.
for _ in range(self.exam.number_of_questions):
question = ExamQuestion.objects.create(exam=self.exam)
# You might want to link question to user / exam apply here?
self.exam.question_set.add(question)
super().save(*args, **kwargs)
In your ExamApply creation view or serializer you might want to return the questions id, if you use DRF it's trivial to do so: https://www.django-rest-framework.org/api-guide/relations/#primarykeyrelatedfield
But you might want to link questions to ExamApply and/or user and not just Exam.
On a side note, for the future, if you need the created object id you should use
question = ExamQuestion.objects.create(exam=instance)
question.id
I am working on a project. I have Django for my backend and Vue for my front end. When using the templates and saving in the Django project I have no issues.
However, when I POST to my projects API the following save from my modal is not being created.
models.py
class DevProjects(models.Model):
PROJECT_TYPE = [
('New Application', 'New Application'),
('Update Application', 'Update Application'),
('Bug Fixes', 'Bug Fixes')
]
PROJECT_STATUS = [
('New', 'New'),
('In Progress', 'In Progress'),
('Complete', 'Complete'),
]
project_id = models.CharField(max_length=15, editable=False, unique=True)
project_title = models.CharField(max_length=100)
project_desc = models.CharField(max_length=500)
project_category = models.CharField(max_length=25, choices=PROJECT_TYPE, null=True, blank=True)
project_status = models.CharField(max_length=25, choices=PROJECT_STATUS, default='New')
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateField(auto_now=True)
created_by = models.ForeignKey(User, related_name='projects', on_delete=models.CASCADE)
def save(self, *args, **kwargs):
super(DevProjects, self).save(**kwargs)
self.project_id = 'PROJ-' + str(self.id)
super(DevProjects, self).save(**kwargs)
def __str__(self):
return self.project_title
I have the project_id being created on save which gets the original ID but just adds 'PROJ-' in front. Whenever I submit the form from my frontend, that save definition is not being called, thus not creating the project_id.
Project ID is what I use to send a GET request to get the projects.
serailizers.py
class DevProjectSerializer(serializers.ModelSerializer):
class Meta:
model = DevProjects
fields = ("project_id", "project_title", "project_desc", "project_category", "project_status")
views.py
class DevProjectViewSet(viewsets.ModelViewSet):
serializer_class = DevProjectSerializer
queryset = DevProjects.objects.all()
def perform_create(self, serializer):
serializer.save(created_by=self.request.user)
Whenever I post, I get the following error:
IntegrityError: UNIQUE constraint failed: ckcSupportWeb_devprojects.project_id
What do I need to do for the project_id to generate when POSTing from DRF? Any and all help is appreciated.
UPDATE
I can try to use the following code in my viewset:
def create(self, *args, **kwargs):
self.project_id = 'PROJ-' + str(self.id)
super(DevProjectViewSet, self).save(**kwargs)
But, I get the following error:
self.project_id = 'PROJ-' + str(self.id)
AttributeError: 'DevProjectViewSet' object has no attribute 'id'
I am truly stuck on how to handle this for API post requests.
From what I can understand, you can relax the unique constraint on the project_id and your previous code should work fine.
Since the project code is not editable, it won't be updated from a POST API call.
I was able to get rid of all of these issues with writing a simple function in utils.py that gets the latest ID created, adds 1 and then sets the new project_id.
Try with this code snippet
def save(self, *args, **kwargs)
self.project_id = 'PROJ-' + str(self.id)
super(DevProjects, self).save(**kwargs)
i'm sending notifications to a user via django notifications. And i have username regex working on the html so anyone comments with #username it will post and the html is linkable so click on the #username it will take him to the username profile page. Now i am using django signals to match the username and print out the username. but when i use notify to send the notification. it does not work.
models.py:
class Comment(models.Model):
post = models.ForeignKey(post, on_delete=models.CASCADE, related_name='comments')
user = models.ForeignKey(User, on_delete=models.CASCADE)
reply = models.ForeignKey('Comment', null=True, related_name='replies', on_delete=models.CASCADE)
content = models.TextField()
image = models.ImageField(upload_to='comments-pics', null=True, blank=True)
voice_record = models.FileField(upload_to='voice-comments', null=True, blank=True)
timestamp = models.DateTimeField(auto_now_add=True)
def __str__ (self):
return '{}.{}'.format(self.post.title, str(self.user.username))
def save(self, *args, **kwargs):
super(Comment, self).save(*args, **kwargs)
def Comment_save_receiver(sender, instance, created, *args,**kwargs):
if created and not instance.parent:
user_regex = r'#(?P<username>[\w.#+-]+)'
m = re.search(user_regex, instance.content)
if m:
try:
recipient = User.objects.get(username=m.group('username'))
except (User.DoesNotExist, User.MultipleObjectsReturned):
pass
else:
notify.send(instance.user, recipient=recipient, actor=instance.user, verb='mention you in a post', target=instance, nf_type='tagged_by_one_user')
post_save.connect(Comment_save_receiver, sender=post)
the problem has been solved. i did wrong with the signal portion. it will be:
def comment_save_receiver(sender, instance, created, *args,**kwargs):
if created:
user_regex = r'#(?P<username>[\w.#+-]+)'
m = re.search(user_regex, instance.content)
if m:
try:
recipient = User.objects.get(username=m.group('username'))
except (User.DoesNotExist, User.MultipleObjectsReturned):
pass
else:
notify.send(instance.user, recipient=recipient, actor=instance.user, verb='mention you in a post', target=instance.post, nf_type='tagged_by_one_user')
post_save.connect(comment_save_receiver, sender=Comment)
I am trying to save a form which have ForeignKey (purchaseContractID).Here is my contract Model
class contracts(models.Model):
productDetailID=models.ForeignKey('Inventory.productDetails',related_name='+',on_delete=models.CASCADE,verbose_name='Select Product',default=None)
supplierID=models.ForeignKey(suppliers,on_delete=models.CASCADE,verbose_name='Select Supplier',default=None)
totalUnits=models.IntegerField(verbose_name='Total Units',editable=False,default=None)
ratePerUnit=models.IntegerField(verbose_name='Rate Per Unit',default=None)
saleTax=models.IntegerField(verbose_name='Sale Tax',default=None)
incomeTax=models.IntegerField(verbose_name='Income Tax',default=None)
saleTaxwithHeld=models.IntegerField(verbose_name='Sale Tax with Held',default=None)
startDate=models.DateField(verbose_name='Start Date',default=None)
endDate=models.DateField(verbose_name='End Date',default=None)
manulContractNumber=models.IntegerField(verbose_name='Manul Contract Number',default=None)
paymentDays=models.IntegerField(verbose_name='Payment Days',default=None)
remarks=models.CharField(verbose_name='Remarks',max_length=100,default=None)
dateOfEntry=models.DateField(editable=False,default=datetime.now())
def __str__(self):
return str(self.productDetailID.name)
here is my inventoryIn Model which foreignKey of PurchaseContract
class inventoryIn(models.Model):
supplierID=models.ForeignKey('Purchase.suppliers',editable=False,on_delete=models.CASCADE,verbose_name='Supplier')
productID=models.ForeignKey(products,editable=False,on_delete=models.CASCADE)
purchaseContractID=models.ForeignKey('Purchase.contracts',on_delete=models.CASCADE,verbose_name='Contract ID')
unitsIn=models.IntegerField(verbose_name='Enter No of Bags')
MYCHOCIES = (('orginal', 'ORGINAL'), ('dummy', 'DUMMY'))
doType = models.CharField(blank=True, choices=MYCHOCIES, verbose_name='Select DO Type', max_length=20)
doID=models.IntegerField(verbose_name='Do No')
doImage=models.ImageField(upload_to='doImage/%Y/%m/%d',verbose_name='Do Image')
invoiceID=models.IntegerField(verbose_name='Invoice No')
invoiceImage=models.ImageField(upload_to='inventoryIn/%Y/%m/%d')
agingDate=models.DateField(verbose_name='Receiving Date')
labReportImage = models.ImageField(upload_to='labReportImage/%Y/%m/%d', blank=True,verbose_name='Lab Report Image')
enterPaymentDays = models.IntegerField(verbose_name='Enter Payment Days', blank=True, default=None)
dateOfEntry=models.DateField(default=datetime.now())
def __str__(self):
return self.supplierID
here is my admin.py where i am adding admin form and also adding a js that add some fields dynamical.
class inventoryInAdmin(admin.ModelAdmin):
fields = ['purchaseContractID','unitsIn','doType','doID','doImage','invoiceID','invoiceImage','agingDate','labReportImage','enterPaymentDays']
class Media:
js = ('js/addInventory.js',)
admin.site.register(inventoryIn,inventoryInAdmin)
it is not allowing me to submit form and giving me error "Select a valid choice. That choice is not one of the available choices."
I have resolved this issue by adding the save method at InventoryIn Model.
class inventoryIn(models.Model):
supplierID=models.ForeignKey('Purchase.suppliers',editable=False,on_delete=models.CASCADE,verbose_name='Supplier')
productID=models.ForeignKey(products,editable=False,on_delete=models.CASCADE)
purchaseContractID=models.ForeignKey('Purchase.contracts',on_delete=models.CASCADE,verbose_name='Contract ID')
unitsIn=models.IntegerField(verbose_name='Enter No of Bags')
MYCHOCIES = (('orginal', 'ORGINAL'), ('dummy', 'DUMMY'))
doType = models.CharField(blank=True, choices=MYCHOCIES, verbose_name='Select DO Type', max_length=20)
doID=models.IntegerField(verbose_name='Do No')
doImage=models.ImageField(upload_to='doImage/%Y/%m/%d',verbose_name='Do Image')
invoiceID=models.IntegerField(verbose_name='Invoice No')
invoiceImage=models.ImageField(upload_to='inventoryIn/%Y/%m/%d')
agingDate=models.DateField(verbose_name='Receiving Date')
labReportImage = models.ImageField(upload_to='labReportImage/%Y/%m/%d', blank=True,verbose_name='Lab Report Image')
enterPaymentDays = models.IntegerField(verbose_name='Enter Payment Days', blank=True, default=None)
dateOfEntry=models.DateField(default=datetime.now())
def __str__(self):
return str(self.supplierID)
def save(self, force_insert=False, force_update=False, using=None,
update_fields=None):
from Purchase.models import contracts,suppliers
contract = contracts.objects.values('supplierID', 'productDetailID').filter(id=self.purchaseContractID.id)
supplier=contract[0].get("supplierID")
product=contract[0].get("productDetailID")
self.supplierID=suppliers.objects.get(id=supplier)
self.productID=products.objects.get(productDetailsID=product)
super(inventoryIn,self).save()
and i also had made my two fields editable=False
supplierID=models.ForeignKey('Purchase.suppliers',editable=False,on_delete=models.CASCADE,verbose_name='Supplier')
productID=models.ForeignKey(products,editable=False,on_delete=models.CASCADE)
I am learning Django by following an application tutorial written by others called "portfolio". The code is available at http://www.lightbird.net/dbe/. I tried to modify the code so when a user submits a picture, the current user's name can be saved as "creator" defined in model.py as part of the image model. I have a hard time to make this work since I either got the error of unexpected argument of "dpk" or an error related to the number of arguments in "POST" function. Can someone help? Here are the information I have. I highlighted the part of the codes added, which are not part of the original.
models.py:
class Image(BaseModel):
title = CharField(max_length=60, blank=True, null=True)
description = TextField(blank=True, null=True)
image = ImageField(upload_to="images/")
thumbnail1 = ImageField(upload_to="images/", blank=True, null=True)
thumbnail2 = ImageField(upload_to="images/", blank=True, null=True)
width = IntegerField(blank=True, null=True)
height = IntegerField(blank=True, null=True)
hidden = BooleanField(default=True)
group = ForeignKey(Group, related_name="images", blank=True)
created = DateTimeField(auto_now_add=True)
creator = models.ForeignKey(User, null=True, blank=True)
##########################################################
def save(self,**kwargs):
if kwargs.has_key('request') and self.creator is None:
self.creator= kwargs['request'].creator
super(Image, self).save(**kwargs)
forms.py:
class AddImageForm(f.ModelForm):
class Meta:
model = Image
exclude = "width height hidden group thumbnail1 thumbnail2
creator".split()
attrs = dict(cols=70, rows=2)
widgets = dict( description=f.Textarea(attrs=attrs) )
#####################################################################
def save(self, commit=True , *args, **kwargs):
m = super(AddImageForm, self).save(commit=False, *args, **kwargs)
if m.creator is None and kwargs.has_key('request'):
m.creator= kwargs['request'].creator
m.save()
views.py:
class AddImages(DetailView, FormSetView):
"""Add images to a group view."""
detail_model = Group
formset_model = Image
formset_form_class = AddImageForm
template_name = "add_images.html"
extra = 1
############################################################
def post(self, request):
if form.is_valid():
form.save(request=request)
############################################################
def process_form(self, form):
form.instance.update( group=self.get_detail_object() )
def get_success_url(self):
return self.detail_absolute_url()
urls.py:
urlpatterns = patterns("portfolio.views",
(r"^group/(?P<dpk>\d+)/(?P<show>\S+)/" , GroupView.as_view(), {},
"group"),
(r"^group/(?P<dpk>\d+)/" , GroupView.as_view(), {},
"group"),
(r"^add-images/(?P<dpk>\d+)/" , AddImages.as_view(), {},
"add_images"),
(r"^slideshow/(?P<dpk>\d+)/" , SlideshowView.as_view(), {},
"slideshow"),
(r"^image/(?P<mfpk>\d+)/" , ImageView.as_view(), {},
"image"),
(r"^image/" , ImageView.as_view(), {},
"image"),
(r"" , Main.as_view(), {},
"portfolio"),
)
You've overridden the post method in your view to only take the request, but your URLs are passing it the dpk parameter.
You should not be overriding post anyway. The logic you have there should happen in form_valid.
(Also, you should reflect on whether you really need the same logic in three places. I would put all this code in form_valid, and not override save on the form or the model at all.)