I am just starting with Django and web development , so please be nice with me. i am trying to build an app that generates a new number to reports created by our inspectors (our company is an inspection company). each inspector chooses the type of reports, the inspection date and the client and the app saves the data and creates a report number . the report number is generated depending on the type of the report and the date. for example if i have 3 reports of type "visual inspection" done in 2022, the new "visual inspection" report will have the number 4/2022.
here is the code I used to attempt this but unfortunately it is not working:
Views.py
from modulefinder import ReplacePackage
from django.shortcuts import render
from report.models import Report
from django.http import HttpResponse
from django.db.models.aggregates import Count
from django.db import transaction
from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response
from .serializers import ReportSerializer
#api_view(['GET','POST'])
def Report_add_view(request):
if request.method =='GET':
queryset = Report.objects.select_related('type').all()
serializer = ReportSerializer(queryset,many=True)
return Response(serializer.data,status=status.HTTP_200_OK)
elif request.method =='POST':
serializer = ReportSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data,status=status.HTTP_201_CREATED)
# Create your views here.
models.py
from django.db import models
# Create your models here.
class Client(models.Model):
name = models.CharField(max_length = 255)
code = models.PositiveIntegerField()
class ReportType(models.Model):
report_type = models.CharField(max_length = 255)
report_code = models.CharField(max_length = 255)
report_rev = models.CharField(max_length = 20)
def __str__(self):
return self.report_type
class Inspector(models.Model):
first_name = models.CharField(max_length = 255)
last_name = models.CharField(max_length = 255)
full_name = models.CharField(max_length = 255)
class Report (models.Model):
number = models.CharField(max_length=100)
type = models.CharField(max_length = 255)
inspection_date = models.DateField()
date_created = models.DateTimeField(auto_now_add=True)
inspector = models.ForeignKey(Inspector,on_delete=models.PROTECT)
client = models.ForeignKey(Client,on_delete=models.PROTECT)
type = models.ForeignKey(ReportType,on_delete=models.PROTECT)
reportlink = models.TextField()
serializers.py
from rest_framework import serializers
from .models import *
from django.db.models.aggregates import Count
from django.db.models import F
class ReportSerializer(serializers.ModelSerializer):
class Meta:
fields = ['number','type','inspection_date','inspector','client','reportlink','date_created']
model = Report
number = serializers.SerializerMethodField(method_name='report_number')
def report_number(self, report:Report):
print(report.type_id)
num1 = Report.objects.filter(type_id = report.type_id).all().aggregate(num=Count('id'))['num']+1
year = str(report.inspection_date)[:4]
print(year)
print(num1)
return str(num1) + "/"+ year
class InspectorSerializer(serializers.ModelSerializer):
class Meta:
fields = ['first_name','last_name','full_name']
model = Inspector
class ReportTypeSerializer(serializers.ModelSerializer):
class Meta:
fields = ['report_type','report_code','report_rev']
model = Report
screenshot of api result:
database screenshot:
As stated in the DRF doc: https://www.django-rest-framework.org/api-guide/fields/#serializermethodfield
SerializerMethodField is a read_only field.
To achieve what you're trying to do, i would override the "create" method of the serializer. It takes a dict of validated_data as parameter (generate thanks to the is_valid call you're doing).
In this method, you should be able to set validated_data["number"] with your desired value (return the modified dict at the end of the "create" method).
I'm not sure, but i think you should remove "number" from your list of fields in the serializer since you're calculating it.
Related
Here is my model
Model
from Account.models import User
from django.db import models
class Seller(models.Model):
seller = models.OneToOneField(User, on_delete = models.CASCADE)
email = models.EmailField(max_length = 90, unique = True)
country = models.CharField(max_length = 60)
phone = models.CharField(max_length= 20, unique = True, blank = True, null = True)
address = models.TextField()
zipcode = models.CharField(max_length = 10)
form
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.db import transaction
from .models import Seller
from Account.models import User
class SellerCreationForm(UserCreationForm):
name = forms.CharField(required = True)
email = forms.EmailField(required = True)
phone = forms.CharField(required = False)
country = forms.CharField(required = True)
address = forms.CharField(required = True)
zipcode = forms.CharField(required = True)
class Meta(UserCreationForm.Meta):
model = User
#transaction.atomic
def save(self):
user = super().save(commit=False)
user.is_seller = True
user.name = self.cleaned_data.get('name')
user.save()
seller = Seller.objects.create(user=user)
seller.email = self.cleaned_data.get('email')
seller.phone = self.cleaned_data.get('phone')
seller.country = self.cleaned_data.get('country')
seller.address = self.cleaned_data.get('address')
seller.zipcode = self.cleaned_data.get('zipcode')
seller.save()
return user
views
from django.shortcuts import render, redirect
from django.views.generic import CreateView
from .forms import SellerCreationForm
from django.contrib.auth.forms import AuthenticationForm
from Account.models import User
class RegisterSeller(CreateView):
model = User
form_class = SellerCreationForm
template_name = 'registration/registerseller.html'
def form_valid(self, form):
user = form.save()
login(self.request, user)
return redirect('/')
I tried to create a project with multiple users types and all users having different functionality.
Everything in the code functions well but whenever I try to register a new user I get an error.
And it says Seller() got an unexpected keyword argument 'user'
The ForeignKey from the Seller to the User has been named seller, not seller`. You thus can construct an object with:
seller = Seller.objects.create(
seller=user,
email=self.cleaned_data['email']
phone = self.cleaned_data['phone']
country = cleaned_data['country']
address = self.cleaned_data['address']
zipcode = self.cleaned_data['zipcode']
)
But perhaps it is better to rename the field to:
from Account.models import User
from django.db import models
class Seller(models.Model):
user = models.OneToOneField(User, on_delete = models.CASCADE)
# ⋮
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.
i created a proxy model in django 3.1.10 where i defined a function to make a copy of an object with all it's related objects through foreign key and it worked fine , but when i upgraded to django 3.2 the function only create a copy of the object without any related objects
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
from ValPlanner.models import ProgramExecution
import datetime
from django.utils import timezone
#-----------------------------------------------------------------------------------------------------------------------------
class Record(models.Model):
title = models.CharField(max_length=50)
description = models.CharField(max_length=200)
execution = models.ForeignKey(ProgramExecution, on_delete=models.PROTECT,null=True)
timestamp = models.DateTimeField(auto_now_add=True)
creator = models.ForeignKey(User, on_delete=models.PROTECT)
record_type = models.CharField(max_length=50,default='template')
def __str__(self):
return self.title
class TemplateRecord(Record):
class Meta:
proxy = True
def create_report(self,creator,execution):
stages = self.stage_set.all();
self.record_type = 'record'
self.pk = None;
self.execution = execution
self.creator = creator
self.save();
for stage in stages :
samples = stage.sample_set.all()
stage.pk = None
stage.stage_type = 'record'
stage.record = self
stage.save();
for sample in samples :
tests = sample.testnum_set.all()
sample.sample_type = 'record'
sample.stage = stage
sample.sample_time = timezone.now()
sample.sampler = creator
for samplenum in range(sample.number_of_samples):
sample.pk = None
sample.save();
for test in tests :
test.pk = None
test.test_type = 'record'
test.sample = sample
test.tester = creator
test.save();
#-----------------------------------------------------------------------------------------------------------------------------
class Stage(models.Model):
record = models.ForeignKey(Record, on_delete=models.CASCADE)
title = models.CharField(max_length=50)
stage_type = models.CharField(max_length=50,default='template')
def __str__(self):
return self.title
#-----------------------------------------------------------------------------------------------------------------------------
class Sample(models.Model):
stage = models.ForeignKey(Stage, on_delete=models.CASCADE)
name = models.CharField(max_length=50)
sample_time = models.DateTimeField(default=timezone.now)
sample_location = models.CharField(max_length=50)
sampler = models.ForeignKey(User, on_delete=models.PROTECT)
sample_type = models.CharField(max_length=50,default='template')
number_of_samples = models.PositiveSmallIntegerField(null=True,default=1)
def __str__(self):
return self.name
#-----------------------------------------------------------------------------------------------------------------------------
class TestNum(models.Model):
sample = models.ForeignKey(Sample, on_delete=models.CASCADE)
name = models.CharField(max_length=50)
result = models.DecimalField(max_digits=15, decimal_places=5,null=True)
acceptance = models.CharField(max_length=50)
maximum_acceptance = models.DecimalField(max_digits=15, decimal_places=5)
minimum_acceptance = models.DecimalField(max_digits=15, decimal_places=5)
test_type = models.CharField(max_length=50,default='template')
tester = models.ForeignKey(User, on_delete=models.PROTECT)
def __str__(self):
return self.name
#-----------------------------------------------------------------------------------------------------------------------------
and my function is in view.py :
from django.shortcuts import render, get_object_or_404, redirect
from django.contrib import messages
from django.contrib.auth.models import User
from django.urls import reverse
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView, TemplateView
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin, PermissionRequiredMixin
from .models import Record, TemplateRecord, Stage, Sample, TestNum
import datetime
from django.utils import timezone
class CreateEmptyReport (PermissionView, UpdateView):
model = TemplateRecord
permission_required = 'ETRecord.add_record'
fields = ['execution']
def get_object(self):
template_list = TemplateRecord.objects.filter(record_type='template')
return super().get_object(queryset = template_list)
def form_valid(self,form):
self.object.create_report(creator=self.request.user,execution=form.instance.execution)
return super().form_valid(form);
def get_success_url(self):
return reverse('ETRecord:report_details',kwargs= {'pk': self.object.id})
on old version it ould copy the record and all relaated stages , samples and tests but after update it only copies the record with no associated stages or samples
i tried to uninstall and re-install the older verison it works only on the older version , so how can i make it compatable with the new 3.2 version ?
You are creating the queryset before you copy the record itself, which seems fine
stages = self.stage_set.all();
But... Django won't resolve this queryset before it'll be accessed. Older versions of Django would probably just hold the ID of the parent element, so the queryset doesn't change after you change the ID on the self, but newer versions of Django are holding the entire object and extracting the ID of the object just before the queryset is actually executed on the database.
This causes your for loop to iterate over stages connected to the new record instance (you've just created it, so it's an empty queryset) instead of the old one.
To fix that issue, you can either force the execution of the queryset earlier (for example by casting it into a list) or by creating the queryset that won't use the self object, but the ID of the old object explicitly, for example:
stages = Stage.objects.filter(record_id=self.id);
I am trying to select all class for a user and then load all of the classes objects that are corresponding. Here is my model.py file:
from django.db import models
from django.contrib.auth.models import User
class Class(models.Model):
name = models.CharField(max_length=150)
description = models.TextField()
teacher = models.ForeignKey(User)
class UserClasses(models.Model):
class_name = models.ForeignKey(Class)
user = models.ForeignKey(User)
And here is the call i'm making:
def index(request):
#grab all classes for a user
users_classes = UserClasses.objects.filter(user=request.user)
#pass the array of class objects and get their info
classes = Class.objects.select_related(self=users_classes)
context_dict = {}
return render(request, 'dashboard/index.html', context_dict)
How can I achieve the above?
You can do
users_classes = UserClasses.objects.filter(user=request.user)
classes = Class.objects.filter(class_name__in=users_classes)
Now classes objects contains all class which user belongs to.
I still cant seem to put a simple program together. I am thinking of a simple program where my coworkers and I could propose a bet with each other. (example: I bet the detriot Lions dont win another game this season) If someone is feeling up to the task of taking that bet they can just hit an accept button. I want the user to be logged in and upon submitting the bet_name and bet_desc of the bet, their username, bet_name, bet_desc, and timestamp is saved to a table. Then a relationship table would save the bet id, win, tie, created_user_id, accepted_user_id, accepted_timestamp, and cancelled. Then userprofile table to keep their username, wins, losses, ties, bets_made, and bets_accepted.
models.py
from django.db import models
from django.contrib.auth.models import User
from datetime import datetime
class UserProfiles(models.Model):
username = models.OneToOneField(User)
wins = models.PositiveIntegerField(default=0)
losses = models.PositiveIntegerField(default=0)
ties = models.PositiveIntegerField(default=0)
bets_made = models.PositiveIntegerField(default=0)
bets_accepted = models.PositiveIntegerField(default=0)
def __str__(self):
return "%s's profile" % self.username
class Bets2(models.Model):
bet_name = models.CharField(max_length=30)
bet_desc = models.CharField(max_length=300)
timestamp = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
created_user = models.OneToOneField(UserProfiles, primary_key=True)
accepted_user = models.PositiveIntegerField(default=0)
accepted_timestamp = models.DateTimeField(auto_now=True)
win = models.BooleanField(default=True)
tie = models.BooleanField(default=True)
cancelled = models.BooleanField(default=True)
def __str__(self):
return "%s's profile" % self.bet_name
As far as forms.py and views this is all i have so far:
forms.py
from django import forms
from django.core.exceptions import ValidationError
from .models import Bets2, UserProfiles
class BetForm(forms.ModelForm):
class Meta:
model = Bets2
fields = ['bet_name', 'bet_desc',]
def clean_name(self):
bet_name = self.cleaned_data.get('bet_name')
#write code here
return name
def clean_bet(self):
bet_desc = self.cleaned_data.get('bet_desc')
#write code here
return bet
views.py
from django.shortcuts import render
from django.conf import settings
from .forms import BetForm
from .models import Bets2, UserProfiles
def home(request):
title = "2015 Boardbets"
queryset = Bets2.objects.all().order_by('timestamp')
queryuser = UserProfiles.objects.all()
context = {
"title": title,
"queryset" : queryset,
"queryuser" : queryuser,
}
return render(request, "home.html", context)
def boardbet(request):
form = BetForm(request.POST or None)
bet_variables = Bets2.objects.all()
context = {
"form" : form,
"bet_variables" : bet_variables,
}
if form.is_valid():
form.save()
return render(request, "bets.html", context)
This is where i get stumped, i dont know how to incorporate the other two models into the view so that all three tables get created and also how to reference them in the template.
Edit: changed it to one model for Bets
For academic purposes, I am creating software that can manage a company's clients, project, and staff members. I figured out that by referencing a foreignkey in a separate model, you can get two models to display next to each other and be related. The problem is, is that it only displays one item for each model.
For example: You have a project your company is working on. In the admin section, it displays the project name and a single staff member. However, it should be displaying 2+ staff members.
Here's the file layout (I tried creating a separate app for different fields clients being the primary and projects the secondary):
clients.admin:
from django.contrib import admin
from django.db import models
from clients.models import Status, Project, Staff_Member, Client
class StatusInline(admin.TabularInline):
model = Status
extra = 0
class Staff_MemberInline(admin.TabularInline):
model = Staff_Member
extra = 5
project = models.ForeignKey(Project)
class ProjectInline(admin.TabularInline):
model = Project
extra = 1
class ClientAdmin(admin.ModelAdmin):
fieldsets = [
(None, {'fields': ['name']}),
]
inlines = [ProjectInline, StatusInline]
search_fields = ['name']
admin.site.register(Client, ClientAdmin)
#admin.site.register(Project)
admin.site.register(Staff_Member)
next file
clients.models:
from django.db import models
import datetime
from django.utils import timezone
# Create your models here.
class Client(models.Model):
name = models.CharField(max_length=200)
def __unicode__(self):
return self.name
#def was_published_recently(self):
# return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
#was_published_recently.admin_order_filed = 'pub_date'
#was_published_recently.boolean = True
#was_published_recently.short_description = 'Published recently?'
class Status(models.Model):
client = models.ForeignKey(Client)
#staff_member = models.ForeignKey(Staff_Member)
#project = models.ForeignKey(Project)
status_text = models.CharField(max_length=200)
def stat(self):
return self.status_text
def __unicode__(self):
return self.status_text
class Staff_Member(models.Model):
#status = models.ForeignKey(Status)
#project = models.ForeignKey(Project)
#client = models.ForeignKey(Client)
staff_member_text = models.CharField(max_length=200)
def __unicode__(self):
return self.staff_member_text
def mem(self):
return self.staff_member_text
class Project(models.Model):
client = models.ForeignKey(Client)
project_text = models.CharField(max_length=200)
staff_member = models.ForeignKey(Staff_Member)
#status = models.ForeignKey(Status)
def __unicode__(self):
full_name = self.client.name +'\'s '+ self.project_text
return full_name
def project_name(self):
return self.project_text
name = client.name
next file
projects.admin:
from django.contrib import admin
from django.db import models
from clients.models import Project, Status, Client
from clients.admin import StatusInline, Staff_MemberInline
class ClientInline(admin.TabularInline):
model = Client
extra = 1
#class ProjectAdmin(admin.ModelAdmin):
# inlines = [Staff_MemberInline, ClientInline]
#admin.site.unregister(Project)
admin.site.register(Project)#, ProjectAdmin)
next file
projects.models
from django.db import models
import datetime
from django.utils import timezone
from django.db import models
from clients.models import *
# Create your models here.
I'm pretty new to stackoverflow, so if there's a way I'm missing to make this more eye-friendly let me know.
Thanks!
Change extra = 1 to a higher number. More info in the docs.