I'm newbie in django and I'm doing my first educational project. I would like make an action with an intermediate page, but I receive :
KeyError at /admin/students/student/ 'action'
Scenario:
User selects from "Actions" listbox , action called :
u'Перемістити у групу'
Presses Go
New page should appears with the list of students and listbox to select a group.
please explain where is my error. My code is listed below:
class UpdateGroupForm(forms.Form):
group = forms.ModelChoiceField(queryset=Group.objects.all().order_by('title'), required=False)
def update_group(modeladmin,request,queryset):
if 'change_group' in request.POST:
form=UpdateGroupForm(request.POST)
if form.is_valid():
group=form.cleaned_data['group']
updated_group=queryset.update(student_group=group)
counter=queryset.count()
modeladmin.message_user(request,u"У %s студентів було змненно групу на %s")%(counter,group)
return
if not form:
form= UpdateGroupForm()
return (request,'/students/change_group.html',{'students':queryset,'form':form,'title':u'Зміна групи'})
update_group.short_description=u'Перемістити у групу'
class StudenAdmin(admin.ModelAdmin):
action_form = UpdateGroupForm
actions = [update_group]
list_display = ['last_name','first_name' ,'ticket','student_group']
list_display_links = ['last_name','first_name']
list_editable = ['student_group']
ordering = ['last_name']
list_filter = ['student_group']
list_per_page = 10
search_fields = ['last_name','first_name' ,'ticket','notes']
def get_view_on_site_url(self, obj):
return reverse ('students_edit',kwargs={'pk':obj.id})
code of my page:
{% extends "admin/base_site.html" %}
{% block content %}
<form action="" method="post">
{% csrf_token %}
{{ form }}
<p>Групу буде змінено у таких студентів:</p>
<ul>{{ students|unordered_list }}</ul>
<input type="hidden" name="action" value="update_group" />
<input type="submit" name="change_group" value="Зберігти" />
</form>
{% endblock %}
and here is code of my models:
class Student (models.Model):
"""Student Model"""
class Meta (object):
verbose_name=u"Студент"
verbose_name_plural=u"Студенти"
first_name=models.CharField(max_length=256,blank=False,verbose_name=u"Ім'я")
last_name=models.CharField(max_length=256,blank=False,verbose_name=u"Прізвище")
middle_name=models.CharField(max_length=256,blank=True,verbose_name=u"По-батькові")
birthday=models.DateField(blank=False,verbose_name=u"Дата народження",null=True)
photo=models.ImageField(blank=True,verbose_name=u"Фото",null=True)
ticket=models.CharField(max_length=256,blank=False,verbose_name=u"Білет")
student_group=models.ForeignKey('Group',verbose_name=u"Група",blank=False,null=True,on_delete=models.PROTECT)
notes=models.TextField(blank=True,verbose_name=u"Додаткові нотатки")
def __unicode__(self):
return u"%s %s" % (self.first_name,self.last_name)
# post_delete signal deletes student photo
post_delete.connect(remove_photo,Student)
class Group (models.Model):
"""Group Model"""
class Meta(object):
verbose_name=u"Група"
verbose_name_plural=u"Групи"
title=models.CharField(max_length=256,blank=False,verbose_name=u"Назва")
leader=models.OneToOneField('Student',verbose_name=u"Староста",blank=True,null=True,on_delete=models.SET_NULL)
notes=models.TextField(blank=True,verbose_name=u"Додаткові нотатки")
def __unicode__(self):
if self.leader:
return u"%s(%s %s)"%(self.title,self.leader.first_name,self.leader.last_name)
else:
return u"%s"%(self.title)
Related
I have a page with a form that takes in an employee # (using foreignkey), and when it is submitted it verifies that this employee # is in fact in another model (Salesman), and checks if 'WF' is in the team field for this employee. While the logic works and everything is being displayed, I keep getting this random bold text under the box Salesman object (406) (or whichever number I entered that would give me an error) after submitting the form, along with the proper error on top.
I think this is related to the foreignkey field part, but I'm not sure how to prevent this from showing up when there are errors.
models.py
class EmployeeWorkAreaLog(TimeStampedModel, SoftDeleteModel, models.Model):
employee_number = models.ForeignKey(Salesman, on_delete=models.SET_NULL, null=True, blank=False)
...
def __str__(self):
return self.employee_number
forms.py
class WarehouseForm(AppsModelForm):
class Meta:
model = EmployeeWorkAreaLog
widgets = {
'employee_number': ForeignKeyRawIdWidget(EmployeeWorkAreaLog._meta.get_field('employee_number').remote_field, site, attrs={'id':'employee_number_field'}),
}
fields = ('employee_number', 'work_area', 'station_number')
def clean_employee_number(self):
employee_number = self.cleaned_data.get('employee_number')
if 'WF' in employee_number.team:
raise forms.ValidationError("Employee not valid, please contact manager")
else:
pass
return self.cleaned_data
views.py
class EnterExitArea(CreateView):
model = EmployeeWorkAreaLog
template_name = "operations/enter_exit_area.html"
form_class = WarehouseForm
def form_valid(self, form):
emp_num = form.cleaned_data['employee_number']
area = form.cleaned_data['work_area']
station = form.cleaned_data['station_number']
if 'enter_area' in self.request.POST:
form.save()
EmployeeWorkAreaLog.objects.filter((Q(employee_number=emp_num) & Q(work_area=area) & Q(time_out__isnull=True) & Q(time_in__isnull=True)) & (Q(station_number=station) | Q(station_number__isnull=True))).update(time_in=datetime.now())
return HttpResponseRedirect(self.request.path_info)
elif 'leave_area' in self.request.POST:
form.save()
return HttpResponseRedirect(self.request.path_info)
enter_exit_area.html
{% extends "base.html" %}
{% block main %}
<form id="warehouseForm" action="" method="POST" novalidate >
{% csrf_token %}
<div>
<div style="color: red">{{ form.employee_number.errors.as_text }}</div>
<div>
<label>Employee</label>
{{ form.employee_number }}
</div>
<!-- ... More fields ... -->
</div>
<div>
<div>
<button type="submit" name="enter_area" value="Enter">Enter Area</button>
<button type="submit" name="leave_area" value="Leave">Leave Area</button>
</div>
</div>
</form>
{% endblock main %}
That is part of the ForeignKeyRawIdWidget widget and it's the representation of the selected object (the Salesman object with ID 406).
If you wanted to get rid of it you would have to create a new widget which extends ForeignKeyRawIdWidget and removes that bit from the template. Here you can see how ForeignKeyRawIdWidget and its template look like.
Alternatively, and possibly better, you could consider to define the __str__ method of the Salesman model to show something more meaningful, in the same way you did for EmployeeWorkAreaLog.
I'm using models.manager to count the number of votes but I don't understand why the number of vote isn't showing off. the voting system works(checked with admin) but the manager isn't working.
models.py
class PostVoteCountManager(models.Manager):
def get_query_set(self):
return super(PostVoteCountManager, self).get_query_set.annotate(
votes=Count('vote')).order_by("-votes")
class Post(models.Model):
rank_score = models.FloatField(default=0.0)
with_votes = PostVoteCountManager()
class Vote(models.Model):
voter = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
def __str__(self):
return "%s voted %s" %(self.voter.username, self.post.title)
my views.py
class PostListView(ListView):
model = Post
template_name = 'community/home.html' # <app>/<model>_<viewtype>.html
context_object_name = 'posts'
#ordering = ['-date_posted']
queryset = Post.with_votes.all()
def get_context_data(self, **kwargs):
context = super(PostListView, self).get_context_data(**kwargs)
if self.request.user.is_authenticated:
voted = Vote.objects.filter(voter=self.request.user)
posts_in_page = [post.id for post in context["object_list"]]
voted = voted.filter(post_id__in=posts_in_page)
voted = voted.values_list('post_id', flat=True)
context["voted"] = voted
return context
In html I do
{% for post in posts %}
<form method="post" action="{% url 'vote' %}" class="vote_form">
<li> [{{ post.votes }}]
{{post}}
{% csrf_token %}
<input type="hidden" id="id_post" name="post" class="hidden_id" value="{{ post.pk }}" />
<input type="hidden" id="id_voter" name="voter" class="hidden_id" value="{{ user.pk }}" />
{% if not user.is_authenticated %}
<button disabled title="Please login to vote">+</button>
{% elif post.pk not in voted %}
<button>+</button>
{% else %}
<button>-</button>
{% endif %}
</form>
{% endform%}
You wrote the function as get_query_set, but the name is get_queryset [Django-doc]. Furthermore, you forgot to call the get_queryset(..) function here:
class PostVoteCountManager(models.Manager):
def get_queryset(self):
return super(PostVoteCountManager, self).get_queryset().annotate(
votes=Count('vote')).order_by("-votes")
I'm not sure how to filter dropdown based on user id.
Not I want for user id 2.
I want exactly like this for user id 2.
Model
#python_2_unicode_compatible # only if you need to support Python 2
class PredefinedMessage(models.Model):
user = models.ForeignKey(User)
list_name = models.CharField(max_length=50)
list_description = models.CharField(max_length=50)
def __str__(self):
return self.list_name
class PredefinedMessageDetail(models.Model):
predefined_message_detail = models.ForeignKey(PredefinedMessage)
message = models.CharField(max_length=5000)
View
class PredefinedMessageDetailForm(ModelForm):
class Meta:
model = PredefinedMessageDetail
fields = ['predefined_message_detail', 'message']
exclude = ('user',)
def predefined_message_detail_update(request, pk, template_name='predefined-message/predefined_message_detail_form.html'):
if not request.user.is_authenticated():
return redirect('home')
predefined_message_detail = get_object_or_404(PredefinedMessageDetail, pk=pk)
form = PredefinedMessageDetailForm(request.POST or None, instance=predefined_message_detail)
if form.is_valid():
form.save()
return redirect('predefined_message_list')
return render(request, template_name, {'form':form})
html file
{% extends "base.html" %}
{% load i18n %}
{% block content %}
<form method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
{% endblock %}
You can do it in view itself using
form = PredefinedMessageDetailForm(request.POST or None, instance=predefined_message_detail)
form.fields["predefined_message_detail"].queryset= PredefinedMessage.objects.filter(user=request.user)
But filtering happens based on request.user so it should be logged in.Consider that also. Hope this helps
I'm trying to add some users, in my Django project, to my created before group, but I know how to add to the specific group which I know the name and it's not dynamic. I would like that when I select a specific group, already add the next user. The problem is here:
g = Group.objects.get(name= 'New')
What should I do to replace this and indicate this group which I clicked?
views.py:
#login_required
def choose_group(request, pk):
if request.method == "POST":
cvs = get_object_or_404(Cv, pk=pk)
p = Person.objects.create(name=cvs.author)
g = Group.objects.get(name= 'New')
m = Membership.objects.create(person=p, group=g, leader=False)
return redirect( 'proj.views.cv_detail', pk=cvs.pk )
else:
cv = Cv.objects.filter(author = request.user)
cvs = get_object_or_404(Cv, pk=pk)
mem = Membership.objects.all()
context = {
'mem':mem,
'cvs':cvs,
'cv':cv
}
return render(request, 'choose_group.html', context)
models.py:
class Person(models.Model):
name = models.CharField(max_length=128)
def __str__(self): # __unicode__ on Python 2
return self.name
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
def __str__(self): # __unicode__ on Python 2
return self.name
class Membership(models.Model):
person = models.ForeignKey(Person)
leader = models.BooleanField(default=False)
group = models.ForeignKey(Group)
choose_groups.html:
{% block profile %}
<div class="jumbotron">
<h3>Choose a group to add:</h3>
</div>
<ul>
{% for m in mem %}
<form method="POST" class="post-form" >{% csrf_token %}
<li><button type="submit" class="li1"> <b>{{ m.group }}</b></li>
</form>
{% endfor %}
</ul>
{% endblock %}
The main issue i see here is that you are not sending the group name m.group from your html.
to do so, you must add name and value to the button element in your html (and don't forget to close the button element)
<button type="submit" class="li1" name="group" value="{{m.group}}"> <b>{{ m.group }}</b></button>
Then, you can retrieve this group value in your views.py by using request.POST
g = Group.objects.get(name=request.POST['group'])
I'm writing a django app, and I'd like for users to be able to select a [team_number] from a dropdown menu, then when they hit submit be redirected to a page that renders out the database information associated with that selection. I'm using the redirect class View, but the problem I'm having is that there is no dropdown menu showing up to select [team_number] from on the html page team-stats.html.
views.py:
class TeamStatsView(View):
def get(self, request, *args, **kwargs):
return render(request, 'team-stats.html',
{'team_number': TeamStats()})
def post(self, request, *args, **kwargs):
team_number = TeamStats(request.POST, request.FILES)
if team_number.is_valid():
# do stuff & add to database
team_number.save()
team_number = TeamStats.objects.create()
# use my_file.pk or whatever attribute of FileField your id is
# based on
return HttpResponseRedirect('/team-stats/%i/' % team_number.pk)
return render(request, 'team-stats.html', {'team_number': team_number})
models.py:
class Team(models.Model):
team_number = models.IntegerField()
team_notes = models.CharField(max_length=150)
event_id = models.ForeignKey(
'Event', on_delete=models.CASCADE, unique=False)
def __unicode__(self):
return str(self.team_number)
class Meta:
db_table = 'teams'
app_label = 'frcstats'
forms.py:
class TeamStats(forms.ModelForm):
class Meta:
model = Team
fields = ['team_number']
team-stats.html:
<form method="post" action="">
{% csrf_token %} {{ TeamStatsView }}
<input type="submit" value="Submit" />
</form>
If there are any other files that I need to update into here to show what I'm trying to do, please let me know. Thanks
Try changing your view variable name to team_numbers and replacing your team-stats.html snippet with the following:
<form method="post" action="">
<select name="teams">
{% for team_number in team_numbers %}
<option value="{{ team_number }}">Team Num: {{ team_number }}</option>
{% endfor %}
</select>
</form>
Then update your view to:
class TeamStatsView(View):
def get(self, request, *args, **kwargs):
return render(request, 'team-stats.html',
{'team_numbers':Team.objects.values('team_number')})
You can use choices=NUMBERS
NUMBERS = (
('1','1'),
('2','2'),
('3','3'),
('4','4')
)
class Team(models.Model):
team_number = models.IntegerField(choices=NUMBERS )
team_notes = models.CharField(max_length=150)
event_id = models.ForeignKey(
'Event', on_delete=models.CASCADE, unique=False)
def __unicode__(self):
return str(self.team_number)
class Meta:
db_table = 'teams'
app_label = 'frcstats'
Your view variable is called team_number.
Try to change TeamStatsView into team_number:
<form method="post" action="">
{% csrf_token %} {{ team_number }}
<input type="submit" value="Submit" />
</form>