Newby in django, have two question, can't find needed info.
1) I have database (SQLite) which have table scale_calibration and field weight. Other application rewrite value in field weight 1-2 times per second. Is there possibility in Django to renew this field without renew browser (F5)?
models.py:
from django.db import models
class Calibration(models.Model):
mean_weight = models.FloatField(editable=True)
hours_to_export = models.PositiveIntegerField(default=4, editable=True)
weight = models.FloatField(editable=True)
admin.py:
from django.contrib import admin
from .models import Calibration
# Register your models here.
admin.site.register(Calibration)
2) I try follow that link to make easy calculated field (that will be write to database when save), but i have no results and no error, don't understand where i did mistake.
models.py:
from django.db import models
class Calibration(models.Model):
mean_weight = models.FloatField(editable=True)
hours_to_export = models.PositiveIntegerField(default=4, editable=True)
weight = models.FloatField(editable=True)
calibration_factor = models.FloatField(editable=True)
#property
def get_calibration(self):
return self.weight/self.mean_weight
def save(self, *args, **kwarg):
self.calibration_factor = self.get_calibration()
super(Calibration, self).save(*args, **kwarg)
Please help with advise.
As #david-alford mention, AJAX is a good solution to your problem. This simply writing JavaScript in your templates that make a request every n seconds and update your webpage, also you will need a new endpoint in your Django app that provides the update values from your model to this requests to be repeated.
If this sounds weird or complicated, take a look at some AJAX examples with Django, and feel free to ask more specific questions for clarifications.
Related
I'm new to Django and I'm trying to make an application that registers the attendance of entrepreneurs (I'm currently working on this). There are some services that I would like to select, sometimes the same person requires more than one service per appointment. However, part of the application uses the Models and part uses the Forms, I'd like to keep the two ones separate to keep the code organized, but I have no idea how to do it, I even created a separate class just for the tuple that holds the values, but no I managed to implement, can anyone help me? Here are the codes:
models.py
from django.db import models
from django_cpf_cnpj.fields import CPFField, CNPJField
class CadastroEmpreendedor(models.Model):
ABERTURA = 'ABERTURA MEI'
ALTERACAO = 'ALTERAÇÃO CADASTRAL'
INFO = 'INFORMAÇÕES'
DAS = 'EMISSÃO DAS'
PARC = 'PARCELAMENTO'
EMISSAO_PARC = 'EMISSÃO DE PARCELA'
CODIGO = 'CÓDIGO DE ACESSO'
REGULARIZE = 'REGULARIZE'
BAIXA = 'BAIXA MEI'
CANCELADO = 'REGISTRO BAIXADO'
descricao_atendimento = (
(ABERTURA, 'FORMALIZAÇÃO'),
(ALTERACAO, 'ALTERAÇÃO CADASTRAL'),
(INFO, 'INFORMAÇÕES'),
(DAS, 'EMISSÃO DAS'),
(PARC, 'PARCELAMENTO'),
(EMISSAO_PARC, 'EMISSÃO DE PARCELA'),
(CODIGO, 'CÓDIGO DE ACESSO'),
(REGULARIZE, 'REGULARIZE'),
(BAIXA, 'BAIXA MEI'),
(CANCELADO, 'REGISTRO BAIXADO'),
)
cnpj = CNPJField('CNPJ')
cpf = CPFField('CPF')
nome = models.CharField('Nome', max_length=120)
nascimento = models.DateField()
email = models.EmailField('Email', max_length=100)
telefone_principal = models.CharField(max_length=11)
telefone_alternativo = models.CharField(max_length=11, blank=True)
descricao_atendimento
def __str__(self) -> str:
return self.nome
class DescricaoAtendimento(models.Model):
descricao = models.ForeignKey(CadastroEmpreendedor, on_delete=models.CASCADE)
forms.py
from django import forms
from .models import DescricaoAtendimento
class EmpreendedorForm(forms.ModelForm):
class Meta:
model = DescricaoAtendimento
fields = ['descricao']
widgets = {'descricao': forms.CheckboxSelectMultiple(),}
views.py
from django.shortcuts import render
from django.contrib import messages
from .forms import EmpreendedorForm
def cadastro_empreendedor(request):
if str(request.method) == 'POST':
form = EmpreendedorForm(request.POST, request.FILES)
if form.is_valid():
form.save()
messages.success(request, 'Produto salvo com sucesso!')
form = EmpreendedorForm()
else:
messages.success(request, 'Erro ao salvar produto!')
else:
form = EmpreendedorForm()
context = {
'form': form
}
return render(request, 'empreendedor.html', context)
If you have any tips, I really appreciate it, I started with Django almost a month ago, so there's a long way to go.
P.S.: I integrated with PostgreSQL and in the Django administration part I can save all the fields in the DB, but I can't implement that part of the checkbox.
At this moment, I get the error:
It is impossible to add a non-nullable field 'descricao' to descricaoatendimento without specifying a default. This is because the database needs something to populate existing rows.
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
2) Quit and manually define a default value in models.py.
In the template, I gonna work with bootstrap4 to create the forms. But I'd like to resolve this before. I'm still learning English, so sorry for some mistakes.
It sounds like you have many Entrepreneurs, each of which can choose many Services. This is a ManyToMany Relationship and you can create it in Django by having one model for each and creating the link between them like this
class CadastroEmpreendedor(models.Model):
...
descricao_atendimento = models.ManyToManyField(DescricaoAtendimento)
class DescricaoAtendimento(models.Model):
nome = models.CharField('Nome', max_length=120, default="unnamed service")
In this case, every object/row in DescricaoAtendimento is a service. Each entrepeneur can have many services associated with them.
This way you don't need to create a model form for DescricaoAtendimento to choose services for an entrepeneur. As it's linked to them by a manytomany relationship you can have an CadastroEmpreendedor model form with just the escricao_atendimento field and the various services become available as options.
Django handles this by creating a 'through table' which is basically a table with two fields of foreign keys, one pointing to an entrepeneur, and the other to a service. You can also create this table yourself as a through table - which is useful if you want to extend data about the relationship - eg, a begin and end date for the entrepeneur's use of a service.
The error you are getting when you migrate isn't an error, per se. It seems you created an number of DescricaoAtendimento objects and then added the descricao field later. When you then try and migrate, django wants you to provide a default value for the already existing rows, or allow the field to be empty (via blank=True in the model). You can assign a dummy value and then go back and change it in /admin later, or, if you don't have a lot of data, recreate your database and remigrate. Above I've used a default value to avoid this situation.
However, if you are dead set against extra tables, you might want to look at an extension like django multiselectfield
Lets say I have a model:
class Applicant(models.Model):
name = models.CharField()
status = Models.CharField(choices=Choices)
Lets say Choices gives the choices of Reviewed, Rejected, Accepted.
I want to be able to declare a choice for an instance in the admin panel, and once I save the choice, the instance is moved to another section, preferably another admin folder such as Reviewed Applicants, Rejected Applicant, etc etc.
Whats the best way to achieve this?
Thank you
Quoted from This, This should solve your problem
from django.shortcuts import redirect
class PaymentAdmin(VersionAdmin, admin.ModelAdmin):
def response_add(self, request, obj, post_url_continue=None):
return redirect('/admin/sales/invoice')
def response_change(self, request, obj):
return redirect('/admin/sales/invoice')
and here're the official doc links
I couldn't find an answer to the following question, it took me a couple of hours to find out, hence I'm adding it. I'll add my approach of solving it and the answer.
I'm following a YouTube tutorial from This person. For some reason I'm typing the same code, and I checked every single letter. Yet for some reason my cleaning functions aren't called. It's probably something simple, especially since a related question showed something similar. It's probably a framework thing that I get wrong, but I wouldn't know what it is.
Here is the relevant code.
forms.py (complete copy/paste from his Github)
from django import forms
from .models import SignUp
class ContactForm(forms.Form):
full_name = forms.CharField(required=False)
email = forms.EmailField()
message = forms.CharField()
class SignUpForm(forms.ModelForm):
class Meta:
model = SignUp
fields = ['full_name', 'email']
### exclude = ['full_name']
def clean_email(self):
email = self.cleaned_data.get('email')
email_base, provider = email.split("#")
domain, extension = provider.split('.')
# if not domain == 'USC':
# raise forms.ValidationError("Please make sure you use your USC email.")
if not extension == "edu":
raise forms.ValidationError("Please use a valid .EDU email address")
return email
# Final part is ommited, since it's not relevant.
admin.py (typed over from the tutorial)
from django.contrib import admin
# Register your models here.
from .models import SignUp
from .forms import SignUpForm
class SignUpAdmin(admin.ModelAdmin):
list_display = ['__unicode__', 'timestamp', 'updated']
class Meta:
model = SignUp
form = SignUpForm
admin.site.register(SignUp, SignUpAdmin)
After using print statements for a while and reading questions that seemed similar but eventually didn't solve my problem, I decided to look into the source of Django (idea inspired by the most similar question I could find).
Then, I decided to debug the source, since I wanted to know how Django is treating my customized function (thanks to a tutorial + SO answer). In the source I found that the customized functions were called around return super(EmailField, self).clean(value) (line 585, django/forms/fields.py, Django 1.8). When I was stepping through the code I found the critical line if hasattr(self, 'clean_%s' % name): (line 409, django/forms/forms.py, Django 1.8). I checked for the value name which was "email". Yet, the if-statement evaluated as False ((Pdb) p hasattr(self, 'clean_%s' % name)). I didn't understand why, until I figured out that the function name was not registered ((Pdb) pp dir(self)).
I decided to take a look at the whole source code repository and cross-checked every file and then I found that
class Meta:
model = SignUp
form = SignUpForm
means that form / SignUpForm were nested inside the Meta class. At first, I didn't think much of it but slowly I started to realize that it should be outside the Meta class while staying main class (SignUpAdmin).
So form = SignUpForm should have been idented one tab back. For me, as a Django beginner, it still kind of baffles me, because I thought the Meta class was supposed to encapsulate both types of data (models and forms). Apparently it shouldn't, that's what I got wrong.
I'm becoming increasingly bewildered by the range of answers on offer to the seemingly simple problem of adding custom fields to the django-registration register form/flow. This should be a default, documented aspect of the package (not to sound ungrateful, just that it is such a well-equipped package), but solutions to the problem are dizzying.
Can anyone give me the most simple solution to getting UserProfile model data included in the default registration register page?
Update:
I eventually used Django Registration's own signals to give me this hacky fix. It is particularly ugly because, I had to use try on the POST attribute dealing with my Boolean since I found that the checkbox returned nothing if left empty.
Would appreciate any advice on improving this, or best practice.
My app / models.py
from registration.signals import user_registered
from django.dispatch import receiver
class UserProfile(models.Model):
user = models.OneToOneField(User)
event_commitments = models.ManyToManyField(Event, null=True, blank=True)
receive_email = models.BooleanField(default=True)
#receiver(user_registered)
def registration_active_receive_email(sender, user, request, **kwargs):
user_id = user.userprofile.id
user = UserProfile.objects.get(pk=user_id)
try:
if request.POST['receive_email']:
pass
except:
user.receive_email = False
user.save()
Registration app / forms.py
class RegistrationForm(forms.Form):
# default fields here, followed by my custom field below
receive_email = forms.BooleanField(initial=True, required=False)
Thanks
What you have looks like a workable approach.
I've looked through the django-registration code, and based on the following comments in the register view I've come up with another solution. I'm not totally sure this is cleaner, but if you aren't a fan of signals this is good. This also provides a much easier avenue if you intend to make more customizations.
# from registration.views.register:
"""
...
2. The form to use for account registration will be obtained by
calling the backend's ``get_form_class()`` method, passing the
``HttpRequest``. To override this, see the list of optional
arguments for this view (below).
3. If valid, the form's ``cleaned_data`` will be passed (as
keyword arguments, and along with the ``HttpRequest``) to the
backend's ``register()`` method, which should return the new
``User`` object.
...
"""
You could create a custom backend and override those mentioned methods:
# extend the provided form to get those fields and the validation for free
class CustomRegistrationForm(registration.forms.RegistrationForm):
receive_email = forms.BooleanField(initial=True, required=False)
# again, extend the default backend to get most of the functionality for free
class RegistrationBackend(registration.backends.default.DefaultBackend):
# provide your custom form to the registration view
def get_form_class(self, request):
return CustomRegistrationForm
# replace what you're doing in the signal handler here
def register(self, request, **kwargs):
new_user = super(RegistrationBackend, self).register(request, **kwargs)
# do your profile stuff here
# the form's cleaned_data is available as kwargs to this method
profile = new_user.userprofile
# use .get as a more concise alternative to try/except around [] access
profile.receive_email = kwargs.get('receive_email', False)
profile.save()
return new_user
To use the custom backend, you can then provide separate urls. Before including the default urls, write 2 confs that point at your custom backend. Urls are tested in the order defined, so if you define these two before including the defaults, these two will capture before the default ones are tested.
url(r'^accounts/activate/(?P<activation_key>\w+)/$',
activate,
{'backend': 'my.app.RegistrationBackend'},
name='registration_activate'),
url(r'^accounts/register/$',
register,
{'backend': 'my.app.RegistrationBackend'},
name='registration_register'),
url(r'^accounts/', include('registration.backends.default.urls')),
The docs actually describe all this, but they aren't particularly accessible (no readthedocs). They are all included in the project, and I was browsing them here.
I eventually used Django Registration's own signals to give me this fix.
I will clean up the try/except flow at some point. dokkaebi also points out above that I might be able to assess the request.GET parameters for when a checkbox is left empty.
My app / models.py
from registration.signals import user_registered
from django.dispatch import receiver
class UserProfile(models.Model):
user = models.OneToOneField(User)
event_commitments = models.ManyToManyField(Event, null=True, blank=True)
receive_email = models.BooleanField(default=True)
#receiver(user_registered)
def registration_active_receive_email(sender, user, request, **kwargs):
user_id = user.userprofile.id
user = UserProfile.objects.get(pk=user_id)
try:
if request.POST['receive_email']:
pass
except:
user.receive_email = False
user.save()
Registration app / forms.py
class RegistrationForm(forms.Form):
# default fields here, followed by my custom field below
receive_email = forms.BooleanField(initial=True, required=False)
I have several Customers who book Appointments. Each Appointment has exactly one customer, though a customer can be booked for multiple appointments occurring at different times.
class Customer(model.Model):
def __unicode__(self):
return u'%s' % (self.name,)
name = models.CharField(max_length=30)
# and about ten other fields I'd like to see from the admin view.
class Appointment(models.Model):
datetime = models.DateTimeField()
customer = models.ForeignKey("Customer")
class Meta:
ordering = ('datetime',)
Now when an admin goes to browse through the schedule by looking at the Appointments (ordered by time) in the admin, sometimes they want to see information about the customer who has a certain appointment. Right now, they'd have to remember the customer's name, navigate from the Appointment to the Customer admin page, find the remembered Customer, and only then could browse their information.
Ideally something like an admin inline would be great. However, I can only seem to make a CustomerInline on the Appointment admin page if Customer had a ForeignKey("Appointment"). (Django specifically gives me an error saying Customer has no ForeignKey to Appointment). Does anyone know of a similar functionality, but when Appointment has a ForeignKey('Customer')?
Note: I simplified the models; the actual Customer field currently has about ~10 fields besides the name (some free text), so it would be impractical to put all the information in the __unicode__.
There is no easy way to do this with django. The inlines are designed to follow relationships backwards.
Potentially the best substitute would be to provide a link to the user object. In the list view this is pretty trivial:
Add a method to your appointment model like:
def customer_admin_link(self):
return 'Customer' % reverse('admin:app_label_customer_change %s') % self.id
customer_admin_link.allow_tags = True
customer_admin_link.short_description = 'Customer'
Then in your ModelAdmin add:
list_display = (..., 'customer_admin_link', ...)
Another solution to get exactly what you're looking for at the cost of being a bit more complex would be to define a custom admin template. If you do that you can basically do anything. Here is a guide I've used before to explain:
http://www.unessa.net/en/hoyci/2006/12/custom-admin-templates/
Basically copy the change form from the django source and add code to display the customer information.
Completing #John's answer from above - define what you would like to see on the your changelist:
return '%s' % (
reverse('admin:applabel_customer_change', (self.customer.id,)),
self.customer.name # add more stuff here
)
And to add this to the change form, see: Add custom html between two model fields in Django admin's change_form
In the ModelAdmin class for your Appointments, you should declare the following method:
class MySuperModelAdmin(admin.ModelAdmin):
def get_form(self, request, obj=None, **kwargs):
if obj:
# create your own model admin instance here, because you will have the Customer's
# id so you know which instance to fetch
# something like the following
inline_instance = MyModelAdminInline(self.model, self.admin_site)
self.inline_instances = [inline_instance]
return super(MySuperModelAdmin, self).get_form(request, obj, **kwargs)
For more information, browser the source for that function to give you an idea of what you will have access to.
https://code.djangoproject.com/browser/django/trunk/django/contrib/admin/options.py#L423
There is a library you can use it.
https://github.com/daniyalzade/django_reverse_admin
But if you want to use link to object in showing table you can like this code:
def customer_link(self, obj):
if obj.customer:
reverse_link = 'admin:%s_%s_change' % (
obj.customer._meta.app_label, obj.customer._meta.model_name)
link = reverse(reverse_link, args=[obj.customer.id])
return format_html('More detail' % link)
return format_html('<span >-</span>')
customer_link.allow_tags = True
customer_link.short_description = 'Customer Info'
And in list_display:
list_display = (...,customer_link,...)