Django view if statement - django

i have choices field. I want in views.py like this;
How can i do?
if gametype == 1:
template='xxx.html'
if gametype == 2:
template='xxx1.html'
views.py
def game_detail(request,tournamentslug,slug,gameslug):
game=get_object_or_404(Model,tournament__slug=tournamentslug,slug=slug,game__slug=gameslug)
context={
'game':game,
}
return render(request,'esports/lolgame.html',context)
models.py
class Model(models.Model):
type_tvt = 1
type_pvp = 2
type_royale=3
types = (
(type_tvt, 'T'),
(type_pvp, 'P'),
(type_royale,'R'),
)
gametype=models.SmallIntegerField(choices=types)

Assuming you have a class-based detail view (and the model is named Game for sanity, not Model as in your example),
class GameView(generic.DetailView):
model = Game
def get_template_names(self):
if self.object.gametype == Game.type_tvt:
return ['xxx.html']
elif self.object.gametype == Game.type_pvp:
return ['xxx2.html']
elif self.object.gametype == Game.type_royale:
return ['xxx3.html']
raise ValueError('invalid game type')
would do the trick – or to simplify using a dict,
class GameView(generic.DetailView):
model = Game
template_names = {
Game.type_tvt: 'xxx.html',
Game.type_pvp: 'xxx2.html',
Game.type_royale: 'xxx3.html',
}
def get_template_names(self):
return [self.template_names[self.object.gametype]] # may raise KeyError
EDIT: for a function-based view, as in the edited question,
template_names = {
Model.type_tvt: "xxx.html",
Model.type_pvp: "xxx2.html",
Model.type_royale: "xxx3.html",
}
def game_detail(request, tournamentslug, slug, gameslug):
game = get_object_or_404(
Model,
tournament__slug=tournamentslug,
slug=slug,
game__slug=gameslug,
)
context = {"game": game}
template_name = template_names[game.gametype]
return render(request, template_name, context)

Related

I'm trying to override a django formtools wizard form widget, but it is just using the standard widget

I have the following form
class ProviderSignUp1(forms.ModelForm):
class Meta:
model = models.Provider
fields = [
'childcare_type_informal',
'childcare_type_accredited',
]
wigdets = {
'childcare_type_informal': PatchRadioSelect(
attrs={
'class':'form-control'
}
),
'childcare_type_accredited': PatchRadioSelect(
attrs={
'class':'form-control'
}
)
}
def clean(self):
cleaned_data = self.cleaned_data
if cleaned_data['childcare_type_informal'] == True and cleaned_data['childcare_type_accredited'] == True:
raise ValidationError("You must select only one type of childcare")
if cleaned_data['childcare_type_informal'] == False and cleaned_data['childcare_type_accredited'] == False:
raise ValidationError("You must select at least one type of childcare")
return super().clean()
The widget is defined as
from django.forms.widgets import RadioSelect
class PatchRadioSelect(RadioSelect):
template_name = 'userprofiles/form_widgets/radio.html'
option_template_name = 'userprofiles/form_widgets/radio_option.html'
And my wizard is:
PROVIDER_SIGNUP_TEMPLATES = {
'page0': 'userprofiles/provider_signup_wizard/page0.html',
'page1': 'userprofiles/provider_signup_wizard/page1.html',
'page2': 'userprofiles/provider_signup_wizard/page2.html',
'page3': 'userprofiles/provider_signup_wizard/page3.html',
'page4': 'userprofiles/provider_signup_wizard/page4.html',
'page5': 'userprofiles/provider_signup_wizard/page5.html',
'page6': 'userprofiles/provider_signup_wizard/page6.html',
'page7': 'userprofiles/provider_signup_wizard/page7.html',
'page8a': 'userprofiles/provider_signup_wizard/page8.html',
'page8b': 'userprofiles/provider_signup_wizard/page8.html',
'page9': 'userprofiles/provider_signup_wizard/page9.html',
'page10': 'userprofiles/provider_signup_wizard/page10.html',
}
PROVIDER_SIGNUP_FORMS = [
("page0", forms.ProviderSignUp0),
("page1", forms.ProviderSignUp1),
("page2", forms.ProviderSignUp2),
("page3", forms.ProviderSignUp3),
("page4", forms.ProviderSignUp4),
("page5", forms.ProviderSignUp5),
("page6", forms.ProviderSignUp6),
("page7", forms.ProviderSignUp7),
("page8a", forms.ProviderSignUp8a),
("page8b", forms.ProviderSignUp8b),
("page9", forms.ProviderSignUp9),
("page10", forms.ProviderSignUp10),
]
def accredited_only_condition(wizard):
cleaned_data = wizard.get_cleaned_data_for_step('page1') or {}
return cleaned_data.get('childcare_type_accredited', True)
def informal_only_condition(wizard):
cleaned_data = wizard.get_cleaned_data_for_step('page1') or {}
return cleaned_data.get('childcare_type_informal', True)
class ProviderSignUpWizard(SessionWizardView):
form_list = PROVIDER_SIGNUP_FORMS
condition_dict = {
'page2': accredited_only_condition,
'page8a': accredited_only_condition,
'page8b': informal_only_condition,
'page9': informal_only_condition,
}
def get_form_instance(self, step):
if step == 'page4':
return self.instance_dict.get(step, self.request.user)
return self.instance_dict.get(step, self.request.user.provider)
def get_template_names(self):
return [PROVIDER_SIGNUP_TEMPLATES[self.steps.current]]
def done(self, form_list, **kwargs):
provider_instance = models.Provider.objects.get(id=self.request.user.provider.id)
user_instance = models.User.objects.get(id=self.request.user.id)
for form in form_list:
provider_instance = construct_instance(form, provider_instance, form._meta.fields, form._meta.exclude)
user_instance = construct_instance(form, user_instance, form._meta.fields, form._meta.exclude)
provider_instance.save()
user_instance.save()
return redirect(self.request.user.get_provider_profile_url())
def post(self, *args, **kwargs):
form = self.get_form(data=self.request.POST, files=self.request.FILES)
if form.is_valid():
form.save()
if 'services' in form.cleaned_data:
models.Provider.objects.get(id=self.request.user.provider.id).services.set(form.cleaned_data['services'])
if 'features' in form.cleaned_data:
models.Provider.objects.get(id=self.request.user.provider.id).features.set(form.cleaned_data['features'])
if 'informal_phrases' in form.cleaned_data:
models.Provider.objects.get(id=self.request.user.provider.id).informal_phrases.set(form.cleaned_data['informal_phrases'])
return super().post(*args, **kwargs)
My widget is being ignored and the standard widget is being used. Please note, I seem unable to change any of the widgets from the standard and can only add attributes to the existing widget. What am I doing wrong?
Just in case anyone else comes across the same issue, I found if I define __init__ within the first form in the wizard, I can then override the widgets within __init__ in whichever form I need to use it. But it doesn't work if I don't specify __init__ in the first form.
I think this more a workaround than solution.

How to render form with errors in generic detail view

I am trying to render a generic detail view page with a form with errors
My post method in my generic detail view is
def post(self, request, slug):
if 'submit-edit-roster' in request.POST:
edit_roster_form = EditRosterForm(request.POST, team=self.request.user.playerprofile.team)
if edit_roster_form.is_valid():
edit_roster_form.save()
return redirect ('tcl-team', slug=self.request.user.playerprofile.team.urlslug)
my edit roster form is
class EditRosterForm(forms.Form):
members = 0
team = None
sublist = []
playerlist = []
def __init__(self, *args, **kwargs):
self.team = kwargs.pop('team', None)
self.members = 0
self.sublist = []
self.playerlist = []
super(EditRosterForm, self).__init__(*args, **kwargs)
currentroster = Roster.objects.filter(team=self.team)[0]
for member in Playerprofile.objects.filter(team=self.team).order_by('name'):
if member in currentroster.players.all():
self.fields[str(member.name)] = forms.ChoiceField(choices=ROSTER_CHOICES)
self.initial[str(member.name)] = '1'
elif member in currentroster.subs.all():
self.fields[str(member.name)] = forms.ChoiceField(choices=ROSTER_CHOICES)
self.initial[str(member.name)] = '2'
self.members += 1
def clean(self):
cleaned_data = super().clean()
i = 0
for member in Playerprofile.objects.filter(team=self.team):
if cleaned_data[member.name] == '1':
self.playerlist.append(member)
elif cleaned_data[member.name] == '2':
self.sublist.append(member)
i += 1
print(len(self.sublist))
if len(self.sublist) > 2:
raise ValidationError("Maximum of 2 subs allowed")
if len(self.playerlist) > 5:
raise ValidationError("Maximum of 5 players allowed")
if len(self.playerlist) + len(self.sublist) > i:
raise ValidationError("Team members must be a sub or a player")
return cleaned_data
def save(self):
cleaned_data = self.cleaned_data
print(cleaned_data)
UpdateRoster(roster=self.team.GetCurrentRoster(), players=self.playerlist, subs=self.sublist)
When my form has errors I get
The view team.views.TeamEditView didn't return an HttpResponse object. It returned None instead.
I know I need to add something to pass my form the form object with errors but can't find how to do this.
if edit_roster_form.is_valid():
edit_roster_form.save()
return redirect ('tcl-team', slug=self.request.user.playerprofile.team.urlslug)
else:
# Render detail view page with form
Apologies if my question is incoherent, I'm new to django and stackoverflow
I think you have to add request as parameter to the render shortcut

django tables 2 - delete column and delete_item for inherited tables

I want to have one abstract function for all my tablelists (one for each model) and (one delete_item) function in view.
I don't know how to make the delete (column in this table) and pass the model to the delete_item function in the view
Tables.py
############ Abstract Table
class abs_Table(tables.Table):
SN = tables.Column(empty_values=(), orderable=False)
delete = tables.LinkColumn('delete_item', args=[A('pk'), ?????Model???], attrs={
'a': {'class': 'btn btn-small btn-dark'}
# })
def __init__(self, *args, **kwargs):
super(abs_Table, self).__init__(*args, **kwargs)
self.counter = itertools.count(1)
def render_SN(self, record):
pg = getattr(self, 'paginator', None)
if pg:
v = next(self.counter)
return v + self.paginator.per_page * (self.page.number-1)
else:
return next(self.counter)
class Meta:
model = None
fields = [ 'SN', 'id', 'delete', ]
attrs = {"class": "table-striped table-bordered", 'width': '100%'}
empty_text = "There are no Records matching the search criteria..."
Then for model Table
Tables.py
class ModelTable(abs_Table):
class Meta(abs_Table.Meta):
model = modelname
fields = abs_Table.Meta.fields+[selected_model_fields]
Views.py
def delete_item(request, pk, delmodel):
obj = get_object_or_404(delmodel, id=pk)
if request.method == "POST":
obj.delete()
return redirect("../")
else:
pass
context = {
'object': obj
}
return render(request, '/delete_confirmation.html', context)
For the Views part. It works for me after passing the model as string and then using apps.get_model to change it into a model.
views.py`
from django.apps import apps
def delete_item(request, pk, delmodel):
DeleteModel = apps.get_model("Myapp", delmodel)
obj = get_object_or_404(DeleteModel, id=pk)
if request.method == "POST":
obj.delete()
return redirect("../")
else:
pass
context = {
'object': obj
}
return render(request, '/delete_confirmation.html', context)
Still the confirmation is not handled correctly and the delete column in tables need to be improved.

Сreate a full copy of the object from UpdateView or from ListView in Django

I have Class Based views for my models. I want to create a full copy of the object and go to editing it. I would like to do this from UpdateView with a special button for copying, but it is a good option from the list of objects. How can I do this? Below is the code for one of the models.
My CreateView:
class CreateDealView(
CustomSuccessMessageDeal,
CustomPermissionRequired,
CreateView
):
model = Deal
template_name = 'db_visual/create_deal.html'
form_class = DealForm
permission_required = (
'db_visual.add_deal',
)
success_message = "Сделка %(pk)s успешно создана!"
def get_success_url(self):
url_kwargs = {'deal_id': self.object.id}
url_name = 'update_deal'
return reverse_lazy(url_name, kwargs=url_kwargs)
My UpdateView:
class UpdateDealView(
CustomSuccessMessageDeal,
CustomPermissionRequired,
UpdateView
):
model = Deal
pk_url_kwarg = 'deal_id'
template_name = 'db_visual/update_deal.html'
form_class = DealForm
success_message = "Сделка <a href='%(url)s'>%(id)s</a> " \
"успешно изменена!"
def get_success_url(self):
url_name = 'deals'
return reverse_lazy(url_name)
def get_success_message(self, cleaned_data):
return self.success_message % dict(
cleaned_data,
id=self.object.id,
url=reverse_lazy(
'update_deal',
kwargs={
'deal_id': self.object.id,
}
),
)
UPD: I wrote a view for create copy by id, but when I try redirect to UpdateView I get error:
My view:
def copy_deal(request, deal_id):
new_deal = Deal.objects.get(pk=deal_id)
new_deal.pk = None
new_deal.save()
return reverse_lazy(
'update_deal',
kwargs={'deal_id': new_deal.pk}
)
What's wrong with my reverse?
I changed
return reverse_lazy(
'update_deal',
kwargs={'deal_id': new_deal.pk}
) to
return HttpResponseRedirect(reverse(
'update_deal',
kwargs={'deal_id': new_deal.pk}
))

How can i render templates on the basis of conditions in django DetailView

I have tried overriding get_templates_name().But it is not helping me out.
def get_template_names(self):
theme = Themes.objects.filter(theme_creator=self.request.user)
for t in theme:
if t.technology_theme == True:
return ["landing/preview/preview1.html/"]
elif t.default_theme == True:
return ["landing/categories/technology/technology1.html/"]
Initialize a variable like
if t.technology_theme == True:
template_name = "landing/preview/preview1.html"
elif t.default_theme == True:
template_name = "landing/categories/technology/technology1.html"
and return template_name form your view like
In CBV:
template_name=template_name
In FBV:
retrun render(request, template_name, context)
Inside get_object(), or get_context_data(), you can define the template name like this:
def get_context_data(self, **kwargs):
context = super(YourView, self).get_context_data(**kwargs)
self.template_name = 'your_template.html'
return context