I have problems with views - django

I have this models:
Class Category(models.Model):
name = models.CharField(max_length=150, unique=True)
description = models.CharField(max_length=250)
def get_absolute_url(self):
return reverse('categories_url', args=[str(self.id)])
class Company(models.Model):
name = models.CharField(max_length=150, unique=True)
country = models.CharField(max_length=50)
class Motobike(models.Model):
name = models.CharField(max_length=150)
company = models.ForeignKey('Company', on_delete=models.CASCADE)
category = models.ForeignKey('Category', on_delete=models.CASCADE)
def get_absolute_url(self):
return reverse('details_url', args=[str(self.id)])
And views:
class CategoryView(DetailView):
model = Motobike
template_name = 'bikes_site/categories_detail.html'
pk_url_kwarg = 'pk'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
category = self.get_object()
context['motobikes'] = Motobike.objects.filter(category_id=category.pk)
return context
And test:
def test_category(setup):
client = Client()
category_id = Category.objects.get(name='Мотоциклы').id
response = client.get(f'/categories/{category_id}/')
assert response.status_code == 200
response_data = json.loads(response.content.decode('utf-8'))
assert len(response_data) == 2
assert response_data[1]['name'] == 'Ninja Turbo'
assert response_data[1]['vendor'] == 'Kawasaki'
assert response_data[1]['category'] == 'Мотоциклы'
assert response_data[1]['description'] == ''
response = client.get(f'/categories/25/')
assert response.status_code == 404
I need to present all thin in JSON, through JsonResponce, and what should almost go to the meaning of the dictonary, did i create them correctly?

You should do something like in your view:
from django.http import JsonResponse
class CategoryView(DetailView):
model = Motobike
template_name = 'bikes_site/categories_detail.html'
pk_url_kwarg = 'pk'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
category = self.get_object()
context['motobikes'] = Motobike.objects.filter(category_id=category.pk)
return JsonResponse(context, status=200) # or wahtever status is appropriate
Note: Haven't tested it, but that's what I use with GenericAPIView

Related

Django UpdateView Two Seperate Form Save (included inlineformset_factory)

I have a specific problem with my forms. I think it would be better to share my codes instead of explaining the problem in detail.
However, to explain in a nutshell; inside my model I have field OneToOneField and model of that field has inlineformset_factory form. My new model also has a form and I want to save both forms.
I get the following error when I want to save the offer update form:
TypeError at /ru/mytarget/offer-update/T2GTTT053E9/
AdminOfferUpdateView.form_invalid() missing 2 required positional arguments: 'request_form' and 'request_item_formset'
Models:
request.py
class RequestModel(models.Model):
customer = models.ForeignKey(Customer, on_delete=models.CASCADE, related_name="customer_requests")
id = ShortUUIDField(primary_key=True, length=10, max_length=10, prefix="T", alphabet="ARGET0123456789", unique=True, editable=False)
status = models.BooleanField(default=True)
request_title = models.CharField(max_length=300)
......
updated_on = models.DateTimeField(auto_now=True)
published_date = models.DateTimeField(default=timezone.now)
def __str__(self):
return str(self.request_title)
class Meta:
verbose_name_plural = "Requests"
verbose_name = "Request"
def get_absolute_url(self):
return reverse('mytarget:customer_request_details', kwargs={'pk': self.id})
class RequestItem(models.Model):
request_model = models.ForeignKey(RequestModel, on_delete=models.CASCADE, related_name="request_items")
product_name = models.CharField(max_length=300)
......
offer.py
class OfferModel(models.Model):
request_model_name = models.OneToOneField(RequestModel, on_delete=models.CASCADE, primary_key=True)
status = models.BooleanField(default=True)
offer_validity = models.CharField(max_length=50, blank=True)
......
updated_on = models.DateTimeField(auto_now=True)
published_date = models.DateTimeField(default=timezone.now)
def __str__(self):
return str(self.request_model_name)
class Meta:
verbose_name_plural = "Offers"
verbose_name = "Offer"
def get_absolute_url(self):
return reverse('mytarget:admin_offer_update', kwargs={'pk': self.request_model_name})
Forms:
request_create_form.py
class CustomerRequestForm(forms.ModelForm):
disabled_fields = ("customer",)
class Meta:
model = RequestModel
fields = ("customer", "request_title", "delivery_time", "shipping_country", "shipping_address",
"preferred_currency", "shipping_term", "delivery_term")
widgets = {
'request_title': TextInput(attrs={'class': 'form-control tableFormInputs',
'placeholder': _('Example: Printers, Toner, and Cartridges')}),
......
}
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('customer')
super(CustomerRequestForm, self).__init__(*args, **kwargs)
self.fields['preferred_currency'].queryset = self.fields['preferred_currency'].queryset.translated().order_by("translations__currency_name")
self.fields['shipping_term'].queryset = self.fields['shipping_term'].queryset.translated().order_by("translations__shipping_term")
for field in self.disabled_fields:
self.fields[field].widget = forms.HiddenInput()
self.fields[field].disabled = True
class CustomerRequestItemForm(forms.ModelForm):
class Meta:
model = RequestItem
fields = ("product_name", "product_info", "target_price", "price", "quantity", "dimensions", "net_weight", "gross_weight",
"hs_or_tn_ved_code", "brand", "manufacturer", "origin_country", "manufacturer_address")
exclude = ()
widgets = {
'product_name': TextInput(attrs={'class': 'form-control tableFormInputs'}),
......
}
RequestItemInlineFormset = inlineformset_factory(RequestModel, RequestItem,
form=CustomerRequestItemForm,
extra=1,
can_delete=True
)
offer_update_form.py
class AdminOfferUpdateForm(forms.ModelForm):
disabled_fields = ()
hidden_fields = ("request_model_name",)
request_title = forms.CharField(required=False, widget=TextInput(attrs={'class': 'form-control tableFormInputs', 'placeholder': _('Example: Printers, Toner, and Cartridges')}))
......
class Meta:
model = OfferModel
fields = ("request_model_name", "offer_validity", ......
)
widgets = {'offer_validity': TextInput(attrs={'class': 'form-control tableFormInputs'}),
......
'is_detailed_offer': CheckboxInput(attrs={'class': 'form-check-input'}),
}
def __init__(self, *args, **kwargs):
super(AdminOfferUpdateForm, self).__init__(*args, **kwargs)
self.fields["preferred_currency"].choices = [(c.id, c.currency_name) for c in Currency.objects.all()]
self.fields["shipping_term"].choices = [(st.id, st.shipping_term) for st in ShippingTerm.objects.all()]
self.fields["delivery_term"].choices = [(dt.id, dt.delivery_term) for dt in DeliveryTerms.objects.all()]
self.fields["request_statuses"].choices = [(r.id, r.status) for r in RequestStatus.objects.all()]
for field in self.disabled_fields:
self.fields[field].disabled = True
for field in self.hidden_fields:
self.fields[field].widget = forms.HiddenInput()
Views:
offer_update_view.py
#method_decorator([login_required(login_url=reverse_lazy("accounts:signin")), user_is_superuser], name='dispatch')
class AdminOfferUpdateView(UpdateView):
model = OfferModel
form_class = AdminOfferUpdateForm
template_name = "mytarget/admin_offer_update.html"
def get_context_data(self, **kwargs):
context = super(AdminOfferUpdateView, self).get_context_data(**kwargs)
if self.request.POST:
context['request_form'] = AdminOfferUpdateForm(self.request.POST, instance=self.object.request_model_name)
context['request_item_formset'] = RequestItemInlineFormset(self.request.POST, instance=self.object.request_model_name)
else:
context['request_form'] = AdminOfferUpdateForm(instance=self.object.request_model_name)
context['request_item_formset'] = RequestItemInlineFormset(instance=self.object.request_model_name)
return context
def form_valid(self, form):
context = self.get_context_data()
request_form = context['request_form']
request_item_formset = context['request_item_formset']
with transaction.atomic():
self.object = form.save()
if request_form.is_valid() and request_item_formset.is_valid():
request_form.instance = self.object.request_model_name
request_form.save()
request_item_formset.instance = self.object.request_model_name
request_item_formset.save(commit=False)
for ri in request_item_formset:
ri.save(commit=False)
request_item_formset.save()
return super(AdminOfferUpdateView, self).form_valid(form)
def form_invalid(self, form, request_form, request_item_formset):
return self.render_to_response(
self.get_context_data(form=form, request_form=request_form, request_item_formset=request_item_formset)
)
def get_initial(self):
self.object = self.get_object()
if self.object:
return {"request_model": self.object.request_model_name, "request_item_formset": self.object.request_model_name}
return super().initial.copy()
def get_success_url(self):
return reverse('mytarget:admin_offer_update', kwargs={'pk': self.object.id})
I solved my problem. I created a button function that creates a new model with inheritance of other model fields. In this way, there is no need to edit the form of the other model inside the form of my current model.

Django CustomUser Function

I created a CustomUser as follows, however, I am not able to use the CustomUser functions in Views as I get the error message "get_first_name() missing 1 required positional argument: 'self'" when I call CustomUser.get_first_name().
I checked my settings.py and do import CustomUser, models as well as settings in the view file.
If you could help me here that would be awesome.
models.py
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(verbose_name='email', unique=True)
first_name = models.CharField(verbose_name='first_name', max_length = 15)
last_name = models.CharField(verbose_name='last_name', max_length = 15)
organization = models.CharField(verbose_name="organization", max_length = 15, choices=ORGANIZATIONS)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True) # check this for login email purposes
date_joined = models.DateTimeField(default=timezone.now)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name', 'last_name', 'organization']
objects = CustomUserManager()
def get_full_name(self):
'''
Returns the first_name plus the last_name, with a space in between.
'''
full_name = '%s %s' % (self.first_name, self.last_name)
return full_name.strip()
def get_short_name(self):
'''
Returns the short name for the user.
'''
return self.first_name
def __str__(self):
return self.email
def get_organization(self):
return self.organization
def get_first_name(self):
return self.first_name
def get_email(self):
return self.email
views.py
class Dashboard(LoginRequiredMixin, TemplateView):
template_name = "plot.html"
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super(Dashboard, self).get_context_data(**kwargs)
context['plot'] = plots.plotsurvey()
return context
plots.py
def plotsurvey():
c = CustomUser()
name = c.get_first_name()
df = pd.read_csv(str(name) +'.csv') #
trace = go.Bar(
x = df['Y'],
y = df['Z'], name = 'N'
)
data = [trace]
layout = go.Layout(title="X", margin = dict(b = 150))
fig = go.Figure(data=data, layout=layout)
plot_div = plot(fig, output_type='div', include_plotlyjs=False)
#logger.info("Plotting number of points {}.".format(3))
return plot_div
You are using an instance method, as if it were a class method.
You need to change, this
def plotsurvey():
c = CustomUser()
name = CustomUser.get_first_name()
...
To this (use the instance)
def plotsurvey():
c = CustomUser()
name = c.get_first_name()
...
Note that you have another problem here. You are not actually getting any real user with c = CustomUser(). To get a user, you would need to do something like
CustomUser.objects.get(pk=user_id)
In that case, you finally get:
def plotsurvey(user_id):
c = CustomUser.objects.get(pk=user_id)
name = c.get_first_name()
...
EDIT
We can be more practical, using the view.
class Dashboard(LoginRequiredMixin, TemplateView):
template_name = "plot.html"
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super(Dashboard, self).get_context_data(**kwargs)
user = self.request.user
context['plot'] = plots.plotsurvey(user.pk)
return context
You can use request object
request.user.get_first_name()

How to get access to different models in the template?

I have 3 models
Do I need to change connections in the models, and make the key field not an id, but a name?
class Category(models.Model):
name = models.CharField(max_length=150, unique=True)
description = models.CharField(max_length=250)
class Company(models.Model):
name = models.CharField(max_length=150, unique=True)
country = models.CharField(max_length=50)
class Motobike(models.Model):
name = models.CharField(max_length=150)
company = models.ForeignKey('Company', on_delete=models.CASCADE)
category = models.ForeignKey('Category', on_delete=models.CASCADE)
And tests:
def test_category(setup):
client = Client()
category_id = Category.objects.get(name='Мотоциклы').id
response = client.get(f'/categories/{category_id}/')
assert response.status_code == 200
response_data = json.loads(response.content.decode('utf-8'))
assert len(response_data) == 2
assert response_data[1]['name'] == 'Ninja Turbo'
assert response_data[1]['vendor'] == 'Kawasaki'
assert response_data[1]['category'] == 'Мотоциклы'
assert response_data[1]['description'] == ''
response = client.get(f'/categories/25/')
assert response.status_code == 404
In view I do so:
class CategoryView(DetailView):
model = Category
template_name = 'bikes_site/categories_detail.html'
def get_context_data(self, id, **kwargs):
context = get_object_or_404(self.model, id)
context['motobikes'] = Motobike.objects.filter(category_id=id).all()
return context
I get an error:
get_context_data() missing 1 required positional argument: 'id'
The function signature for get_context_data is wrong it should be
def get_context_data(self, **kwargs):
//todo
your detail view should like this
class CategoryView(DetailView):
model = Category
template_name = 'bikes_site/categories_detail.html'
pk_url_kwarg = "id"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
category = self.get_object()
context['motobikes'] = Motobike.objects.filter(category_id=category.pk)
return context

not enough values to unpack (expected 2, got 1)

I have a problem with a queryset in one view. My idea is show all users who are not registered in a program, I put here the models:
models.py
class UCAUser(AbstractUser):
dni_cif=models.CharField(
max_length=9,
blank=True,
verbose_name="DNI/CIF"
)
class InscripcionRealizada(models.Model):
formulario = models.ForeignKey(Formulario)
inscrito = models.ForeignKey(UCAUser,related_name="inscripciones_realizadas")
fecha_registro = models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name = "Inscripción realizada"
verbose_name_plural = "Inscripciones realizadas"
def __str__(self):
return "{} - {} - {}".format(self.formulario.programa, self.formulario.edicion, self.inscrito)
You can see UCAUser and InscripcionRealizada are connected by InscripcionRealizada.inscrito field.
view.py
class InscribirUsuariosListView(ListView):
template_name = "inscripciones/InscribirUsuariolist.html"
model = UCAUser
group_required = ['Administrador']
login_url = "auth-login"
def get_queryset(self):
qs = super(InscribirUsuariosListView, self).get_queryset()
return qs.filter(UCAUser.objects.filter(inscripciones_realizadas__formulario!=self.kwargs['formulario_id']))
def get_context_data(self, **kwargs):
context = super(InscribirUsuariosListView, self).get_context_data(**kwargs)
context['formulario_id'] = self.kwargs['formulario_id']
return context
When I try this, I get an error:
not enough values to unpack (expected 2, got 1)
Any idea?

form.is_valid method keeps failing

I'm trying to make an editing page for the users to update an object data. However, form.is_valid() keeps failing, I have no idea why.
My model:
class Thread(models.Model):
title = models.CharField(max_length=200)
created = models.DateTimeField(auto_now_add=True)
creator = models.ForeignKey(User, blank=True, null=True)
body = models.TextField(max_length=10000)
USER_TYPES = (
('INI','Iniciante'),
('INT','Intermediário'),
('AVA','Avançado')
)
user_type = models.CharField(max_length=20, choices = USER_TYPES, default='INI')
category = models.ForeignKey(Category)
orcamento = models.IntegerField(default=0)
slug = models.SlugField(max_length=40, unique=True)
def get_absolute_url(self):
return "/%s/" % self.slug
def __str__(self):
return self.title
def save(self, **kwargs):
slug_str = "%s %s" % (self.category, self.title)
unique_slugify(self, slug_str)
super(Thread, self).save(**kwargs)
My view:
def edit_thread(request, thread_slug):
thread = Thread.objects.get(slug=thread_slug)
if request.method == 'POST':
form = EditThread(request.POST)
if form.is_valid():
thread.title = form.cleaned_data['title']
thread.orcamento = form.cleaned_data['orcamento']
thread.user_type = form.cleaned_data['experiencia']
thread.body = form.cleaned_data['pergunta']
thread.save()
return HttpResponseRedirect('/thread' + thread.get_absolute_url())
else:
data = {'title' : thread.title, 'experiencia':thread.user_type, 'orcamento' : thread.orcamento, 'pergunta': thread.body}
form = EditThread(initial=data)
return render(request, 'edit_thread.html', {
'form': form })
My form:
class EditThread(forms.ModelForm):
title = forms.CharField(label='Título', max_length=200, error_messages=my_default_errors)
orcamento = forms.IntegerField(label='Preço máximo', error_messages=my_default_errors)
experiencia = forms.ChoiceField(label='Você é um usuário...', choices=Thread.USER_TYPES, error_messages=my_default_errors)
pergunta = forms.CharField(label='Pergunta', widget=forms.Textarea, error_messages=my_default_errors)
class Meta:
model = Thread
def __init__(self, *args, **kwargs):
super(EditThread, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.layout = Layout(
Div('title',
'experiencia',
PrependedAppendedText('orcamento', 'R$', ',00', active=True),
'pergunta',
FormActions(
Submit('save', 'Salvar alterações'),
)))
When accessing the page, the form gets pre-populated with the object's data as it should.
Your form should be inherited from the simple forms.Form instead of the forms.ModelForm:
class EditThread(forms.Form):
...
I would suggest you look at django's class based UpdateView. It can generate an update form for you or you could give it a custom ModelForm by overriding the form_class attribute on your view. When using a ModelForm, you also have to specify which model the form is for eg:
class EditThread(forms.ModelForm):
"field definitions ..."
class Meta:
model = Thread
fields = ['my_field_1', 'my_field_2']