File "C:\Users\NICSI\Desktop\lastnow\mynew\cheque\models.py", line 39, in st
r
return (self.related.relation.username).title()
AttributeError: 'NoneType' object has no attribute 'relation'
[28/Sep/2018 12:36:49] "GET /admin/cheque/mycheque/ HTTP/1.1" 500 301999
Exception Value:
Signs matching query does not exist.
DJANGO throw these two errors how could i resolve this to show the relation between user and these details
models.py
class Signs(models.Model):
relation = models.OneToOneField(User, on_delete=models.CASCADE)
department = models.CharField(null=True, blank=True, max_length=1000, help_text="User Department")
mobile = models.CharField(null=True, blank=True, max_length=1000, help_text="User Mobile")
def __str__(self):
return (self.relation.username).title()
class Meta:
verbose_name_plural = "Registration Information"
class Mycheque(models.Model):
related = models.ForeignKey(Signs, on_delete=models.CASCADE, null=True, blank=True)
to_pay = models.CharField(max_length=250, null=True, blank=True)
amount = models.BigIntegerField(default=0, null=True, blank=True)
amount_in_words = models.CharField(max_length=10000, null=True, blank=True)
vouchar_no = models.BigIntegerField(default=0, null=True, blank=True)
dated = models.DateTimeField(auto_now_add=True, null=True, blank=True)
cheque_no = models.BigIntegerField(default=0, null=True, blank=True)
cheque_date = models.CharField(max_length=10, null=True, blank=True)
account_no = models.BigIntegerField(default=0, null=True, blank=True)
def save(self):
self.dated = datetime.now()
super(Mycheque, self).save()
def __str__(self):
return (self.related.relation.username).title()
class Meta:
verbose_name_plural = "Single Cheque Of Users"
views.py
def mycheque(request):
if request.method == "POST":
userdata = User.objects.get(username = request.user)
user_data = Signs.objects.get(relation_id=userdata.id)
if userdata.check_password(passwd) == True:
to_p = request.POST['topay']
amnt = request.POST['amount1']
amnt_in_words = request.POST['amount_string']
vouch_no = request.POST['voucharno']
d = request.POST['date']
cheq_no = request.POST['chequeno']
cheq_date = request.POST['chequedate']
acc_no = request.POST['accountno']
single = Mycheque(to_pay=to_p, amount=amnt, amount_in_words=amnt_in_words, vouchar_no=vouch_no, dated=d, cheque_no=cheq_no, cheque_date=cheq_date, account_no=acc_no)
single.save()
messages.success(request, "Your Cheque is created")
else:
messages.error(request, "Please Try again...")
return render(request, 'cheque/mycheque.html', {})
AttributeError
The error originates from the fact that the Mycheque.related relation is NULLable: it is possible to set it to NULL.
This means that for some Mycheques, the self.related object will be None, and therefore self.related.relation will error.
You will thus to add some logic to the __str__ to handle that case, for example:
def __str__(self):
if self.related:
return self.related.relation.username.title()
else:
return 'no related!'
That being said, I find the __str__ function rather "weird": the textual representation of a Mycheque only takes the related.relation object into account? So you should consider redesigning this.
The same "scanario" can happen on multiple places, so you should run a search and fix it accordingly
Singns does not exists
This is probably due to the line:
user_data = Signs.objects.get(relation_id=userdata.id)
The strange thing is here that you do nothing with the user_data variable at all, so - given you implemented the view correctly - can remove the line.
That being said the line itself makes no sense: you query a ForeignKey in reverse, that means that for a User object, there can be zero, one, or multiple Signs objects. So it makes more sense to use .filter(..) since if there are no related Signs (or multiple) this query will error.
Refactoring the view, and introducing a ModelForm
The line above:
userdata = User.objects.get(username = request.user)
makes no sense either: the request.user is a User object, so it is equivalent to:
userdata = request.user
Other piculiarities in the view are that you perform authentication yourself, instead of using the #login_required [Django-doc], and furthermore it here definitely makes sense to define a ModelForm [Django-doc], by using a form, the view will probably be reduced to 5-7 lines, and the errors are handled at the correct place.
Related
I'm running into the following error, and been stuck on it the last two weeks. I don't know what it could possibly mean by 'int' object has no attribute 'country' in my case, and country exists in my serializer and model. If I remove country from the serializer, I get the same error with post_code.
I haven't got a clue what could be going wrong
Got AttributeError when attempting to get a value for field `country` on serializer `AddressSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `int` instance.
Original exception text was: 'int' object has no attribute 'country'
View:
class Address(generics.RetrieveUpdateDestroyAPIView):
permission_classes = [AddressPermission]
queryset = Addresses.objects.all()
def get_object(self):
try:
if self.request.COOKIES['access_token'] is not None:
obj = get_object_or_404(self.get_queryset(), user=NewUser.objects.get(id=jwt.decode(self.request.COOKIES['access_token'], settings.SECRET_KEY, algorithms=["HS256"])['user_id']))
self.check_object_permissions(self.request, obj)
return obj
except:
return status.HTTP_401_UNAUTHORIZED
serializer_class = AddressSerializer
Serializer:
class AddressSerializer(serializers.ModelSerializer):
class Meta:
fields = ('country', 'organization_name', 'administrative_area', 'sub_administrative_area', 'locality', 'post_code', 'thoroughfare', 'premise')
model = Addresses
Model:
class Addresses(models.Model):
country = models.CharField(max_length=2)
organization_name = models.CharField(max_length=150, null=True, blank=True)
# State/Province
administrative_area = models.CharField(max_length=150, null=True, blank=True)
# County/District/Municipality
sub_administrative_area = models.CharField(max_length=150, null=True, blank=True)
locality = models.CharField(max_length=150, null=True, blank=True)
post_code = models.CharField(max_length=12)
# the actual street address
thoroughfare = models.CharField(max_length=95)
# Apt, suite, or box number
premise = models.CharField(max_length=16)
user = models.ForeignKey(NewUser, on_delete=models.CASCADE)
Quickly looking at your code again i think you are getting the error because in your get_object you are returning an int and not a string.
In your exception, try to return an HTTPResponse as:
return HttpResponse(status=status.HTTP_401_UNAUTHORIZED)
I think the reason why when you remove country from the serializer you get the same error on the post_code is because all you other attributes have null=True, blank=True. Country does not have this and the next in line without is post_code. Although both of these should be empty strings anyway when saved.
So try to return an HttpResponse and let's see what happens.
I have the following models/forms/view in which I have managed to submit to two different models as follows:
Models
class Account(models.Model):
username = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
name = models.CharField(max_length=150)
actflag = models.CharField(max_length=1, blank=True)
acttime = models.DateTimeField(blank=True, null=True)
comments = models.TextField(_('comments'), max_length=500, blank=True)
def __str__(self):
return self.name
class ISIN(models.Model):
code = models.CharField(max_length=12)
account_name = models.ForeignKey(Account, on_delete=models.SET_NULL, null=True)
actflag = models.CharField(max_length=1, blank=True)
acttime = models.DateTimeField(blank=True, null=True)
def __str__(self):
return self.code
Forms
from apps.portfolio.models import Account, ISIN
class PortfolioForm(forms.ModelForm):
class Meta:
model = Account
fields = ['name', 'comments']
class IdentifierForm(forms.ModelForm):
class Meta:
model = ISIN
fields = ['code']
View
def portfolios(request):
if request.user.is_authenticated:
if request.POST:
fm = PortfolioForm(request.POST)
fm2 = IdentifierForm(request.POST)
if fm.is_valid():
messages.success(request, 'Portfolio has been created.')
account = fm.save(commit=False)
account.username = request.user
account.acttime = timezone.now()
account.actflag = 'I'
account.save()
isin = fm2.save(commit=False)
#isin.account_name = account.name
isin.acttime = timezone.now()
isin.actflag = 'I'
isin.save()
return redirect('portfolios')
else:
fm = PortfolioForm()
fm2 = IdentifierForm()
context = {"name": request.user, "form": fm, "form2": fm2}
return render(request, 'portfolios.html', context)
else:
return redirect('login')
However, you will notice the commented line in my view: isin.account_name = account.name, when I uncomment this line and try to submit the forms again I get the following error: Cannot assign "'test'": "ISIN.account_name" must be a "Account" instance.
I believe it's to do with ForeignKey but still unsure how to store the newly created account name the user submitted within the isin model.
Help is much appreciated.
Although my answer solves the problem you originally had, there are a couple additional points that I wanted to make.
Improve naming and fix the original error
Your field is called account_name, and it implies that a string will be stored there. If it was actually a string, you would be able to do what you tried:
isin.account_name = account.name
In reality, you have a ForeignKey to the Account model, so you have to actually save a reference to the account object:
isin.account_name = account
It's a really good idea to have a foreign key instead of just a string because it avoids denormalization.
The problem here is the name of the field, account_name. If you later want to access the account name, you would have to write something like isis.account_name.name. Sounds wrong, doesn't it?
You could solve this by renaming your field like so:
class ISIN(models.Model):
code = models.CharField(max_length=12)
account = models.ForeignKey(Account, on_delete=models.SET_NULL, null=True)
actflag = models.CharField(max_length=1, blank=True)
acttime = models.DateTimeField(blank=True, null=True)
def __str__(self):
return self.code
Then, in your view, you would just isin.account = account, and later, if you wanted to access the name, you would use isin.account.name.
Another minor thing is that in some places an account is called Account and in other places it's Portfolio. This creates an illusion that they're unrelated entities and makes your code harder to read and maintain.
You probably should decide which one is the better term, and make it consistent everywhere.
Use builtin timestamp mechanism
Looks like you're using the acttime field to manually store creation time of accounts and ISINs.
You could use Django's auto_now_add property to do that automatically, like so:
class Account(models.Model):
acttime = models.DateTimeField(auto_now_add=True)
If you also wanted to store the last time an Account was updated, you could use auto_now (also renamed fields here for clarity):
class Account(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
And to stay DRY, you could make a mixin for that and use it in both Account and ISIN:
class TimeStampMixin(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
class Account(TimeStampMixin, models.Model):
username = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
name = models.CharField(max_length=150)
actflag = models.CharField(max_length=1, blank=True)
comments = models.TextField(_('comments'), max_length=500, blank=True)
def __str__(self):
return self.name
class ISIN(TimeStampMixin, models.Model):
code = models.CharField(max_length=12)
account = models.ForeignKey(Account, on_delete=models.SET_NULL, null=True)
actflag = models.CharField(max_length=1, blank=True)
def __str__(self):
return self.code
This way, the creation time and the latest update time are automatically stored in your models (the ones that inherit from TimeStampMixin).
Validate both forms
Looks like you're only checking one of the forms for validity, and not the other:
if fm.is_valid():
You should probably check both, in case ISIN.code is invalid:
if fm.is_valid() and fm2.is_valid():
What it means is that you have to make an instance of the account model by getting the name in order to save the form like so:
def portfolios(request):
if request.user.is_authenticated:
if request.POST:
fm = PortfolioForm(request.POST)
fm2 = IdentifierForm(request.POST)
if fm.is_valid():
messages.success(request, 'Portfolio has been created.')
account = fm.save(commit=False)
account.username = request.user
account.acttime = timezone.now()
account.actflag = 'I'
account.save()
# Here is where we get the instance of account
account = Account.objects.get(name=account.name)
isin = fm2.save(commit=False)
isin.account_name = account
isin.acttime = timezone.now()
isin.actflag = 'I'
isin.save()
return redirect('portfolios')
else:
fm = PortfolioForm()
fm2 = IdentifierForm()
context = {"name": request.user, "form": fm, "form2": fm2}
return render(request, 'portfolios.html', context)
else:
return redirect('login')
The field account_name is a ForeignKey to Account, but you are assigning an string. You should to assign an Account.
Change:
isin.account_name = account.name
To:
isin.account_name = account
I can not get a clear answer after two days of searching for what must probably be one of the most common things to do with a DRF:
I have the following model:
class ProcessedStockAmounts(models.Model):
prodName = models.ForeignKey(Productlist, on_delete=models.CASCADE, blank=False, unique=False)
amount = models.CharField(unique=False, max_length=255)
time = models.ForeignKey(StockTakingTimes, on_delete=models.CASCADE, blank=False, unique=False, default=1)
def __str__(self):
return str(self.prodName)
And I am returning a JSON object via my API that looks like this:
[{'prodName': 'SV1', 'amount': '1111111', 'time' : 1}]
When I insert my prodName with a value it has no problem, but obviously my user will not know the prodName ID and only the prod name. So when I try to insert the above I get the following error:
ValueError: Cannot assign "'SV1'": "ProcessedStockAmounts.prodName" must be a "Productlist" instance.
This was the closest I got to an answer and when I do the following it actually inserts:
p = ProcessedStockAmounts(amount='33', prodName = Productlist.objects.get(productid = 'SV1'), time = StockTakingTimes.objects.get(times='06:00'))
p.save()
but giving data this way is obviously defeating the purpose.
My serializer looks like the following:
class TestSerializer(serializers.ModelSerializer):
# time = serializers.SlugRelatedField(read_only=True, slug_field='time')
prodName = serializers.CharField()
# prodName = serializers.SlugRelatedField(read_only=True, slug_field='prodName')
class Meta:
model = ProcessedStockAmounts
fields = ('prodName','amount','time')
With my view:
class InsertMultiProcessedStock(APIView):
def post(self, request, format='json'):
serializer = TestSerializer(data = request.data, many=True)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
else:
return Response(serializer.errors)
Productlist model:
class Productlist(models.Model):
productid = models.CharField(unique=True, max_length=20) # Field name made lowercase.
proddescription = models.CharField(db_column='prodDescription', max_length=255, blank=True, null=True) # Field name made lowercase.
packaging = models.ForeignKey(Packaging, on_delete=models.CASCADE, blank=True, null=True)
unitweight = models.FloatField(db_column='unitWeight', blank=True, null=True)
def __str__(self):
return self.productid
This would have been easier if you had the related model. But the commented-out slugrelatedfield is the way you should do it, using the actual field name:
prodName = serializers.SlugRelatedField(read_only=False, slug_field='productid')
Your serializer is wrong, You must use relationship serializer.
prodName = ProductlistSerializer(many = False)
But I found Your model defintion is very confusing
I have a bunch of message records that I would like to assign to different taskboxes.
#models.py
class TaskBox(models.Model):
name = models.CharField(max_length=64, blank=False)
def __str__(self):
return u'%s' % (self.name)
class Admin:
pass
class InboxEntry(models.Model):
job_number = models.CharField(max_length=14, unique=False, blank=False, null=False)
job_name = models.CharField(max_length=64, unique=False, blank=False, null=False)
request = models.CharField(max_length=64, choices=PRINT_CHOICES, blank=True, null=True)
date_due = models.DateTimeField(("Due"),auto_now=False)
note = models.TextField(max_length=1000, unique=False, blank=True, null=True)
assigned_by = models.ForeignKey(UserProfile, blank=False, null=False)
box = models.ForeignKey(TaskBox)
assigned_to = models.ManyToManyField(UserProfile, related_name='name', blank=True)
status = models.CharField(max_length=30, choices=STATUS_CHOICES, default="Awaiting Action")
def __str__(self):
return u'%s %s' % (self.job_number, self.job_name)
class Admin:
pass
class Meta:
ordering = ['status']
The idea is for the template to have some generic tags like {{ for taskbox in taskboxes }} to create a separate div for each taskbox that will hold a table for that box's records. My problem is constructing the view function...
#views.py
def display_prdInboxEntry(request, id):
if request.method == 'POST':
form = PrdInboxForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('taskmanager/display/'+ id +'/')
else:
form = PrdInboxForm(request.POST)
return HttpResponseRedirect('taskmanager/display/'+ id +'/')
else:
form = PrdInboxForm()
user = request.user
**taskboxes = TaskBox.objects.all()
records_1 = InboxEntry.objects.filter(taskboxes[id]=1)
records_2 = InboxEntry.objects.filter(taskboxes[id]=2)
records_3 = InboxEntry.objects.filter(taskboxes[id]=3)
..... **
return render_to_response('taskmanager/taskmanager_view.html', {'form': form, 'taskboxes': taskboxes, 'records_1' : records_1, 'records_2' : records_2, 'records_3' : records_3, 'user': user}, context_instance=RequestContext(request))
The InboxEntry model has a field called "box" that's just a reference to the TaskBox model. I need a way to map say... TaskBox id 1 with all of the InboxEntry objects with "box = 1" so that I can populate the templates appropriately. Can I construct the function to accommodate this, or am I going about it the wrong way entirely?
It sounds like you're looking for the automatically-generated attribute for reverse lookups. You can get a QuerySet of all InboxEntries associated with a TaskBox like this:
TaskBox.objects.filter(id=1).inboxentry_set.all()
See the documentation on related objects.
I want to do "contextal" form validation in django. Consider this case:
PLACE_TYPES = (
('RESTAURANT', 'Restaurant'),
('BARCLUB', 'Bar / Club'),
('SHOPPING', 'Shopping'),
)
RESTAURANT_FORMAT_CHOICES = (
('FAST_FOOD', 'Fast Food'),
('FAST_CASUAL', 'Fast Casual'),
('CASUAL', 'Casual'),
('CHEF_DRIVEN', 'Chef Driven'),
)
class Place(models.Model):
place_type = models.CharField(max_length=48, choices=PLACE_TYPES, blank=False, null=False)
name = models.CharField(max_length=256)
website_1 = models.URLField(max_length=512, blank=True)
hours = models.CharField(max_length=1024, blank=True)
geometry = models.PointField(srid=4326, blank=True, null=True)
#Restaurant Specific
restaurant_format = models.CharField(max_length=128, choices=RESTAURANT_FORMAT_CHOICES, blank=True, null=True)
So in the django admin, the corresponding form for Place will have pulldown menu with choices like "restaurant, bar, club", and there is another field called "restaurant_format".
Validation should make sure restaurant_field cannot be null if the first pulldown was set as "restaurant".
I am trying something like this:
class PlaceAdminForm(forms.ModelForm):
def clean(self):
if self.cleaned_data['place_type'] == 'RESTAURANT':
if self.cleaned_data['place_type'] is None:
raise forms.ValidationError('For a restaurant you must choose a restaurant format')
but get this error:
Exception Type: KeyError
Exception Value:
place_type
Exception Location: /place/admin.py in clean, line 27
i think i got it working with this clean routine:
def clean(self):
cleaned_data = self.cleaned_data
place_type = cleaned_data.get("place_type")
restaurant_format = cleaned_data.get("restaurant_format")
if place_type == 'RESTAURANT':
if self.cleaned_data['restaurant_format'] is None:
raise forms.ValidationError('For a restaurant you must choose a restaurant format')
# Always return the full collection of cleaned data.
return cleaned_data