I have a question about a ForeignKey reference problem with django.
This is a part of my code :
App ticketsTrader
class TicketsTrader(models.Model):
seller = models.ForeignKey(User, related_name='ticketsTrader_seller')
buyer = models.ForeignKey(User, related_name='ticketsTrader_buyer')
inscription = models.ForeignKey(Inscription)
transactionCode = models.CharField(max_length=30,blank=False,null=False)
...
App inscription
class Event(models.Model):
title = models.CharField(max_length=75)
description = models.TextField()
...
class Inscription(models.Model):
event = models.ForeignKey(Event)
packs = models.ManyToManyField(PackChoise)
user = models.ForeignKey(User)
...
def __unicode__(self):
return self.event.__unicode__() + u': ' + self.user.__unicode__()
def inscriptionKey(self):
return str(self.pk) + '_' + str(self.valkey)
But when I try to acces to the "Add Ticket Trader" interface in my Grapelli admin, I get an error message :
User matching query does not exist.
Python27\lib\site-packages\django\db\models\query.py in get, line 366
In template \grappelli\templates\admin\includes\fieldset.html, error
at line 19
What I want to get is : in the "inscription" column of my ticketTrader table get the value of the unique id (pk) of my "Inscription" table.
Or the value of the "inscriptionKey" but I don't think it's possible.
Django Version:1.4 / Python Version: 2.7.3 / South last version
Thanks for your help :)
I can only guess:
TicketsTrader has a foreign key to Inscription, which has a foreign key to User and uses that key in its __unicode__() method.
Now, I don't know Grapelli but the default admin app would render a dropdown for Inscription-s on the Add TicketsTrader page. If some of the Inscription-s pointed to non-existing User-s, then their __unicode__() method would fail with the error message you specified.
The question is how could some User-s be missing and Inscription-s pointing to them not. Well, if you use e.g. MySQL+MyISAM, foreign keys are not enforced there so all sorts of weird things can happen.
I think because you don't have any User... try create User before create Ticket Trader
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
I have this small project to create my bills through Django and Latex which worked flawlessly until today. Now when I try to add another costumer, Django throws
duplicate key value violates unique constraint "kunden_kundearbeitsamt_pkey"
DETAIL: Key (id)=(4) already exists.
These are the model definitions in question:
class Kunde(models.Model):
name = models.CharField('Name', max_length = 200)
vorname = models.CharField('Vorname', max_length = 200)
geburtsdatum = models.DateField('Geburtsdatum', max_length = 200)
untersuchungsdatum = models.DateField('Untersuchungsdatum', max_length = 200)
class Meta:
abstract = True
class KundeArbeitsamt(Kunde):
kundennummer = models.CharField('Kundennummer', max_length = 100)
bglnummer = models.CharField('BGL-Nummer', max_length = 100)
empfaenger = models.ForeignKey('rechnungen.NumberToEmpfaenger', blank = True, null = True)
class Meta:
verbose_name = "Proband Arbeitsamt"
verbose_name_plural = "Proband Arbeitsamt"
def __str__(self):
return '{}, {}'.format(self.name, self.vorname)
The admin part where the object is created (nothing special, I guess):
from django.contrib import admin
from .models import KundeArbeitsamt
class KundeArbeitsamtAdmin(admin.ModelAdmin):
ordering = ('name',)
admin.site.register(KundeArbeitsamt, KundeArbeitsamtAdmin)
I swear, I did not make any migrations or other changes to the database (Postgres) whatsoever. Django is handling the creation of the objects. What is causing this error and how to fix it?
This error is raised by your database, because django wants to add an new column with an ID (=4) already in use.
To investigate further you need to find the part of your app responsible for creating the IDs. Django usually delegates this task to your database. In case of postgres the datatype serial is used. Postgres uses so called sequences for this purpose and generates and executes the following SQL for you:
CREATE SEQUENCE tablename_colname_seq;
CREATE TABLE tablename (
colname integer NOT NULL DEFAULT nextval('tablename_colname_seq')
);
ALTER SEQUENCE tablename_colname_seq OWNED BY tablename.colname;
I would now start with checking the database sanity like that:
-- views contents of the table
SELECT * FROM kunden_kundearbeitsamt;
-- check the sequence
select currval('kunden_kundearbeitsamt_id_seq');
If the first shows 4 records with IDs 1, 2, 3 and 4 and the sequence answers with 4 everything is alright. I would proceed with the django sources to figure out why they pass an ID on object creating without relying on the sequence. The django shell might be a good place to start with in that case.
Otherwise I would fix the sequence and ask myself how this happend as it is barely the case that postgres makes mistakes at this point.
SELECT setval('kunden_kundearbeitsamt_id_seq', (SELECT max(id) FROM kunden_kundearbeitsamt));
I'm building a social network where user are supposed to be able to follow each other. So I define a class user with a field: ManyToMany to stock the users that follow this user. This is what I have done in my model.py:
followings = models.ManyToManyField('self', blank=True)
This is my view.py:
#login_required
def follow_test(request):
name = request.POST.get('name', '')
user_followed = Dater.objects.get(username=name)
current_user = Dater.objects.get(id=request.user.id)
print current_user.followings # display my_app.Dater.None
current_user.followings.add(user_followed)
print current_user.followings # display my_app.Dater.None
I retrieve correctly my users (current (The one who follow someone) and the followed one) but I can't add the followed user in the set followings of the current user. Can you see something I don't do properly in my view?
followings is a manager; to show the members of that relationship, you need to call .all() on it (or another manager/queryset method like order_by).
print current_user.followings.all()
I have 3 models: User, Choice, Card. Each user will look at the same set of 10 cards and decides each one is important or not.
Here are how I define the classes and their relationship
In models.py:
class Choice(models.Model):
user = models.ForeignKey(User)
card = models.ManyToManyField(Card)
is_important = models.NullBooleanField()
class Card(models.Model):
card_number = models.IntegerField(primary_key=True)
content = models.TextField(null=False)
In views.py
(I try to save the choice for the card from the user. )
def listings(request):
user = request.user
choice = Choice.objects.create(user=user, is_important = True)
choice.card= Card.objects.get(1)
However, I got this error
'Card' object is not iterable
Could you please show me where the error is?
Many thanks!
You can add object against many to many field like this
card = Card.objects.create(card_number=any_number, content='abc')
choice.card.add(card)
First, it looks like you forgot pk= in your first .get() argument: Card.objects.get(pk=1)
Second, Choice.cards is a ManyToManyField that expects a list of items and not one in particular. You should set it through:
choice.card.set(Card.objects.filter(pk=1))
Please note that direct assignment with = will be deprecated from Django 1.10 and deleted in Django 2.0
.filter() will return a QuerySet (which is iterable). I think you wanted a ForeignKey instead of a M2M field, in which case your code would work (with the additional pk=).
In your function:
def listings(request):
user = request.user
choice = Choice.objects.create(user=user, is_important = True)
choice.card= Card.objects.get(1)
The following line is trying to fetch the Card object. However, we need to specify which card to be fetched.
If using an id, query it as:
choice.card= Card.objects.get(pk=1)
or else using list of ids:
choice.card = Card.objects.filter(pk__in=[12,22])
If using card_number field:
choice.card= Card.objects.get(card_number=1)
or else using list of card_numbers:
choice.card = Card.objects.filter(card_number__in=[12,22])
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,...)