I'm a beginner in Django, I created a simple ecommerce app and I'm writing some tests in tests.py.
I'm trying to write a test which check the correct creation of an OrderItem, but I don't know how to obtain an user instance.
Should I check the logged in user or the existence of the user is enough?
This is my store/models.py:
from tkinter import CASCADE
from django.db import models
from django.conf import settings
class Item(models.Model):
name = models.CharField(max_length=50)
price = models.FloatField()
def __str__(self):
return self.name
class OrderItem(models.Model):
item = models.ForeignKey(Item, on_delete=models.CASCADE)
quantity = models.PositiveIntegerField(default=1)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
ordered = models.BooleanField(default=False)
def __str__(self):
return f"{self.quantity} of {self.item.name}"
#property
def get_total_price(self):
return self.quantity*self.item.price
And this store/tests.py:
def create_item(name='cintura', price=10):
return Item.objects.create(name=name, price=price)
def get_user():
return User.objects.get(username='foo')
def create_orderitem(quantity=2, user=get_user(), ordered=False):
item = create_item()
return OrderItem.objects.create(item=item, quantity=quantity, user=user, ordered=ordered)
class OrderItemModelTest(TestCase):
def test_orderitem_creation(self):
order_item = create_orderitem()
self.assertFalse(order_item.ordered)
self.assertGreater(order_item.quantity, 0, 'Quantity must be > 0')
#put here user check
This is the error:
django.db.utils.IntegrityError: The row in table 'store_orderitem' with primary key '1' has an invalid foreign key: store_orderitem.user_id contains a value '1' that does not have a corresponding value in auth_user.id.
You need something like this:
def setUp(self):
self.user = User.objects.create_user(username='testuser', password='password')
factory = RequestFactory()
request = factory.get('')
request.user = self.user
self.client.login(username='testuser', password='password')
In your tests use self.client as a ready user.
Django clears the database between tests. If you call your get_user() already in function's signature it gets executed before the test class.
If you want to keep your structure like it is now you have to move it into the function:
def create_orderitem(quantity=2, user=None, ordered=False):
if user is None:
user = get_user()
item = create_item()
return OrderItem.objects.create(item=item, quantity=quantity, user=user, ordered=ordered)
Related
I want to allow a user to edit a project page if ifAdmin (an object in uProject model) == True. I am currently trying to use #user_passes_test to render a view to update the project, but am having difficulties. I am getting uProjects from main.models, and I am working in projects.views. Here's my code.
def admin_check(uProjects):
return uProjects.ifAdmin = True
#user_passes_test(admin_check)
def update(request): etc, etc, etc
models.py
class uProjects(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
project = models.ForeignKey(Project, on_delete=models.CASCADE)
ifAccepted = models.BooleanField(null = True, blank=False, default=False)
#ifLeader = models.BooleanField(null = False, blank=False)
ifAdmin = models.BooleanField(null = True, blank=False, default=False)
title = models.CharField(max_length=100, null=False, blank=False)
def __str__(self):
return self.user.username + ',' + self.project.name
The difficulty is I'm trying to have admin_check work with uProjects, not the User model. I'm also trying to see if ifAdmin == True, but the way I did above renders an error. The error is that the "User object has no attribute ifAdmin"
You can use something like this:
def admin_check(user):
return user.uprojects_set.filter(ifAdmin=True).exists()
#user_passes_test(admin_check)
def update(request): etc, etc, etc
But this will work for any user which has ifAdmin permission in atleast one uProject instance. It can't distinguish by uProject information.
To do that, you can write a custom dectorator like this:
from functools import wraps
from django.http import HttpResponseRedirect
def admin_check(function):
#wraps(function)
def wrap(request, *args, **kwargs):
user = request.user
name = kwargs.get('name') # assuming you are getting the project id here via url: "/<project_id:int>"
if uProjects.objects.filter(title=name, user=user, ifAdmin=True).exists():
return function(request, *args, **kwargs)
else:
return HttpResponseRedirect('/')
return wrap
So I have a problem about how to save model instance with foreign key relation,
models.py
class Connect(models.Model):
username = models.CharField(max_length=255)
password = models.CharField(max_length=255,null=True, blank=True)
conft = models.TextField(null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
def __unicode__(self):
return unicode(self.username)
class Ip(models.Model):
class Meta:
db_table = 'autonet_ip'
connect_id = models.ForeignKey(Connect, on_delete=models.CASCADE)
ipaddr = models.CharField(max_length=255)
def __str__ (self):
return self.ipaddr
forms.py
class NacmForm(ModelForm):
password = forms.CharField(widget=forms.PasswordInput,required = False)
class Meta:
model = Connect
fields = ['username', 'password','conft']
labels = {'conft':_('Config'),}
class IpForm(ModelForm):
class Meta:
model = Ip
fields = ['ipaddr']
labels = {'ipaddr':_('IP address'),}
IpFormset = formset_factory(IpForm, extra=1)
views.py
def konfig(request):
ip_list = []
status = ''
value_bak = 1
if request.method == 'POST':
formm = NacmForm(request.POST or None)
ipform = IpFormset(request.POST)
upform = UploadForm(request.POST,request.FILES)
userValue = formm['username'].value()
passValue = formm['password'].value()
confValue = formm['conft'].value()
usernamef = get_object_or_404(Connect, pk=id)
if ipform.is_valid():
for form in ipform:
ipaddr = form.cleaned_data.get('ipaddr')
//.... some code ...//
simpanIp = form.save(commit=False)
simpanIp.connect_id = usernamef
simpanIp.save()
simpanForm.save()
return HttpResponseRedirect('/konfig')
else:
formm = NacmForm()
ipform = IpFormset()
return render(request, 'konfig.html', {'form': formm, 'logins': Connect.objects.all(), 'ipform': ipform, 'status': status })
Then, when I input all data and click submit to collect form data and on simpanIp.save(), I've got an error: id() takes exactly one argument (0 given).
I just want to know how to save the instance of Connect model to database with foreign key, thanks in advance
so i edit my models.py like this
class Connect(models.Model):
......
def get_usernameinf(self):
return ', '.join(self.usernameinf.all().values_list('username', flat=True))
and views.py like this
if request.method == 'POST':
.....some code.....
if ipform.is_valid() and formm.is_valid():
simpanForm = formm.save()
for form in ipform:
simpanIp = form.save(commit=False)
...... some code ..
simpanIp.connect_id = simpanForm
simpanIp.save()
and its work, now the result is my "connect_id" got value from "Connect id"
id is a Python builtin that gives a unique ID for an object. I would guess that you did not intend to pass it get_object_or_404 on this line:
get_object_or_404(Connect, pk=id)
The calling convention for this functions seems to be that it is meant to be an integer for the primary key in a database table. Figure out where you should be getting your primary key from and set it correctly.
Pro-tip: avoid using names that are predefined by Python (see here for a full list). It can lead to headaches like the one you just had.
Ok, so what I'm trying to do is allow the user to add a "product" to their shop but without having to choose the shop to add it to as each user will only have ONE shop.
I'm getting the:
"IntegrityError at /shop/product/add/
NOT NULL constraint failed: shop_product.business_id"
This is what's being shown in the local variables:
Local Vars
Local Vars:
Variable Value
__class__ <class 'shop.views.ProductCreate'>
form <AddProductForm bound=True, valid=True, fields=(product_name;product_desc;product_image)>
s <Shop: 4>
self <shop.views.ProductCreate object at 0x048B0370>
user 10
Now I believe the issue might be the "s" variable's as the code is actually getting the correct shop.. but it's also adding that weird "
My Code as it is right now.
models.py
# Shop Model. A Shop Object will be created when the user registers
class Shop(models.Model):
name = models.CharField(max_length=150)
owner = models.OneToOneField(User, related_name="owner")
shop_logo = models.FileField()
def __str__(self):
return str(self.name) + ": " + str(self.owner)
def create_shop(sender, **kwargs):
user = kwargs["instance"]
if kwargs["created"]:
up = Shop(owner=user)
up.save()
post_save.connect(create_shop, sender=User)
def shoplogo_or_default(self, default_path='/static/images/dft/no-img.png'):
if self.shop_logo:
return self.shop_logo
return default_path
# The class that will link a product to the shop
class Product(models.Model):
product_name = models.CharField(max_length=250)
# connect the product to the shop
business = models.ForeignKey(Shop, on_delete=models.CASCADE, related_name="products")
product_desc = models.TextField()
product_image = models.FileField()
def __str__(self):
return self.product_name
views.py
class ProductCreate(CreateView):
model = Product
form_class = AddProductForm
template_name = 'shop/add-product.html'
def form_valid(self, form):
form.save(commit=False)
# get current logged in user
user = self.request.user.id
# match the current logged in user to an owner in the Shop model
s = Shop.objects.get(owner=user)
# get the id of that owner's shop identification number
form.business = str(s.id)
form.save()
# This method is called when valid form data has been POSTed.
# It should return an HttpResponse.
return super(ProductCreate, self).form_valid(form)
The above should in theory get the current logged in user, match that user to a shop within the shop model as an owner and then get that shop ID.
forms.py
class AddProductForm(forms.ModelForm):
class Meta:
model = Product
fields = ['product_name', 'product_desc', 'product_image']
exclude = ['business']
I'm rather new to Django and a student so I'd like to apologise if you see anything weird.
Thank you :)
You're close, but don't try to edit the shop value into the form. Instead, capture the in-memory Product instance from saving the form and assign its business attribute:
def form_valid(self, form):
new_product = form.save(commit=False)
# get current logged in user
user = self.request.user.id
# match the current logged in user to an owner in the Shop model
s = Shop.objects.get(owner=user)
# assign the shop instance to the product
new_product.business = s
# record the product to the database
new_product.save()
# This method is called when valid form data has been POSTed.
# It should return an HttpResponse.
return super(ProductCreate, self).form_valid(form)
I am trying to make multiple profile for Userena - each User can only have one Profile type. Following other discussions, I am using multiple table inhertience, but when I do this, I cannot get data to be saved into the derived models. Everything ends up being CommonProfile, which should not be possible/permitted. Example code follows:
in models.py:
# models.py
# This is an example of how i've attempted to get
# multiple user profiles working with Userena
from django.contrib.auth.models import User
from django.db import models
from userena.models import UserenaLanguageBaseProfile
class CommonProfile(UserenaLanguageBaseProfile):
"""Common fields for 2 user profiles: Spam and Eggs"""
user = models.OneToOneField(User)
common_field = models.CharField(max_length=100)
#property
def is_spam(self):
"""Find out if this is a Spam user"""
try:
self.spamprofile
return True
except SpamProfile.DoesNotExist:
return False
def get_real_type(self):
"""return the real model"""
if self.is_spam:
return self.spamprofile
else:
return self.eggsprofile
class SpamProfile(CommonProfile):
spam_field = models.CharField(max_length=20)
class EggsField(CommonProfile):
eggs_field = models.SmallIntegerField()
in forms.py
# forms.py
# This is the form to sign up a Spam Type Person
from django import forms
from userena.forms import SignupFormTos
from . models import CommonProfile, SpamProfile
class SpamSignupForm(SignupFormTos):
"""signup a Spam Person"""
common_field = forms.CharField(label='what is your quest')
spam_field = forms.CharField(label='what kind of spam are you')
def clean(self):
cleaned_data = super(SpamSignupForm,self).clean()
#do stuf, same idea for clean_<field>
return cleaned_data
def save(self):
"""Save the SpamProfile"""
user = super(SpamSignupForm,self).save()
common_profile = user.get_profile()
spam_profile = SpamProfile(commonprofile_ptr=common_profile)
spam_profile.spam_field = self.cleaned_data['spam_field']
spam_profile.save()
return spam_profile
I had the same problem this weekend. Try in your save function
def save:
#your other code
spam_field = self.cleaned_data['spam_field']
new_spam_user = SpamProfile.objects.create_user(spam_field)
return new_user
I'd like to insert individual squawks into the Room object so I can insert into the database. How do I do this?
I tried, Room(squawk=squawk object), but this doesn't appear to work.
class Squawk(models.Model):
username = models.ForeignKey(User)
message = models.CharField(max_length=160)
time = models.DateTimeField(auto_now_add=True)
def __unicode__(self):
return str(self.username) + ' - ' + self.message
class Room(models.Model):
title = models.CharField(max_length=160)
created = models.DateTimeField(auto_now_add=True)
users = models.ManyToManyField(User)
squawks = models.ManyToManyField(Squawk)
def __unicode__(self):
return self.title
from django.shortcuts import get_object_or_404
# get Room instance by id or raise 404 page if not found
room = get_object_or_404(Room,pk = id)
# add squawk to many-to-many relation
room.squawks.add(squawk_object)
https://docs.djangoproject.com/en/dev/ref/models/relations/