Derived model filefield not available - django

I have a base model and derived model from it. base model is not abstract, so it also has table associated with it.
Problem : I create a base instance first and then derived instance. And associate derived instance to base. But I get FileField in my derived class as None, even if its saved and available in parent. Why so? Am I missing something?
Some sample code:
def get_filepath(instance):
return u''+instance.name
def BaseModel(models.Model):
name = models.CharField(max_length=50)
filepath = models.FileField(upload_to=get_filepath,
max_length=255, null=True)
#some other fields
def DerivedModel(BaseModel):
type = models.CharField(max_length=50, null=True, blank=True)
Sample on django shell:
>>> obj = BaseModel.objects.create(name='y')
>>> obj.id
56
>>> obj.save()
>>> obj.id
56
>>> nf=ContentFile("this is dummy text")
>>> obj.filepath.save('dummyfile', nf)
>>> dobj=DerivedModel()
>>> dobj.basemodel_ptr=obj
>>> dobj.save()
>>> dobj.id
56
>>> dobj.filepath
<FieldFile: None>
>>> obj.filepath
<FieldFile: y>
Update: for #dgel's answer:
save_base() does it save the derived object? dobj does not get id after that.
After dobj.save(), it seems attributes in base class are getting overwritten by attributes in derived class.
I added ctime created time in BaseModel with default datetime.datetime.utcnow. So once I save derived object, ctime is updated to save time of derived object.
When I look at the DB through sqlitebrowser, filepath field of the BaseModel row is empty.
>>> dobj.save_base(raw=True)
>>> dobj.id
>>> dobj.save()
>>> dobj.filepath
<FieldFile: None>
>>> obj.ctime
datetime.datetime(2012, 8, 23, 8, 50, 3, 171573)
>>> dobj.ctime
datetime.datetime(2012, 8, 23, 8, 51, 9, 946434)
>>> newdobj = DerivedModel.objects.get(id=dobj.id)
>>> newdobj.ctime
datetime.datetime(2012, 8, 23, 8, 51, 9, 946434)
Thanks.

Try this:
dobj = DerivedModel()
dobj.basemodel_ptr=obj
dobj.save_base(raw=True)

Related

Magic method __repr__ leads to AttributeError with __new__ method

My goal is to give numpy.ndarray a different representation, since I want to represent some arrays with units. Thus, I programmed a class that inherits its attributes/ methods from numpy.ndarray. For the another representation I wanted to use the __repr__ magic method like:
class Quantitiy(np.ndarray):
def __new__(cls, value, unit=None, dtype=None, copy=True, order=None, subok=False, ndmin=0):
value = np.asarray(value)
obj = np.array(value, dtype=dtype, copy=copy, order=order,
subok=True, ndmin=ndmin).view(cls)
obj.__unit = util.def_unit(unit)
obj.__value = value
return obj
def __repr__(self):
prefix = '<{0} '.format(self.__class__.__name__)
sep = ','
arrstr = np.array2string(self.view(np.ndarray),
separator=sep,
prefix=prefix)
return '{0}{1} {2}>'.format(prefix, arrstr, self.__unit)
So far this works fine. However, if I want to access the inherited methods from numpy.ndarray I get a AttributeError because __repr__ cant resolve self.__unit.
I tried to solve this problem with a private method that defines the variable self.__unit and called it within the __new__ method but without success:
class Quantitiy(np.ndarray):
def __new__(cls, value, unit=None, dtype=None, copy=True, order=None, subok=False, ndmin=0):
value = np.asarray(value)
obj = np.array(value, dtype=dtype, copy=copy, order=order, subok=True, ndmin=ndmin).view(cls)
# Here I call the private method to initialize self.__unit.
obj.__set_unit()
obj.__value = value
return obj
def __repr__(self):
prefix = '<{0} '.format(self.__class__.__name__)
sep = ','
arrstr = np.array2string(self.view(np.ndarray), separator=sep, prefix=prefix)
return '{0}{1} {2}>'.format(prefix, arrstr, self.__unit)
# New defined private class.
def __set_unit(self, unit):
self.__unit = util.def_unit(unit)
I can not solve this with something like cls.__unit = util.def_unit(unit) in the __new__ method. I already tried to define a __init__ method after __new__. Moreover, I tried to interchange the private methods with public methods.
What I expect:
>>> array = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])
>>> q = Quantity(value, unit="meter / second")
>>> q
<Quantitiy [[1,2,3,4],
[5,6,7,8]] meter/second>
>>> q * q
>>> <Quantitiy [[ 1, 4, 9,16],
[25,36,49,64]] meter**2/second**2>
>>> q.min()
>>> <Quantitiy 1 meter/second>
The actual result is:
>>> array = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])
>>> q = Quantity(value, unit="meter / second")
>>> q
<Quantitiy [[1,2,3,4],
[5,6,7,8]] meter/second>
>>> q * q
>>> <Quantitiy [[ 1, 4, 9,16],
[25,36,49,64]] meter**2/second**2>
# Up to here everything works fine.
>>> q.min()
>>> AttributeError: 'Quantitiy' object has no attribute
'_Quantitiy__unit'
Does anyone see the mistake and can help me?
Ok, the answer is - as usual - in the FineManual (and could be found searching for "subclassing numpy ndarray" - which is how I found it actually), and requires implementing __array_finalize__(self, obj) :
import numpy as np
class Quantitiy(np.ndarray):
def __new__(cls, value, unit=None, dtype=None, copy=True, order=None, subok=False, ndmin=0):
value = np.asarray(value)
x = np.array(value, dtype=dtype, copy=copy, order=order, subok=True, ndmin=ndmin)
obj = x.view(type=cls)
obj._unit = unit
obj._value = value
return obj
def __repr__(self):
print("repr %s" % type(self))
prefix = '<{0} '.format(self.__class__.__name__)
sep = ','
arrstr = np.array2string(self.view(np.ndarray),
separator=sep,
prefix=prefix)
return '{0}{1} {2}>'.format(prefix, arrstr, self._unit)
def __array_finalize__(self, obj):
# see InfoArray.__array_finalize__ for comments
if obj is None:
return
self._unit = getattr(obj, '_unit', None)
self._value = getattr(obj, '_value', None)

how to get a related value from a ForeignKey model django admin

I've a model with a fk, but when save method I need get related value, e.g:
class Pedidos(models.Model):
ped_cliente = models.ForeignKey(Clientes, verbose_name='Cliente')
ped_remetente = models.ForeignKey(Remetentes, verbose_name='Remetente')
ped_produto = models.ForeignKey(Produtos, verbose_name='Produto')
ped_data_pedido = models.DateField(verbose_name='Data Pedido')
ped_quantidade = models.DecimalField(verbose_name='Peso/Volume', max_digits=10, decimal_places=0)
ped_key = models.IntegerField(unique=True, editable=False, verbose_name='Cod. Pedido')
class Pagamentos(models.Model):
pag_cliente = models.ForeignKey(Clientes, verbose_name='Cliente')
pag_key_ped = models.ForeignKey(Pedidos, verbose_name='Cód. Pedido')
pag_vencimento = models.DateField(verbose_name='Data Vencimento')
pag_vlr_total = models.DecimalField(verbose_name='Valor Total', max_digits=10, decimal_places=2)
I need when I save model Pagamentos the value field: pag_key_ped receive Pedidos.ped_key value
How I do to access this value?
You can access it via pag_key_ped.ped_key.
So:
>>> p = Pedidos(ped_key=1)
>>> p.save()
>>> pagamentos = Pagamentos()
>>> pagamentos.pag_key_ped = p
>>> pagamentos.save()
>>> print(pagamentos.pag_key_ped.ped_key)
[out] 1
>>> pagamentos.pag_key_ped = pagamentos.pag_key_ped.ped_key
>>> pagamentos.save()
HOWEVER!: This is a strange thing you want to do. pag_key_ped is already a ForeignKey and you want to override it with another ID. If there is no object with that ID, it will throw an DoesNotExist error.

Django: Identify the urls that provide duplicate content and set a canonical link

models.py
class People(models.Model):
name = models.CharField(max_length=16)
meters_away = models.IntegerField()
Lets populate the db:
>>> from people.models import People
>>> a = People()
>>> a.name = 'George'
>>> a.meters_away = 15
>>> a.save()
>>> b = People()
>>> b.name = 'Jim'
>>> b.meters_away = 10
>>> b.save()
Supposing that we have a url that returns all people in a range of x meters:
http://example.com/range/<meters>
This url scheme accepts 3 hits as follows:
http://example.com/range/20
http://example.com/range/30
http://example.com/range/40
Those hits will create the following queries:
>>> hit1 = People.objects.filter(meters_away__lt=20)
>>> hit2 = People.objects.filter(meters_away__lt=30)
>>> hit3 = People.objects.filter(meters_away__lt=40)
Where:
>>> list(hit1) == list(hit2) == list(hit3)
>>> True
This means that example.com, will serve 3 different urls with the same content.
From a SEO point of view, how could all the possible urls (meters: 21, 22, 23, 24, 30, 40 etc) be filtered in a way that a canonical url is appended to them?
The way i understood your question, you may want to get the maximum distance in meters that produce the same result as the current distance (say m meters):
next_number = People.objects.filter(meters_away__gte=m).order_by('meters_away')[:1]
next_number = next_number[0] if next_number else m
and the canonical url will be:
http://example.com/range/<next_number>

django contains all query

I have some models like that;
class Ingredient(models.Model):
name = models.CharField(max_length=128)
class Recipe(models.Model):
name = models.CharField(max_length=128)
ingredients = models.ManyToManyField(Ingredient, through='RecipeIngredient')
class RecipeIngredient(models.Model):
recipe = models.ForeignKey(Recipe)
ingredient = models.ForeignKey(Ingredient)
How can I find the recipes that contains all Ingredients?
Here is an example;
>>> i1 = Ingredient(name="egg")
>>> i1.save()
>>> i2 = Ingredient(name="flour")
>>> i2.save()
>>> i3 = Ingredient(name="water")
>>> i3.save()
>>> i4 = Ingredient(name="milk")
>>> i4.save()
>>> i5 = Ingredient(name="sugar")
>>> i5.save()
>>> i6 = Ingredient(name="carrot")
>>> i6.save()
>>> i7 = Ingredient(name="wheat")
>>> i7.save()
>>> r1 = Recipe(name="omelet")
>>> r1.save()
>>> r1.ingredients.add(i1, i2, i3)
>>> r2 = Recipe(name="icecream")
>>> r2.save()
>>> r2.ingredients.add(i3, i4, i5)
>>> test = Recipe.objects.filter(ingredients__in=[i1.id, i2.id, i3.id, i4.id])
>>> test
[<Recipe: omelet>, <Recipe: omelet>, <Recipe: omelet>, <Recipe: icecream>, <Recipe: icecream>]
I want to find only omelet. Because only omelet contains egg (i1), flour (i2), water (i3)
Thanks
maybe chain it together?
Recipe.objects.filter(ingredients=i1.id).filter(ingredients=i2.id).filter(ingredients=i3.id).filter(ingredients=i4.id)

Python Variable doesn't rebound in for loop

employees = []
for i in range(0,10):
emp = Employee(i)
emp.first_name = "%s-%s"%("first name", i)
emp.last_name = "%s-%s"%("last_name", i)
emp.desgination = "%s-%s"%("engineer", i)
employees.append(emp)
ids = [e.eid for e in employees]
Following is my class definition:
class Employee:
_fields = {}
def __init__(self, eid):
self.eid = eid
def __getattr__(self, name):
return self._fields.get(name)
def __setattr__(self,name,value):
self._fields[name] = value
def __str__(self):
return str(self._fields)
def __unicode__(self):
return str(self._fields)
The issue is that when I print ids, it contains 10 times 9... i.e.
[9, 9, 9, 9, 9, 9, 9, 9, 9, 9]
It seems that the same emp variable is being overwritten. I am not sure what going wrong. Though I am a Java coder but I thought I had a fair idea of Python as well.
The problem is, indeed, your java past ! :)
The error is here:
_fields = {}
_fields is a CLASS member ! So each instance of Employee shares the same _fields var, and whenever you modify one, you modify all other objects.
You must move the _fields = {} part into the __init__ function :
self._fields={}
But then, you will run into another problem: self.eid = xx invokes the __setattr__ method! (and so does self._fields !)
The solution is to use self.__dict__['_fields'] when you need to access to the instance's '_fields' member instead of self._fields. It will directly access the member, instead of going through __getattr__ and an infinite reccursion, with a nice stack overflow in the end.
its a side effect of the functions:
def __getattr__(self, name):
return self._fields.get(name)
def __setattr__(self,name,value):
self._fields[name] = value
remove them and it works. so this is the direction to look.